21 Commits

Author SHA1 Message Date
3f51413038 Add sum to producteur_consommateur 2023-05-09 23:24:43 +02:00
e3654de298 Fixed nobody to run 2023-05-09 23:17:51 +02:00
98fe63f487 print exit code when using debug machine, add matmult 2023-05-09 23:16:16 +02:00
15a04fb9da Fixed tests failing because of a too small memory 2023-05-09 20:52:00 +02:00
86113da9d3 Fixed missing UserStackSize from default configuration 2023-05-09 19:32:33 +02:00
7be0c0accc Add user_stack_size to Machine and use it for threads sp 2023-05-09 17:01:52 +02:00
7d29b92eba temporary workaround for producteur_consommateur 2023-05-07 16:56:38 +02:00
2884d5d479 Fix shutdown test exception 2023-05-07 16:09:45 +02:00
c862c42e43 Fix instructions tests 2023-05-07 16:02:48 +02:00
5000c28b97 Fix endianness issues particulary with strings 2023-05-07 15:51:38 +02:00
5f8965b94d Merge branch 'thread_join' into 'main'
Merge ~~thread_scheduler~~ thread_join to main

See merge request simpleos/burritos!17
2023-05-04 22:41:25 +00:00
e0eb027aea Merge branch 'thread_scheduler' into 'thread_join'
Merge Thread scheduler to thread_join

See merge request simpleos/burritos!16
2023-05-04 22:21:22 +00:00
6eeaa57647 Merge branch 'fix-double-free' into 'thread_scheduler'
Fix double free

See merge request simpleos/burritos!15
2023-05-04 22:14:47 +00:00
bec0143a40 Added missing current_thread assignment in test_lock_multiple 2023-05-04 23:44:10 +02:00
28cd0a9f6e Try to fix double free 2023-05-04 22:58:13 +02:00
43f023e0b0 Fix join not working on join.c 2023-05-04 22:19:00 +02:00
02cdb5239b Update userlib/sys.s 2023-05-02 19:57:43 +00:00
a211e93905 try to implement join 2023-04-23 15:42:33 +02:00
1055e6a0ac Fixed lock_release behaviour when multiple users of given lock 2023-04-20 15:34:49 +02:00
c278236d81 Updated thread_manager module documentation 2023-04-20 15:21:28 +02:00
597ffa753a test lock for multiple threads
Signed-off-by: Rémi Rativel <remi.rativel@etudiant.univ-rennes1.fr>
2023-04-20 15:20:28 +02:00
19 changed files with 437 additions and 232 deletions

View File

@ -2,7 +2,7 @@
# BurritOS configuration file # BurritOS configuration file
################################################## ##################################################
NumPhysPages = 400 NumPhysPages = 40000000
UserStackSize = 4096 UserStackSize = 4096
MaxFileNameSize = 256 MaxFileNameSize = 256
NumDirEntries = 30 NumDirEntries = 30

View File

