diff --git a/Cargo.toml b/Cargo.toml index c071bd08..d1140c26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ default-run = "moros" default = ["video"] video = [] serial = [] +userspace = [] [dependencies] acpi = "5.0.0" diff --git a/Makefile b/Makefile index f397edfb..b6cea2ae 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ user-rust: basename -s .rs src/bin/*.rs | xargs -I {} \ touch dsk/bin/{} basename -s .rs src/bin/*.rs | xargs -I {} \ - cargo rustc --release --bin {} + cargo rustc --no-default-features --features userspace --release --bin {} basename -s .rs src/bin/*.rs | xargs -I {} \ cp target/x86_64-moros/release/{} dsk/bin/{} strip dsk/bin/* diff --git a/dsk/bin/clear b/dsk/bin/clear index 360ea6b1..089513c3 100644 Binary files a/dsk/bin/clear and b/dsk/bin/clear differ diff --git a/dsk/bin/halt b/dsk/bin/halt index 65e7e325..3cbce7ea 100644 Binary files a/dsk/bin/halt and b/dsk/bin/halt differ diff --git a/dsk/bin/hello b/dsk/bin/hello old mode 100755 new mode 100644 index 8ff6a1c7..afc01f9d Binary files a/dsk/bin/hello and b/dsk/bin/hello differ diff --git a/dsk/bin/print b/dsk/bin/print index 43165144..53d333bf 100644 Binary files a/dsk/bin/print and b/dsk/bin/print differ diff --git a/dsk/bin/reboot b/dsk/bin/reboot index 6c364872..d6e9d9a0 100644 Binary files a/dsk/bin/reboot and b/dsk/bin/reboot differ diff --git a/dsk/bin/sleep b/dsk/bin/sleep index c9cc905f..37bcd49c 100644 Binary files a/dsk/bin/sleep and b/dsk/bin/sleep differ diff --git a/src/api/allocator.rs b/src/api/allocator.rs new file mode 100644 index 00000000..17df2a04 --- /dev/null +++ b/src/api/allocator.rs @@ -0,0 +1,18 @@ +use crate::api::syscall; + +use core::alloc::{GlobalAlloc, Layout}; + +pub struct UserspaceAllocator; + +unsafe impl GlobalAlloc for UserspaceAllocator{ + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + syscall::alloc(layout.size(), layout.align()) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + syscall::free(ptr, layout.size(), layout.align()); + } +} + +#[cfg_attr(feature = "userspace", global_allocator)] +static ALLOCATOR: UserspaceAllocator = UserspaceAllocator; diff --git a/src/api/mod.rs b/src/api/mod.rs index 848a9874..3047c8de 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -5,6 +5,7 @@ macro_rules! entry_point { #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { $crate::api::syscall::write(1, b"An exception occured!\n"); + $crate::api::syscall::exit($crate::api::process::ExitCode::ExecError); loop {} } @@ -65,6 +66,7 @@ macro_rules! error { }); } +pub mod allocator; pub mod clock; pub mod console; pub mod font; diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 20d98fd6..c37c30cf 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -155,6 +155,18 @@ pub fn accept(handle: usize) -> Result { } } +pub fn alloc(size: usize, align: usize) -> *mut u8 { + unsafe { + syscall!(ALLOC, size, align) as *mut u8 + } +} + +pub fn free(ptr: *mut u8, size: usize, align: usize) { + unsafe { + syscall!(FREE, ptr, size, align); + } +} + #[test_case] fn test_file() { use crate::sys::fs::{mount_mem, format_mem, dismount, OpenFlag}; diff --git a/src/bin/hello.rs b/src/bin/hello.rs index d6bea382..4c9951f7 100644 --- a/src/bin/hello.rs +++ b/src/bin/hello.rs @@ -3,7 +3,7 @@ extern crate alloc; -use alloc::format; +use alloc::string::ToString; use moros::api::syscall; use moros::entry_point; @@ -11,9 +11,20 @@ entry_point!(main); fn main(args: &[&str]) { if args.len() > 1 { - // FIXME: This will result in a page fault exception for an address - // that's already mapped to the kernel stack - syscall::write(1, format!("Hello, {}!\n", args[1]).as_bytes()); + syscall::write(1, args[1].as_bytes()); // FIXME: this is needed + syscall::write(1, "\n".as_bytes()); + + let mut hello = "Hello, ".to_string(); + hello.push_str(args[1]); // FIXME: for that to work + hello.push_str("!\n"); + syscall::write(1, hello.as_bytes()); + + if args.len() > 2 { + let mut hello = "Hello, ".to_string(); + hello.push_str(args[2]); // FIXME: not working + hello.push_str("!\n"); + syscall::write(1, hello.as_bytes()); + } } else { syscall::write(1, b"Hello, World!\n"); } diff --git a/src/sys/allocator.rs b/src/sys/allocator.rs index 3d4fcb77..7c006a61 100644 --- a/src/sys/allocator.rs +++ b/src/sys/allocator.rs @@ -13,11 +13,11 @@ use x86_64::structures::paging::mapper::MapToError; use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB}; use x86_64::VirtAddr; -pub const HEAP_START: u64 = 0x4444_4444_0000; - -#[global_allocator] +#[cfg_attr(not(feature = "userspace"), global_allocator)] static ALLOCATOR: LockedHeap = LockedHeap::empty(); +pub const HEAP_START: u64 = 0x4444_4444_0000; + fn max_memory() -> u64 { option_env!("MOROS_MEMORY").unwrap_or("32").parse::().unwrap() << 20 // MB } diff --git a/src/sys/process.rs b/src/sys/process.rs index 623aeb02..433015f3 100644 --- a/src/sys/process.rs +++ b/src/sys/process.rs @@ -5,18 +5,18 @@ use crate::sys::console::Console; use alloc::boxed::Box; use alloc::collections::btree_map::BTreeMap; use alloc::string::{String, ToString}; +use alloc::sync::Arc; use alloc::vec::Vec; +use core::alloc::{GlobalAlloc, Layout}; use core::arch::asm; use core::sync::atomic::{AtomicUsize, Ordering}; use lazy_static::lazy_static; +use linked_list_allocator::LockedHeap; use object::{Object, ObjectSegment}; use spin::RwLock; -use x86_64::structures::idt::InterruptStackFrameValue; use x86_64::registers::control::Cr3; -use x86_64::structures::paging::FrameAllocator; -use x86_64::structures::paging::OffsetPageTable; -use x86_64::structures::paging::PhysFrame; -use x86_64::structures::paging::PageTable; +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 @@ -213,6 +213,18 @@ pub unsafe fn page_table() -> &'static mut PageTable { sys::mem::create_page_table(page_table_frame()) } +pub unsafe fn alloc(layout: Layout) -> *mut u8 { + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.allocator.alloc(layout) +} + +pub unsafe fn free(ptr: *mut u8, layout: Layout) { + let table = PROCESS_TABLE.read(); + let proc = &table[id()]; + proc.allocator.dealloc(ptr, layout) +} + /************************ * Userspace experiment * ************************/ @@ -249,7 +261,7 @@ pub struct Registers { // Saved scratch registers const ELF_MAGIC: [u8; 4] = [0x7F, b'E', b'L', b'F']; const BIN_MAGIC: [u8; 4] = [0x7F, b'B', b'I', b'N']; -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Process { id: usize, code_addr: u64, @@ -259,6 +271,7 @@ pub struct Process { stack_frame: InterruptStackFrameValue, registers: Registers, data: ProcessData, + allocator: Arc, } impl Process { @@ -279,6 +292,7 @@ impl Process { page_table_frame: Cr3::read().0, registers: Registers::default(), data: ProcessData::new("/", None), + allocator: Arc::new(LockedHeap::empty()), } } @@ -310,7 +324,7 @@ impl Process { let proc_size = MAX_PROC_SIZE as u64; let code_addr = CODE_ADDR.fetch_add(proc_size, Ordering::SeqCst); - let stack_addr = code_addr + proc_size; + let stack_addr = code_addr + proc_size - 4096; //debug!("code_addr: {:#x}", code_addr); //debug!("stack_addr: {:#x}", stack_addr); @@ -350,9 +364,11 @@ impl Process { let registers = parent.registers; let stack_frame = parent.stack_frame; + let allocator = Arc::new(LockedHeap::empty()); + let id = MAX_PID.fetch_add(1, Ordering::SeqCst); let proc = Process { - id, code_addr, stack_addr, entry_point_addr, page_table_frame, data, stack_frame, registers + id, code_addr, stack_addr, entry_point_addr, page_table_frame, data, stack_frame, registers, allocator }; let mut process_table = PROCESS_TABLE.write(); @@ -368,6 +384,7 @@ impl Process { let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) }; let heap_addr = self.code_addr + (self.stack_addr - self.code_addr) / 2; + //debug!("user-args: {:#016x}", heap_addr); sys::allocator::alloc_pages(&mut mapper, heap_addr, 1).expect("proc heap alloc"); let args_ptr = ptr_from_addr(args_ptr as u64) as usize; @@ -393,6 +410,11 @@ impl Process { }; let args_ptr = args.as_ptr() as u64; + let heap_addr = addr; + let heap_size = (self.stack_addr - heap_addr) / 2; + //debug!("user-heap: {:#016x}..{:#016x}", heap_addr, heap_addr + heap_size); + unsafe { self.allocator.lock().init(heap_addr as *mut u8, heap_size as usize) }; + set_id(self.id); // Change PID unsafe { diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index 2d4f505e..94f007f8 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -110,6 +110,18 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -1 as isize as usize } } + number::ALLOC => { + let size = arg1; + let align = arg2; + service::alloc(size, align) as usize + } + number::FREE => { + let ptr = arg1 as *mut u8; + let size = arg2; + let align = arg3; + service::free(ptr, size, align); + 0 + } _ => { unimplemented!(); } diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index 96f34d0b..61bd7152 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -13,3 +13,5 @@ pub const POLL: usize = 0xC; pub const CONNECT: usize = 0xD; pub const LISTEN: usize = 0xE; pub const ACCEPT: usize = 0xF; +pub const ALLOC: usize = 0x10; +pub const FREE: usize = 0x11; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index b61ca739..a2ed27ba 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -181,3 +181,22 @@ pub fn accept(handle: usize) -> Result { } Err(()) } + +use core::alloc::Layout; + +pub fn alloc(size: usize, align: usize) -> *mut u8 { + if let Ok(layout) = Layout::from_size_align(size, align) { + let ptr = unsafe { sys::process::alloc(layout) }; + debug!("syscall::alloc(size={}, align={}) -> ptr={:?}", size, align, ptr); + ptr + } else { + core::ptr::null_mut() + } +} + +pub fn free(ptr: *mut u8, size: usize, align: usize) { + if let Ok(layout) = Layout::from_size_align(size, align) { + debug!("syscall::free(ptr={:?}, size={}, align={})", ptr, size, align); + unsafe { sys::process::free(ptr, layout) }; + } +}