Skip to content

Commit

Permalink
Add basic userspace allocator (#544)
Browse files Browse the repository at this point in the history
* Add userspace allocator

* Fix demo

* Return from userspace exceptions

* Add failing test

* Add allocator to process struct

* Update binaries

* Update binaries again

* Fix stack address

* Fix heap size

* Move up debug output in free syscall
  • Loading branch information
vinc authored Nov 20, 2023
1 parent 02c1b7f commit b4b3b0f
Show file tree
Hide file tree
Showing 17 changed files with 115 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ default-run = "moros"
default = ["video"]
video = []
serial = []
userspace = []

[dependencies]
acpi = "5.0.0"
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/*
Expand Down
Binary file modified dsk/bin/clear
Binary file not shown.
Binary file modified dsk/bin/halt
Binary file not shown.
Binary file modified dsk/bin/hello
100755 → 100644
Binary file not shown.
Binary file modified dsk/bin/print
Binary file not shown.
Binary file modified dsk/bin/reboot
Binary file not shown.
Binary file modified dsk/bin/sleep
Binary file not shown.
18 changes: 18 additions & 0 deletions src/api/allocator.rs
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 2 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}

Expand Down Expand Up @@ -65,6 +66,7 @@ macro_rules! error {
});
}

pub mod allocator;
pub mod clock;
pub mod console;
pub mod font;
Expand Down
12 changes: 12 additions & 0 deletions src/api/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ pub fn accept(handle: usize) -> Result<IpAddress, ()> {
}
}

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};
Expand Down
19 changes: 15 additions & 4 deletions src/bin/hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@

extern crate alloc;

use alloc::format;
use alloc::string::ToString;
use moros::api::syscall;
use moros::entry_point;

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");
}
Expand Down
6 changes: 3 additions & 3 deletions src/sys/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u64>().unwrap() << 20 // MB
}
Expand Down
38 changes: 30 additions & 8 deletions src/sys/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 *
************************/
Expand Down Expand Up @@ -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,
Expand All @@ -259,6 +271,7 @@ pub struct Process {
stack_frame: InterruptStackFrameValue,
registers: Registers,
data: ProcessData,
allocator: Arc<LockedHeap>,
}

impl Process {
Expand All @@ -279,6 +292,7 @@ impl Process {
page_table_frame: Cr3::read().0,
registers: Registers::default(),
data: ProcessData::new("/", None),
allocator: Arc::new(LockedHeap::empty()),
}
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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 {
Expand Down
12 changes: 12 additions & 0 deletions src/sys/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!();
}
Expand Down
2 changes: 2 additions & 0 deletions src/sys/syscall/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
19 changes: 19 additions & 0 deletions src/sys/syscall/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,22 @@ pub fn accept(handle: usize) -> Result<IpAddress, ()> {
}
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) };
}
}

0 comments on commit b4b3b0f

Please sign in to comment.