@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc};
use crate::{simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}}; use crate::{simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}};
use crate::kernel::synch::{Lock, Semaphore}; use crate::kernel::synch::{Lock, Semaphore};
use super::{system::{System, self}, thread::Thread}; use super::{system::System, thread::Thread};
/// The halt system call. Stops Burritos. /// The halt system call. Stops Burritos.
pub const SC_SHUTDOWN: u8 = 0; pub const SC_SHUTDOWN: u8 = 0;
@ -138,7 +138,8 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
Some(th) => th.clone(), Some(th) => th.clone(),
None => Err("Current thread is None")? None => Err("Current thread is None")?
}; };
system.get_thread_manager().thread_finish(machine, th); let code = machine.read_int_register(10);
system.get_thread_manager().thread_finish(machine, th, code);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
}, },
SC_EXEC => todo!(), SC_EXEC => todo!(),
@ -154,13 +155,17 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
let f = machine.read_int_register(12); let f = machine.read_int_register(12);
// load buffer // load buffer
let mut buffer = "".to_string(); let mut buffer = String::new();
let mut val: [u8; 4] = [0; 4];
for (j, elem) in val.iter_mut().enumerate() {
*elem = machine.read_memory(1, address as usize + j) as u8;
}
for i in 0..size { for i in 0..size {
buffer.push((machine.read_memory(1, (address + i) as usize)) as u8 as char); buffer.push((machine.read_memory(1, (address + i) as usize)) as u8 as char);
} }
if f as u8 == CONSOLE_OUTPUT { if f as u8 == CONSOLE_OUTPUT {
println!("{}", buffer); // todo replace with console driver in the future print!("{}", buffer); // todo replace with console driver in the future
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
} else { } else {
Err("SC_WRITE to file is not yet implemented")? Err("SC_WRITE to file is not yet implemented")?
@ -278,7 +283,9 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
}; };
let current_thread = current_thread.borrow_mut(); let current_thread = current_thread.borrow_mut();
if let Some(process) = current_thread.get_process_owner() { if let Some(process) = current_thread.get_process_owner() {
system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, current_thread.thread_context.int_registers[2] as u64, args); let sp_max = system.get_thread_manager().get_sp_max() + machine.user_stack_size;
system.get_thread_manager().set_sp_max(sp_max);
system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, sp_max, args);
// TODO changé la valeur de sp quand on supportera les addresses virtuels // TODO changé la valeur de sp quand on supportera les addresses virtuels
machine.write_int_register(10, tid as i64); machine.write_int_register(10, tid as i64);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
@ -316,10 +323,9 @@ fn get_length_param(addr: usize, machine: & Machine) -> usize {
let mut c = 1; let mut c = 1;
while c != 0 { while c != 0 {
c = machine.read_memory(1, addr + i); c = machine.read_memory(1, addr + i);
i +=1; i += 1;
} }
println!("addr: {:x}, i: {}", addr, i + 1);
i + 1 i + 1
} }
@ -334,7 +340,6 @@ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>
dest.push(c as char); dest.push(c as char);
i += 1; i += 1;
} }
dest.push('\0');
dest dest
} }
@ -351,9 +356,18 @@ mod test {
let mut machine = Machine::new(true, get_debug_configuration()); let mut machine = Machine::new(true, get_debug_configuration());
machine.write_int_register(17, SC_SHUTDOWN as i64); // Set type to shutdown machine.write_int_register(17, SC_SHUTDOWN as i64); // Set type to shutdown
// let ecall = Instruction::new(0b000000000000_00000_000_00000_1110011); // let ecall = Instruction::new(0b000000000000_00000_000_00000_1110011);
let insts: [u8; 4] = 0b000000000000_00000_000_00000_1110011_u32.to_le_bytes();
machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall machine.write_memory(1, 0, insts[0] as u64);
machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10 machine.write_memory(1, 1, insts[1] as u64);
machine.write_memory(1, 2, insts[2] as u64);
machine.write_memory(1, 3, insts[3] as u64); // ecall
// machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011_u64.to_be()); // ecall
let insts: [u8; 4] = 0b000000001010_00000_000_00001_0010011_u32.to_le_bytes();
machine.write_memory(1, 4, insts[0] as u64);
machine.write_memory(1, 5, insts[1] as u64);
machine.write_memory(1, 6, insts[2] as u64);
machine.write_memory(1, 7, insts[3] as u64); // r1 <- 10
// machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011_u64.to_be()); // r1 <- 10
let mut system = System::new(true); let mut system = System::new(true);
machine.run(&mut system); machine.run(&mut system);
// If the machine was stopped with no error, the shutdown worked // If the machine was stopped with no error, the shutdown worked

View File

@ -1,7 +1,7 @@
use std::{rc::Rc, cell::RefCell}; use std::{rc::Rc, cell::RefCell};
use super::process::Process; use super::{process::Process, thread_manager::ThreadRef};
use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::list::List};
const STACK_FENCEPOST: u32 = 0xdeadbeef; const STACK_FENCEPOST: u32 = 0xdeadbeef;
@ -26,7 +26,7 @@ pub struct Thread {
name: String, name: String,
pub process: Option<Rc<RefCell<Process>>>, pub process: Option<Rc<RefCell<Process>>>,
pub thread_context: ThreadContext, pub thread_context: ThreadContext,
pub stack_pointer: i32, pub join_thread: List<ThreadRef>,
} }
impl Thread { impl Thread {
@ -40,9 +40,9 @@ impl Thread {
thread_context: ThreadContext { thread_context: ThreadContext {
int_registers: [0; NUM_INT_REGS], int_registers: [0; NUM_INT_REGS],
float_registers: [0f32; NUM_FP_REGS], float_registers: [0f32; NUM_FP_REGS],
pc: 0 pc: 0,
}, },
stack_pointer: 0, join_thread: List::default(),
} }
} }
@ -94,7 +94,6 @@ mod test {
float_registers: [0f32; NUM_FP_REGS], float_registers: [0f32; NUM_FP_REGS],
pc: 0 pc: 0
}; };
x.stack_pointer = 0;
x } x }
}; };
} }

View File

