Sync computers

This commit is contained in:
2026-02-28 18:55:10 +01:00
parent c3eb93e701
commit 9a983c56f3
29 changed files with 1564 additions and 28 deletions

View File

@@ -2,12 +2,17 @@
//!
//! Implements a minimal disk backend and exposes a global FILE_SYSTEM used by
//! the kernel to load user binaries.
use core::{cell::UnsafeCell, ops::Deref};
use core::{
cell::{LazyCell, UnsafeCell},
ops::Deref,
};
use bffs::{
io::{IoBase, Read, Seek},
path::Path,
Fat32FileSystem,
};
use hashbrown::HashMap;
const DISK_ADDR: *const u8 = 0x9000_0000 as *const _;
@@ -79,10 +84,20 @@ impl Read for Disk {
return Ok(0);
}
let size = usize::min(buf.len(), (self.size - self.pos) as usize);
(0..size).for_each(|i| {
buf[i] = unsafe { *DISK_ADDR.byte_add(i + self.pos as usize) };
});
unsafe {
core::ptr::copy_nonoverlapping(
DISK_ADDR.byte_add(self.pos as usize),
buf.as_mut_ptr(),
size,
);
}
self.pos += size as u64;
Ok(size)
}
}
pub struct KernelFDTable(LazyCell<HashMap<u64, Path<'static>>>);
unsafe impl Sync for KernelFDTable {}
pub static KERNEL_FILE_DESCRIPTOR_TABLE: KernelFDTable = KernelFDTable(LazyCell::new(HashMap::new));

View File

@@ -14,7 +14,7 @@ use crate::{
read_csr,
riscv::disable_interrupt,
scheduler::scheduler_without_ret,
set_csr,
set_csr, syscall,
time::{setup_next_timer_interrupt, IRQ_M_TIMER},
write_csr,
};
@@ -57,7 +57,6 @@ unsafe extern "C" fn machine_trap_handler(
c if c == EextensionID::Time as usize => match fid {
c if c == TimerFunctionID::SetTimer as usize => {
clear_csr!(mip, 1 << 5);
// setup_next_timer_interrupt();
}
_ => {}
},
@@ -122,16 +121,21 @@ unsafe extern "C" fn supervisor_trap_handler(
let a3: u64 = unsafe { (*interrupt_state).a[3] };
let syscall: SysCall = syscall_u64.into();
match syscall {
SysCall::Open => {
let path = unsafe { str::from_raw_parts(a1 as *const u8, a2 as usize) };
let fd = syscall::open(path, false);
unsafe { (*interrupt_state).a[0] = fd.unwrap() };
}
SysCall::Alloc => {
let layout = Layout::from_size_align(a1 as usize, a2 as usize).unwrap();
// Allocate memory and put the pointer in a0
unsafe { (*interrupt_state).a[0] = alloc::alloc::alloc(layout) as u64 };
unsafe { (*interrupt_state).a[0] = syscall::alloc(layout) as u64 };
}
SysCall::Dealloc => {
let ptr = a1 as *mut u8;
let layout = Layout::from_size_align(a2 as usize, a3 as usize).unwrap();
// Free memory
unsafe { alloc::alloc::dealloc(ptr, layout) };
unsafe { syscall::dealloc(ptr, layout) };
}
SysCall::Exit => exit_process(&mut interrupt_state),
SysCall::NanoSleep => sleep(Duration::new(a1, a2 as u32), &mut interrupt_state),

View File

@@ -15,6 +15,7 @@
ptr_metadata
)]
use alloc::boxed::Box;
use embedded_alloc::LlffHeap as Heap;
use log::info;
@@ -38,6 +39,7 @@ mod panic_handler;
mod process;
mod riscv;
mod scheduler;
mod syscall;
mod time;
mod uart;
mod user;
@@ -63,8 +65,8 @@ pub extern "C" fn supervisor_mode_entry() {
info!("Hello World !");
unsafe { Vga::draw_string(10, 10, "Hello World !", Color::WHITE, Color::BLACK) };
create_process(&test, "proc1");
create_process(&proc2, "proc2");
create_process(Box::new(test), "proc1");
create_process(Box::new(proc2), "proc2");
create_process_from_file("/usr/bin/test_pic");

View File

@@ -12,6 +12,7 @@ use core::time::Duration;
use alloc::{boxed::Box, format, string::String, vec::Vec};
use bffs::{io::Read, path::Path};
use goblin::elf::reloc::R_RISCV_RELATIVE;
use hashbrown::HashMap;
use shared::syscall::exit;
use crate::{
@@ -82,13 +83,15 @@ pub struct Process {
/// Current state of the process.
pub state: ProcessState,
/// Optional entry point for the process code.
pub entry: Option<&'static dyn Fn()>,
pub entry: Option<Box<dyn Fn()>>,
/// Wake time for sleeping processes.
pub wake_time: Duration,
/// Saved execution context.
pub ctx: ExecutionContext,
/// Process stack.
pub stack: [u64; STACK_SIZE],
/// File descriptor table.
pub fd_table: HashMap<u64, Path<'static>>
}
impl core::fmt::Debug for Process {
@@ -130,13 +133,19 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
// Open and read the binary file
let mut bin = FILE_SYSTEM.open_file(path).unwrap();
println!("Creating process");
let mut content: Vec<u8> = Vec::new();
bin.read_to_end(&mut content).unwrap();
println!("Loading binary at address: {:x?}", content.as_ptr());
println!(
"Loading binary at address: {:x?}, length: {}",
content.as_ptr(),
content.len()
);
// If ELF, use goblin to load PT_LOAD segments and apply relocations
if let Ok(gelf) = goblin::elf::Elf::parse(&content) {
println!("Parsed");
// Determine memory bounds from program headers
let mut min_vaddr = u64::MAX;
let mut max_vaddr = 0u64;
@@ -179,6 +188,7 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
}
}
}
println!("Copied");
// Apply relocations using our parser (handles RELA entries)
for rela in gelf.dynrelas.iter() {
@@ -193,15 +203,16 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
_ => {}
}
}
println!("Relocated");
// Entry point
let entry_va = gelf.entry;
let entry_addr = unsafe { base.add((entry_va - min_vaddr) as usize) } as *const u8;
let entry_fn =
unsafe { core::mem::transmute::<*const u8, extern "C" fn()>(entry_addr) };
let wrapper = Box::leak(Box::new(move || {
let wrapper = Box::new(move || {
entry_fn();
}));
});
println!("Program loaded at : {:x?}", entry_addr);
return create_process(wrapper, name);
}
@@ -210,9 +221,9 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
// Fallback: treat the file as a raw binary blob and execute in-place
let entry_point =
unsafe { core::mem::transmute::<*const u8, extern "C" fn()>(Vec::leak(content).as_ptr()) };
let wrapper = Box::leak(Box::new(move || {
let wrapper = Box::new(move || {
entry_point();
}));
});
create_process(wrapper, name)
}
@@ -236,7 +247,7 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
///
/// The provided `code` function will be executed when the process is first
/// scheduled. Returns the new PID, or -1 if the process table is full.
pub fn create_process<T: Into<String>, F: Fn()>(code: &'static F, name: T) -> i64 {
pub fn create_process<T: Into<String>, F: Fn() + 'static>(code: Box<F>, name: T) -> i64 {
// Search for a free slot in the process table
let mut next_pid = 0;
while next_pid < PROCESS_COUNT && unsafe { PROCESS_TABLE[next_pid].state != ProcessState::Dead }
@@ -262,7 +273,7 @@ pub fn create_process<T: Into<String>, F: Fn()>(code: &'static F, name: T) -> i6
// Configure execution context
// a0 contains the pointer to the function to execute
process.ctx.a[0] = process.entry.as_ref().unwrap_unchecked() as *const &dyn Fn() as u64;
process.ctx.a[0] = &raw const *process.entry.as_ref().unwrap_unchecked() as u64;
// mepc points to process_launcher which will call the function
process.ctx.mepc = process_launcher as *const _;
@@ -295,7 +306,7 @@ pub fn create_process<T: Into<String>, F: Fn()>(code: &'static F, name: T) -> i6
/// This function is installed into the process `mepc` so that when the new
/// process is scheduled it will run this launcher which calls the user
/// function and ensures the process exits cleanly.
extern "C" fn process_launcher(code: *const &dyn Fn()) {
extern "C" fn process_launcher(code: *const Box<dyn Fn()>) {
// SAFETY: The code pointer was initialized in create_process
// and points to a valid function.
unsafe { (*code)() };

View File

@@ -105,7 +105,7 @@ macro_rules! mret {
}
#[unsafe(naked)]
pub extern "C" fn exit_qemu() {
pub extern "C" fn exit_qemu() -> ! {
naked_asm!(
"
li a0, 0x100000

View File

@@ -5,7 +5,8 @@
//! and a simple round-robin scheduler used by the kernel.
use core::{arch::riscv64::wfi, array, cell::LazyCell, time::Duration};
use alloc::string::String;
use alloc::{boxed::Box, string::String};
use hashbrown::HashMap;
use log::info;
use crate::{
@@ -43,6 +44,7 @@ pub static mut PROCESS_TABLE: LazyCell<[Process; PROCESS_COUNT]> = LazyCell::new
},
stack: [0; _],
entry: None,
fd_table: HashMap::new()
})
});
@@ -71,7 +73,7 @@ pub fn scheduler_init() {
}
}
create_process(&idle, "idle");
create_process(Box::new(idle), "idle");
unsafe {
PROCESS_TABLE[0].state = ProcessState::Active;
}

27
src/syscall.rs Normal file
View File

@@ -0,0 +1,27 @@
use core::alloc::Layout;
use bffs::{error::Error, path::Path};
use crate::fs::{Disk, FILE_SYSTEM};
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
unsafe { alloc::alloc::alloc(layout) }
}
pub unsafe fn dealloc(ptr: *mut u8, layout: core::alloc::Layout) {
unsafe { alloc::alloc::dealloc(ptr, layout) }
}
pub fn open<'a, P: Into<Path<'a>>>(
path: P,
in_kernel: bool,
) -> Result<u64, Error<<Disk as bffs::io::IoBase>::Error>> {
let path = path.into();
let file = match path.split_path() {
("dev", path) => {
unimplemented!()
}
_ => FILE_SYSTEM.open_file(path)?,
};
Ok(42)
}