Sync computers
This commit is contained in:
23
src/fs.rs
23
src/fs.rs
@@ -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));
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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)() };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
27
src/syscall.rs
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user