@ -1,13 +1,15 @@
//! # Thread manager //! # Thread manager
//! //!
//! This module describes the data structure and the methods used for thread scheduling //! This module describes the data structure and the methods used for thread scheduling
//! in the BurritOS operating system. A struct named `ThreadManager` holds the list of //! in the BurritOS operating system. A struct named [`ThreadManager`] holds the list of
//! all existing threads and synchronization objects, such as `Locks`, `Semaphores` and //! all existing [`Thread`] instances and synchronization objects, such as
//! `Conditions`. //! [`Lock`](crate::kernel::synch::Lock),
//! [`Semaphore`](crate::kernel::synch::Semaphore) and
//! [`Condition`](crate::kernel::synch::Condition).
//! //!
//! ## Purpose //! ## Purpose
//! //!
//! `ThreadManager` holds the state of the system processes using the following subcomponents: //! [`ThreadManager`] holds the state of the system processes using the following subcomponents:
//! //!
//! ### Two lists of threads //! ### Two lists of threads
//! //!
@ -24,21 +26,23 @@
//! //!
//! Locks, Semaphores and Conditions allow resource sharing among running threads. Since resources //! Locks, Semaphores and Conditions allow resource sharing among running threads. Since resources
//! can only be accessed by a single thread at a time, we need data structures to signal other //! can only be accessed by a single thread at a time, we need data structures to signal other
//! threads that a resource may be busy or unavailable; say for example that thread **A** wants to //! threads that a resource may be busy or unavailable; say for example that:
//! write to a file while **B** is currently reading said file. Thread **A** mutating the state of //!
//! the file could cause issues for **B**. Therefore **B** needs to lock the file in question to //! - Thread **A** wants to write to a file while **B** is currently reading said file.
//! avoid such issues. Thread **A** will have to wait for **B** to finish reading the file. //! - Thread **A** mutating the state of the file could cause issues for **B**.
//! - Therefore **B** needs to lock the file in question to avoid such issues.
//! - Thread **A** will have to wait for **B** to finish reading the file.
//! //!
//! These synchronization objects are held in an instance of the ObjAddr structure held by //! These synchronization objects are held in an instance of the ObjAddr structure held by
//! ThreadManager. Their state is mutated depending on the actions of the currently running thread //! ThreadManager. Their state is mutated depending on the actions of the currently running thread
//! through methods such as `ThreadManager::sem_p`. //! through methods such as [`ThreadManager::sem_p`].
//! //!
//! ## Usage //! ## Usage
//! //!
//! `ThreadManager` is thought as a subcomponent of the `System` struct. Instanciating //! [`ThreadManager`] is thought as a subcomponent of the [`System`](crate::kernel::system::System) struct.
//! `System` will automatically instanciate a `ThreadManager` //! Instanciating [`System`](crate::kernel::system::System) will automatically instanciate a [`ThreadManager`]
//! //!
//! Manually loading a Thread into ThreadManager to execute a program with BurritOS could look like //! Manually loading a [`Thread`] into [`ThreadManager`] to execute a program with BurritOS could look like
//! this: //! this:
//! //!
//! ``` //! ```
@ -62,8 +66,8 @@
//! //!
//! ## Imports //! ## Imports
//! //!
//! The `List` and `ObjAddr` submodules used in this module are defined in the utility //! The [`List`] and [`ObjAddr`] submodules used in this module are defined in the utility
//! module. The source code of ObjAddr has been decoupled from thread_manager in an effort //! module. The source code of [`ObjAddr`] has been decoupled from thread_manager in an effort
//! to keep this module concise. //! to keep this module concise.
use std::{ use std::{
@ -98,7 +102,7 @@ use crate::{
}; };
/// Using this type alias to simplify struct and method definitions /// Using this type alias to simplify struct and method definitions
type ThreadRef = Rc<RefCell<Thread>>; pub type ThreadRef = Rc<RefCell<Thread>>;
/// # Thread manager /// # Thread manager
/// ///
@ -114,7 +118,8 @@ pub struct ThreadManager {
/// List of objects created by the thread manager (such as Locks and Semaphores) /// List of objects created by the thread manager (such as Locks and Semaphores)
obj_addrs: ObjAddr, obj_addrs: ObjAddr,
/// If true, enables debug mode /// If true, enables debug mode
debug: bool debug: bool,
sp_max: u64,
} }
impl ThreadManager { impl ThreadManager {
@ -126,7 +131,8 @@ impl ThreadManager {
g_alive: List::default(), g_alive: List::default(),
ready_list: List::default(), ready_list: List::default(),
obj_addrs: ObjAddr::init(), obj_addrs: ObjAddr::init(),
debug debug,
sp_max: 0
} }
} }
@ -182,6 +188,8 @@ impl ThreadManager {
/// Start a thread, attaching it to a process /// Start a thread, attaching it to a process
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) { pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
let mut thread_m = thread.borrow_mut(); let mut thread_m = thread.borrow_mut();
assert_eq!(thread_m.process, Option::None); assert_eq!(thread_m.process, Option::None);
thread_m.process = Option::Some(Rc::clone(&owner)); thread_m.process = Option::Some(Rc::clone(&owner));
@ -195,23 +203,29 @@ impl ThreadManager {
/// Wait for another thread to finish its execution /// Wait for another thread to finish its execution
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) { pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
let waiting_for = Rc::clone(&waiting_for); let waiting_for = Rc::clone(&waiting_for);
while self.get_g_alive().contains(&waiting_for) { if self.get_g_alive().contains(&waiting_for) {
self.debug(format!("Joining \"{}\" to \"{}\"", waiter.borrow().get_name(), waiting_for.borrow().get_name())); waiting_for.borrow_mut().join_thread.push(Rc::clone(&waiter));
self.thread_yield(machine, Rc::clone(&waiter)); self.thread_yield(machine, Rc::clone(&waiter), false);
} }
} }
/// Relinquish the CPU if any other thread is runnable. /// Relinquish the CPU if any other thread is runnable.
/// ///
/// Cannot use yield as a function name -> reserved name in rust /// Cannot use yield as a function name -> reserved name in rust
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef) { ///
/// ## Parameters
///
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff); let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
self.debug(format!("Yeilding thread: {}", thread.borrow().get_name())); self.debug(format!("Yeilding thread: \"{}\"", thread.borrow().get_name()));
debug_assert_eq!(&Option::Some(Rc::clone(&thread)), self.get_g_current_thread()); debug_assert_eq!(&Option::Some(Rc::clone(&thread)), self.get_g_current_thread());
let next_thread = self.find_next_to_run(); let next_thread = self.find_next_to_run();
if let Some(next_thread) = next_thread { if let Some(next_thread) = next_thread {
if is_ready {
self.ready_to_run(thread); self.ready_to_run(thread);
}
self.switch_to(machine, next_thread); self.switch_to(machine, next_thread);
} }
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
@ -222,22 +236,30 @@ impl ThreadManager {
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff); debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
self.debug(format!("Sleeping thread {}", thread.borrow().get_name()));
let mut next_thread = self.find_next_to_run(); let mut next_thread = self.find_next_to_run();
while next_thread.is_none() { while next_thread.is_none() {
eprintln!("Nobody to run => idle"); eprintln!("Nobody to run => idle");
machine.interrupt.idle(); machine.interrupt.idle();
next_thread = self.find_next_to_run(); if let Some(t) = self.find_next_to_run() {
next_thread = Some(t);
} else {
panic!("Couldn't find next thread to run.\nShutting down...");
}
} }
self.switch_to(machine, Rc::clone(&next_thread.unwrap())); self.switch_to(machine, Rc::clone(&next_thread.unwrap()));
} }
/// Finish the execution of the thread and prepare its deallocation /// Finish the execution of the thread and prepare its deallocation
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef) { pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef, exit_code: i64) {
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff); let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
assert!(self.g_alive.remove(Rc::clone(&thread))); assert!(self.g_alive.remove(Rc::clone(&thread)));
self.debug(format!("Sleeping thread {}", thread.borrow().get_name())); self.debug(format!("Finishing thread {} with code {}", thread.borrow().get_name(), exit_code));
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard // g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
for (_, el) in thread.borrow().join_thread.iter().enumerate() {
self.ready_to_run(Rc::clone(&el));
}
self.thread_sleep(machine, Rc::clone(&thread)); self.thread_sleep(machine, Rc::clone(&thread));
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
} }
@ -351,29 +373,31 @@ impl ThreadManager {
/// Wake up a waiter if necessary, or release it if no thread is waiting. /// Wake up a waiter if necessary, or release it if no thread is waiting.
pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> { pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
let current_thread = match self.get_g_current_thread() { let current_thread = match self.get_g_current_thread() {
Some(thread) => Rc::clone(thread), Some(thread) => Rc::clone(thread),
None => Err(String::from("lock_release error: current_thread should not be None."))? None => Err(String::from("lock_release error: current_thread should not be None."))?
}; };
let mut lock = match self.get_obj_addrs().search_lock(id).cloned() { let mut lock = match self.get_obj_addrs().search_lock(id) {
Some(lock) => lock, Some(lock) => lock,
None => Err(String::from("lock_release error: cannot find lock."))? None => Err(String::from("lock_release error: cannot find lock."))?
}; };
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
if let Some(lock_owner) = &lock.owner { if let Some(lock_owner) = &lock.owner {
if Rc::ptr_eq(&current_thread, lock_owner) { if current_thread.eq(lock_owner) { // is_held_by_current_thread
if let Some(thread) = lock.waiting_queue.pop() { match lock.waiting_queue.pop() {
let clone = Rc::clone(&thread); Some(th) => {
lock.owner = Some(thread); lock.owner = Some(Rc::clone(&th));
self.ready_to_run(clone); self.ready_to_run(Rc::clone(&th));
lock.free = true; },
} else { None => {
lock.free = true; lock.free = true;
lock.owner = None; lock.owner = None;
} }
} }
}
}; };
self.get_obj_addrs().update_lock(id, lock); // self.get_obj_addrs().update_lock(id, lock);
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
} }
@ -405,6 +429,14 @@ impl ThreadManager {
} }
} }
pub fn get_sp_max(&self) -> u64 {
self.sp_max
}
pub fn set_sp_max(&mut self, sp_max: u64) {
self.sp_max = sp_max;
}
} }
#[cfg(test)] #[cfg(test)]
@ -428,7 +460,7 @@ mod test {
let owner1 = Process { num_thread: 0 }; let owner1 = Process { num_thread: 0 };
let owner1 = Rc::new(RefCell::new(owner1)); let owner1 = Rc::new(RefCell::new(owner1));
system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr, -1); system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr + machine.page_size, -1);
debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc); debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc);
debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1)));
@ -443,7 +475,7 @@ mod test {
} }
#[test] #[test]
fn test_lock(){ fn test_lock_single(){
let mut machine = Machine::new(true, get_debug_configuration()); let mut machine = Machine::new(true, get_debug_configuration());
let mut thread_manager = ThreadManager::new(true); let mut thread_manager = ThreadManager::new(true);
let lock = Lock::new(); let lock = Lock::new();
@ -470,6 +502,54 @@ mod test {
} }
} }
#[test]
fn test_lock_multiple() {
let mut machine = Machine::new(true, get_debug_configuration());
let mut thread_manager = ThreadManager::new(true);
let lock = Lock::new();
let lock_id = thread_manager.get_obj_addrs().add_lock(lock);
let thread_1 = Rc::new(RefCell::new(Thread::new("test_lock_1")));
let thread_2 = Rc::new(RefCell::new(Thread::new("test_lock_2")));
thread_manager.ready_to_run(thread_1.clone());
thread_manager.ready_to_run(thread_2.clone());
thread_manager.set_g_current_thread(Some(thread_1.clone()));
thread_manager.lock_acquire(lock_id, &mut machine).expect("lock acquire return an error at first iteration: ");
{
let lock = thread_manager.get_obj_addrs().search_lock(lock_id).unwrap();
assert_eq!(lock.owner,Some(thread_1.clone()));
assert!(!lock.free);
assert!(lock.waiting_queue.is_empty());
}
thread_manager.set_g_current_thread(Some(thread_2.clone()));
thread_manager.lock_acquire(lock_id, &mut machine).expect("lock acquire return an error at second iteration: ");
{
let lock = thread_manager.get_obj_addrs().search_lock(lock_id).unwrap();
assert_eq!(lock.owner,Some(thread_1.clone()));
assert!(!lock.free);
assert_eq!(lock.waiting_queue.iter().count(),1);
}
thread_manager.lock_release(lock_id, &mut machine).expect("lock release return an error at first iteration: ");
{
let lock = thread_manager.get_obj_addrs().search_lock(lock_id).unwrap();
assert_eq!(lock.owner, Some(thread_2.clone()));
assert!(!lock.free);
assert!(lock.waiting_queue.is_empty());
}
thread_manager.set_g_current_thread(Some(thread_2.clone()));
thread_manager.lock_release(lock_id, &mut machine).expect("lock release return an error at second iteration: ");
{
let lock = thread_manager.get_obj_addrs().search_lock(lock_id).unwrap();
assert!(lock.waiting_queue.is_empty());
assert_eq!(lock.owner, None);
assert!(lock.free);
}
}
#[test] #[test]
fn test_semaphore_single() { fn test_semaphore_single() {
// Init // Init

View File

@ -20,7 +20,7 @@ use simulator::{machine::Machine, loader};
use clap::Parser; use clap::Parser;
use utility::cfg::{get_debug_configuration, read_settings}; use utility::cfg::read_settings;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(name = "BurritOS", author, version, about = "Burritos (BurritOS Using Rust Really Improves The Operating System) #[command(name = "BurritOS", author, version, about = "Burritos (BurritOS Using Rust Really Improves The Operating System)
@ -29,9 +29,13 @@ Burritos is an educational operating system written in Rust
running on RISC-V emulator.", long_about = None)] running on RISC-V emulator.", long_about = None)]
/// Launch argument parser /// Launch argument parser
struct Args { struct Args {
/// Enable debug mode /// Enable debug mode.
#[arg(short, long)] /// 0 to disable debug,
debug: bool, /// 1 to enable machine debug,
/// 2 to enable system debug,
/// 3 to enable all debug
#[arg(short, long, value_parser = clap::value_parser!(u8).range(0..=3), default_value_t = 0)]
debug: u8,
/// Path to the executable binary file to execute /// Path to the executable binary file to execute
#[arg(short = 'x', long, value_name = "PATH")] #[arg(short = 'x', long, value_name = "PATH")]
executable: String executable: String
@ -40,10 +44,10 @@ struct Args {
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
let mut machine = Machine::new(args.debug, read_settings().unwrap()); let mut machine = Machine::new(args.debug & 1 != 0, read_settings().unwrap());
let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("An error occured while parsing the program"); let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("An error occured while parsing the program");
let mut system = System::new(args.debug); let mut system = System::new(args.debug & 2 != 0);
let thread_exec = Thread::new(args.executable.as_str()); let thread_exec = Thread::new(args.executable.as_str());
let thread_exec = Rc::new(RefCell::new(thread_exec)); let thread_exec = Rc::new(RefCell::new(thread_exec));
@ -51,7 +55,10 @@ fn main() {
let owner1 = Process { num_thread: 0 }; let owner1 = Process { num_thread: 0 };
let owner1 = Rc::new(RefCell::new(owner1)); let owner1 = Rc::new(RefCell::new(owner1));
system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, ptr, -1); let sp_max = ptr + machine.user_stack_size;
system.get_thread_manager().set_sp_max(sp_max);
system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, sp_max, -1);
let to_run = system.get_thread_manager().find_next_to_run().unwrap(); let to_run = system.get_thread_manager().find_next_to_run().unwrap();
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run)); system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));

