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 allocator #544

Merged
merged 10 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) };
}
}