View File

@ -349,11 +349,11 @@ mod test {
#[test] #[test]
fn test_op() { fn test_op() {
let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011); let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011_u64.to_le());
let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011); let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011_u64.to_le());
let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011); let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011_u64.to_le());
let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011); let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011_u64.to_le());
let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011); let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011_u64.to_le());
assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0)); assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0));
assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0)); assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0));
@ -365,13 +365,13 @@ mod test {
#[test] #[test]
fn test_opi() { fn test_opi() {
let addi = Instruction::new(0b0000000000_10001_000_11100_0010011); let addi = Instruction::new(0b0000000000_10001_000_11100_0010011_u64.to_le());
let slli = Instruction::new(0b0000000000_10001_001_11100_0010011); let slli = Instruction::new(0b0000000000_10001_001_11100_0010011_u64.to_le());
let slti = Instruction::new(0b0000000000_10001_010_11100_0010011); let slti = Instruction::new(0b0000000000_10001_010_11100_0010011_u64.to_le());
let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011); let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011_u64.to_le());
let xori = Instruction::new(0b_0000000000010001_100_11100_0010011); let xori = Instruction::new(0b_0000000000010001_100_11100_0010011_u64.to_le());
let ori = Instruction::new(0b00000000000_10001_110_11100_0010011); let ori = Instruction::new(0b00000000000_10001_110_11100_0010011_u64.to_le());
let andi = Instruction::new(0b000000000000_10001_111_11100_0010011); let andi = Instruction::new(0b000000000000_10001_111_11100_0010011_u64.to_le());
assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0)); assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0));
assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0)); assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0));
assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0)); assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0));
@ -383,8 +383,8 @@ mod test {
#[test] #[test]
fn test_lui() { fn test_lui() {
let lui = Instruction::new(0b01110001000011111000_11100_0110111); let lui = Instruction::new(0b01110001000011111000_11100_0110111_u64.to_le());
let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111); let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111_u64.to_le());
assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0)); assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0));
assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0)); assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0));
} }
@ -392,13 +392,13 @@ mod test {
#[test] #[test]
fn test_ld() { fn test_ld() {
// imm rs1 f3 rd opcode // imm rs1 f3 rd opcode
let lb = Instruction::new(0b010111110000_10001_000_11100_0000011); let lb = Instruction::new(0b010111110000_10001_000_11100_0000011_u64.to_le());
let lh = Instruction::new(0b010111110000_10001_001_11100_0000011); let lh = Instruction::new(0b010111110000_10001_001_11100_0000011_u64.to_le());
let lw = Instruction::new(0b010111110000_10001_010_11100_0000011); let lw = Instruction::new(0b010111110000_10001_010_11100_0000011_u64.to_le());
let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011); let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011_u64.to_le());
let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011); let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011_u64.to_le());
let ld = Instruction::new(0b010111110000_10001_011_11100_0000011); let ld = Instruction::new(0b010111110000_10001_011_11100_0000011_u64.to_le());
let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011); let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011_u64.to_le());
assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0)); assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0));
assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0)); assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0));
@ -411,10 +411,10 @@ mod test {
#[test] #[test]
fn test_opw() { fn test_opw() {
let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011); let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011_u64.to_le());
let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011); let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011_u64.to_le());
let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011); let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011_u64.to_le());
let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011); let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011_u64.to_le());
assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0)); assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0));
assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0)); assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0));
@ -424,9 +424,9 @@ mod test {
#[test] #[test]
fn test_opwi() { fn test_opwi() {
let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011); let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011_u64.to_le());
let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011); let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011_u64.to_le());
let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011); let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011_u64.to_le());
assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0)); assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0));
assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0)); assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0));
assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0)); assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0));
@ -435,13 +435,13 @@ mod test {
#[test] #[test]
fn test_br() { fn test_br() {
let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011); let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011_u64.to_le());
let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011); let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011_u64.to_le());
let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011); let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011_u64.to_le());
let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011); let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011_u64.to_le());
let bge2: Instruction = Instruction::new(0x00f75863); let bge2: Instruction = Instruction::new(0x00f75863_u64.to_le());
let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011); let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011_u64.to_le());
let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011); let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011_u64.to_le());
assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0)); assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0));
assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0)); assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0));
assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4)); assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4));
@ -461,72 +461,72 @@ mod test {
a = a + b; a = a + b;
b = a - b; b = a - b;
*/ */
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0)); assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0));
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0)); assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0));
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0)); assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0));
assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623), 0)); assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623_u64.to_le()), 0));
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0)); assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0)); assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb), 0)); assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb_u64.to_le()), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb), 0)); assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb_u64.to_le()), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0)); assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0));
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0)); assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0));
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0)); assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0));
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0)); assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0));
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0)); assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0));
} }
#[test] #[test]
fn test_fibo() { fn test_fibo() {
assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f), 0x104b4)); assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f_u64.to_le()), 0x104b4));
assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3), 0x10518)); assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3_u64.to_le()), 0x10518));
} }
#[test] #[test]
fn test_mul_prog() { fn test_mul_prog() {
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0)); assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0));
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0)); assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0));
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0)); assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0));
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0)); assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793), 0)); assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793_u64.to_le()), 0));
assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b), 0)); assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b_u64.to_le()), 0));
assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb), 0)); assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb_u64.to_le()), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0)); assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0));
assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223), 0)); assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223_u64.to_le()), 0));
assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783), 0)); assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783_u64.to_le()), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb), 0)); assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb_u64.to_le()), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0)); assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0));
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0)); assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0));
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0)); assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0));
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0)); assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0));
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0)); assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0));
} }
} }

View File

@ -463,7 +463,12 @@ impl Loader {
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError(format!("index 0x{:x} is out of bound because list have a size of 0x{:x} (image offset 0x{:x}, j 0x{:x}, k 0x{:x})", section.image_offset as usize + j + k, self.bytes.len(), section.image_offset, j, k)))?; buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError(format!("index 0x{:x} is out of bound because list have a size of 0x{:x} (image offset 0x{:x}, j 0x{:x}, k 0x{:x})", section.image_offset as usize + j + k, self.bytes.len(), section.image_offset, j, k)))?;
} }
} }
machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j, buf[0] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 1, buf[1] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 2, buf[2] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 3, buf[3] as u64);
} }
} }
} }

View File

@ -95,7 +95,8 @@ pub struct Machine {
// futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize; // futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize;
//creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg //creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg
num_phy_page: u64, num_phy_page: u64,
page_size: u64, pub page_size: u64,
pub user_stack_size: u64,
/// Current machine status /// Current machine status
pub status: MachineStatus pub status: MachineStatus
} }
@ -115,7 +116,8 @@ impl Machine {
let num_phy_page = *settings.get(&MachineSettingKey::NumPhysPages).unwrap(); let num_phy_page = *settings.get(&MachineSettingKey::NumPhysPages).unwrap();
let page_size = *settings.get(&MachineSettingKey::PageSize).unwrap(); let page_size = *settings.get(&MachineSettingKey::PageSize).unwrap();
let mem_size = (page_size*num_phy_page*100_000) as usize; let user_stack_size = *settings.get(&MachineSettingKey::UserStackSize).unwrap();
let mem_size = (page_size*num_phy_page) as usize;
Machine { Machine {
debug, debug,
@ -129,7 +131,8 @@ impl Machine {
registers_trace : String::from(""), registers_trace : String::from(""),
status: MachineStatus::SystemMode, status: MachineStatus::SystemMode,
num_phy_page, num_phy_page,
page_size page_size,
user_stack_size
} }
} }
@ -284,7 +287,7 @@ impl Machine {
*elem = self.main_memory[self.pc as usize + i]; *elem = self.main_memory[self.pc as usize + i];
} }
let val = u32::from_be_bytes(val) as u64; let val = u32::from_le_bytes(val) as u64;
let inst : Instruction = Instruction::new(val); let inst : Instruction = Instruction::new(val);
if self.debug { if self.debug {
self.print_status(); self.print_status();
@ -425,10 +428,10 @@ impl Machine {
RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12), RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12),
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12), RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12), RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12), RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, shamt),
RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI { RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt) compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt)
} else { } else { // SRAI
compute(&core::ops::Shr::shr, rs1, shamt) compute(&core::ops::Shr::shr, rs1, shamt)
} }
_ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))?
@ -501,8 +504,8 @@ impl Machine {
let local_data = self.int_reg.get_reg(inst.rs1); let local_data = self.int_reg.get_reg(inst.rs1);
let result = match inst.funct3 { let result = match inst.funct3 {
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64, RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
RISCV_OPIW_SLLIW => local_data << inst.shamt, RISCV_OPIW_SLLIW => local_data << inst.rs2,
RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 }, RISCV_OPIW_SRW => (local_data >> inst.rs2) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.rs2 as usize] as i64 } else { 1 },
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
}; };
self.int_reg.set_reg(inst.rd, result); self.int_reg.set_reg(inst.rd, result);
@ -519,7 +522,7 @@ impl Machine {
// Match case for multiplication operations (in standard extension RV32M) // Match case for multiplication operations (in standard extension RV32M)
match inst.funct3 { match inst.funct3 {
RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b), RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, (local_data_a * local_data_b) & 0xffffffff),
RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b), RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b),
RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned), RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned),
RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b), RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b),
@ -538,9 +541,9 @@ impl Machine {
}, },
RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)), RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)),
RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW { RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW {
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64) self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab /* & 0x1f */) & self.shiftmask[32 + local_datab as usize] as i64)
} else { // SRAW } else { // SRAW
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f)) self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab /* & 0x1f */))
}, },
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
} }

View File

@ -14,7 +14,7 @@ use std::{fs, io::{BufRead, BufReader, Lines, Error}};
use crate::Machine; use crate::Machine;
/// File section /// File section
pub struct SectionFormat{ pub struct SectionFormat {
/// Memory address of the section /// Memory address of the section
addr: String, addr: String,
/// The size of data in bytes /// The size of data in bytes
@ -26,7 +26,7 @@ pub struct SectionFormat{
/// # Memory section /// # Memory section
/// ///
/// Representation of a section of memory from BurritOS or NachOS /// Representation of a section of memory from BurritOS or NachOS
pub struct Section{ pub struct Section {
/// Memory address of the section /// Memory address of the section
addr: usize, addr: usize,
/// The size of data in bytes /// The size of data in bytes
@ -36,15 +36,23 @@ pub struct Section{
} }
impl Section { impl Section {
/// Creates a memory section from a SectionFormat /// Creates a memory section from a SectionFormat
fn from(section: &SectionFormat) -> Section { fn from(section: &mut SectionFormat) -> Section {
let addr = usize::from_str_radix(&section.addr, 16).unwrap_or_default(); let addr = usize::from_str_radix(&section.addr, 16).unwrap_or_default();
let len = usize::from_str_radix(&section.len, 16).unwrap_or_default(); let len = usize::from_str_radix(&section.len, 16).unwrap_or_default();
let content: Vec<u8> = section.content.as_bytes().chunks(2).map(|x| { let content: Vec<u8>;
u8::from_str_radix(std::str::from_utf8(x).unwrap_or_default(), 16).unwrap_or_default() unsafe {
}).collect(); content = section.content.as_bytes_mut()
Section{addr, len, content} .chunks_mut(4).map(
|x| {
x.reverse();
u8::from_str_radix(
std::str::from_utf8(x).unwrap_or_default(), 16
).unwrap_or_default()
}
).collect();
}
Section { addr, len, content }
} }
/// Pretty prints a memory section /// Pretty prints a memory section
@ -68,7 +76,7 @@ pub struct MemChecker {
} }
impl MemChecker{ impl MemChecker {
///Translate lines of a file in e Vector of String ///Translate lines of a file in e Vector of String
///We need this method to parse the memory we received ///We need this method to parse the memory we received
@ -126,12 +134,12 @@ impl MemChecker{
} }
else { else {
//lecture ligne CONTENT //lecture ligne CONTENT
let section_f = SectionFormat{ let mut section_f = SectionFormat {
addr: tmp_addr_str.clone(), addr: tmp_addr_str.clone(),
len: tmp_len_str.clone(), len: tmp_len_str.clone(),
content: current_line.clone().replace(' ', ""), content: current_line.clone().replace(' ', ""),
}; };
sections.push(Section::from(&section_f)); sections.push(Section::from(&mut section_f));
} }
} }
@ -169,7 +177,7 @@ impl MemChecker{
machine.pc = m_c.pc as u64; machine.pc = m_c.pc as u64;
for section in m_c.sections.iter() { for section in m_c.sections.iter() {
for (i,b) in section.content.iter().enumerate() { for (i, b) in section.content.iter().enumerate() {
machine.main_memory[section.addr + i] = *b; machine.main_memory[section.addr + i] = *b;
} }
} }
@ -235,12 +243,12 @@ mod tests {
#[test] #[test]
fn test_create_section_content(){ fn test_create_section_content(){
let section_format = SectionFormat{ let mut section_format = SectionFormat{
addr: "0".to_string(), addr: "0".to_string(),
len: "0".to_string(), len: "0".to_string(),
content: "00FF0AA0A5".to_string(), content: "00FF0AA0A5".to_string(),
}; };
let section = Section::from(&section_format); let section = Section::from(&mut section_format);
let expected_vec: Vec<u8> = vec![0u8, 255u8, 10u8, 160u8, 165u8]; let expected_vec: Vec<u8> = vec![0u8, 255u8, 10u8, 160u8, 165u8];
assert_eq!(section.content, expected_vec); assert_eq!(section.content, expected_vec);
} }

View File

@ -214,7 +214,7 @@ pub mod global {
/// ///
/// Shift left logical immediate /// Shift left logical immediate
/// ///
/// `SLLI rd, rs1, shamt` => `rd <- rs1 >> shamt` /// `SLLI rd, rs1, shamt` => `rd <- rs1 << shamt`
pub const RISCV_OPI_SLLI: u8 = 0x1; pub const RISCV_OPI_SLLI: u8 = 0x1;
/// Shift right immediate, may be SRAI or SRLI /// Shift right immediate, may be SRAI or SRLI
pub const RISCV_OPI_SRI: u8 = 0x5; pub const RISCV_OPI_SRI: u8 = 0x5;

View File

@ -93,24 +93,29 @@ pub fn read_settings() -> Result<Settings, Error> {
} }
/// Returns a mock configuration for Machine unit testing /// Returns a mock configuration for Machine unit testing
///
/// FIXME: Does not cover the whole configuration yet /// FIXME: Does not cover the whole configuration yet
pub fn get_debug_configuration() -> Settings { pub fn get_debug_configuration() -> Settings {
let mut settings_map = Settings::new(); let mut settings_map = Settings::new();
settings_map.insert(MachineSettingKey::PageSize, 128); settings_map.insert(MachineSettingKey::PageSize, 2048);
settings_map.insert(MachineSettingKey::NumPhysPages, 400); settings_map.insert(MachineSettingKey::NumPhysPages, 8192);
settings_map.insert(MachineSettingKey::UserStackSize, 4096);
settings_map settings_map
} }
/// Removes comments and empty lines
fn filter_garbage<R: std::io::Read>(reader: BufReader<R>) -> Vec<String> { fn filter_garbage<R: std::io::Read>(reader: BufReader<R>) -> Vec<String> {
reader.lines() reader.lines()
.map(|l| l.unwrap()) .map(|l| l.unwrap())
.filter(|l| !l.is_empty() && !l.starts_with("#")) .filter(|l| !l.is_empty() && !l.starts_with('#'))
.collect() .collect()
} }
/// Inserts user settings into setting map
fn update_settings_map(mut settings_map: Settings, key: &str, setting: &str) -> Settings { fn update_settings_map(mut settings_map: Settings, key: &str, setting: &str) -> Settings {
let key = MachineSettingKey::from(key); let key = MachineSettingKey::from(key);
let setting = u64::from_str_radix(setting, 10).unwrap_or(0); let setting = setting.parse::<u64>().unwrap_or(0);
settings_map.insert(key, setting); settings_map.insert(key, setting);
settings_map settings_map
} }

View File

@ -9,11 +9,10 @@ use std::ptr;
/// These methods wrap unsafe instructions because it doesn't respect borrow rules per example /// These methods wrap unsafe instructions because it doesn't respect borrow rules per example
/// but everything has been tested with miri to assure there's no Undefined Behaviour (use-after-free, double free, etc.) /// but everything has been tested with miri to assure there's no Undefined Behaviour (use-after-free, double free, etc.)
/// or memory leak /// or memory leak
#[derive(PartialEq)] #[derive(PartialEq, Clone, Debug)]
#[derive(Clone)]
pub struct List<T: PartialEq> { pub struct List<T: PartialEq> {
head: Link<T>, head: Link<T>,
tail: *mut Node<T>, tail: Link<T>,
} }
type Link<T> = *mut Node<T>; type Link<T> = *mut Node<T>;

View File

@ -1,15 +1,13 @@
int main() { int main() {
int x = 0; int x = 0;
int y = 1; int y = 1;
while (x <= y) {
if (x > y) { if (x > y) {
x += 1; x += 1;
} else if (x == y) {
x += y;
} else if (x < y) {
y += 1;
} else {
return 0;
} }
if (x == y) {
x += y;
}
if (x < y) {
y += 1;
} }
} }

View File

@ -1,4 +1,4 @@
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac PROGRAMS = halt.guac prints.guac producteur_consommateur.guac join.guac matmult.guac
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/Makefile.rules include $(TOPDIR)/Makefile.rules

26
test/syscall_tests/join.c Normal file
View File

@ -0,0 +1,26 @@
#include "userlib/syscall.h"
#include "userlib/libnachos.h"
void thread1() {
for(int i = 0; i < 10; i++)
{
n_printf("Hello from th1\n");
}
}
void thread2() {
for(int i = 0; i < 10; i++)
{
n_printf("Hello from th2\n");
}
}
int main() {
ThreadId th1 = threadCreate("thread 1", thread1);
ThreadId th2 = threadCreate("thread 2", thread2);
Join(th1);
Join(th2);
Shutdown();
return 0;
}

View File

@ -0,0 +1,60 @@
/* matmult.c
* Test program to do matrix multiplication on large arrays.
*
* Intended to stress virtual memory system.
*
* Ideally, we could read the matrices off of the file system,
* and store the result back to the file system!
*
* -----------------------------------------------------
* This file is part of the Nachos-RiscV distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#include "userlib/syscall.h"
#define Dim 10 /* sum total of the arrays doesn't fit in
* physical memory
*/
/* The matrices to be filled-in and multiplied */
int A[Dim][Dim];
int B[Dim][Dim];
int C[Dim][Dim];
int
main()
{
int i, j, k;
Write("Start matmult\n",14,CONSOLE_OUTPUT);
for (i = 0; i < Dim; i++) /* first initialize the matrices */
for (j = 0; j < Dim; j++) {
A[i][j] = i;
B[i][j] = j;
C[i][j] = 0;
}
for (i = 0; i < Dim; i++) /* then multiply them together */
for (j = 0; j < Dim; j++)
for (k = 0; k < Dim; k++)
C[i][j] += A[i][k] * B[k][j];
Exit(C[Dim-1][Dim-1]); /* and then we're done */
return 0;
}

View File

@ -2,9 +2,10 @@
#include "userlib/libnachos.h" #include "userlib/libnachos.h"
int main() { int main() {
n_printf("Hello World 1"); n_printf("Hello World 1\n");
n_printf("Hello World 2"); n_printf("Hello World 2\n");
n_printf("Hello World 3"); n_printf("Hello World 3\n");
n_printf("Hello World 4"); n_printf("Hello World 4\n");
Shutdown();
return 0; return 0;
} }

View File

@ -9,9 +9,32 @@ int tab[3];
SemId svide; SemId svide;
SemId splein; SemId splein;
void producteur(); void producteur() {
for(int i = 0; i < 10; i++)
{
n_printf("batir une information\n");
P(svide);
iplein = (iplein + 1) % N;
// n_printf("communique une information : %d\n", i);
tab[iplein] = i;
V(splein);
}
}
void consommateur(); void consommateur() {
int sum = 0;
for(int i = 0; i < 10; i++)
{
P(splein);
ivide = (ivide +1) % N;
n_printf("recevoir une information\n");
int info = tab[ivide];
V(svide);
sum += info;
// n_printf("exploiter l'information : %d\n", info);
}
Exit(sum);
}
int main() { int main() {
svide = SemCreate("producteur", N); svide = SemCreate("producteur", N);
@ -20,29 +43,6 @@ int main() {
ThreadId consommateurTh = threadCreate("consommateur", consommateur); ThreadId consommateurTh = threadCreate("consommateur", consommateur);
Join(producteurTh); Join(producteurTh);
Join(consommateurTh); Join(consommateurTh);
Shutdown();
return 0; return 0;
} }
void producteur() {
for(int i = 0; i < 10; i++)
{
n_printf("batir une information\n");
P(svide);
iplein = (iplein + 1) % N;
n_printf("communique une information : %d\n", i);
tab[iplein] = i;
V(splein);
}
}
void consommateur() {
for(int i = 0; i < 10; i++)
{
P(splein);
ivide = (ivide +1) % N;
n_printf("recevoir une information\n");
int info = tab[ivide];
V(svide);
n_printf("exploiter l'information : %d\n", info);
}
}

View File

@ -1,5 +1,5 @@
/* Start.s /* Start.s
* Assembly language assist for user programs running on top of Nachos. * Assembly language assist for user programs running on top of BurritOS.
* *
* Since we don't want to pull in the entire C library, we define * Since we don't want to pull in the entire C library, we define
* what we need for a user program here, namely Start and the system * what we need for a user program here, namely Start and the system