Merge branch 'exception' into 'thread_scheduler'
Exception See merge request simpleos/burritos!14
This commit is contained in:
commit
41611b54e8
@ -1,5 +1,9 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}};
|
use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}};
|
||||||
|
|
||||||
|
use super::system::System;
|
||||||
|
|
||||||
|
|
||||||
pub const SC_SHUTDOWN: u8 = 0;
|
pub const SC_SHUTDOWN: u8 = 0;
|
||||||
pub const SC_EXIT: u8 = 1;
|
pub const SC_EXIT: u8 = 1;
|
||||||
@ -40,11 +44,11 @@ pub const SC_DEBUG: u8 = 34;
|
|||||||
pub const CONSOLE_OUTPUT: u8 = 1;
|
pub const CONSOLE_OUTPUT: u8 = 1;
|
||||||
|
|
||||||
// todo : returns new types, not just machine errors and machine ok
|
// todo : returns new types, not just machine errors and machine ok
|
||||||
pub fn call(exception: ExceptionType, machine: &Machine) -> Result<MachineOk, MachineError> {
|
pub fn call(exception: &ExceptionType, machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||||
|
|
||||||
match exception {
|
match exception {
|
||||||
ExceptionType::NoException => todo!(),
|
ExceptionType::NoException => todo!(),
|
||||||
ExceptionType::SyscallException => syscall(machine),
|
ExceptionType::SyscallException => syscall(machine, system),
|
||||||
ExceptionType::PagefaultException => todo!(),
|
ExceptionType::PagefaultException => todo!(),
|
||||||
ExceptionType::ReadOnlyException => todo!(),
|
ExceptionType::ReadOnlyException => todo!(),
|
||||||
ExceptionType::BusErrorException => todo!(),
|
ExceptionType::BusErrorException => todo!(),
|
||||||
@ -55,12 +59,19 @@ pub fn call(exception: ExceptionType, machine: &Machine) -> Result<MachineOk, Ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syscall(machine: &Machine) -> Result<MachineOk, MachineError> {
|
fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||||
let call_type = machine.read_int_register(17) as u8;
|
let call_type = machine.read_int_register(17) as u8;
|
||||||
|
|
||||||
match call_type {
|
match call_type {
|
||||||
SC_SHUTDOWN => Ok(MachineOk::Shutdown),
|
SC_SHUTDOWN => Ok(MachineOk::Shutdown),
|
||||||
SC_EXIT => todo!(),
|
SC_EXIT => {
|
||||||
|
let th = match &system.get_thread_manager().g_current_thread {
|
||||||
|
Some(th) => th.clone(),
|
||||||
|
None => Err("Current thread is None")?
|
||||||
|
};
|
||||||
|
system.get_thread_manager().thread_finish(machine, th);
|
||||||
|
Ok(MachineOk::Ok)
|
||||||
|
},
|
||||||
SC_EXEC => todo!(),
|
SC_EXEC => todo!(),
|
||||||
SC_JOIN => todo!(),
|
SC_JOIN => todo!(),
|
||||||
SC_CREATE => todo!(),
|
SC_CREATE => todo!(),
|
||||||
@ -121,6 +132,7 @@ fn syscall(machine: &Machine) -> Result<MachineOk, MachineError> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::kernel::exception::{SC_SHUTDOWN, SC_WRITE};
|
use crate::kernel::exception::{SC_SHUTDOWN, SC_WRITE};
|
||||||
|
use crate::kernel::system::System;
|
||||||
use crate::simulator::instruction::Instruction;
|
use crate::simulator::instruction::Instruction;
|
||||||
use crate::simulator::machine::Machine;
|
use crate::simulator::machine::Machine;
|
||||||
|
|
||||||
@ -132,8 +144,8 @@ mod test {
|
|||||||
|
|
||||||
machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall
|
machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall
|
||||||
machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10
|
machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10
|
||||||
|
let mut system = System::default();
|
||||||
machine.run();
|
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
|
||||||
assert_ne!(machine.read_int_register(1), 10); // Check if the next instruction was executed
|
assert_ne!(machine.read_int_register(1), 10); // Check if the next instruction was executed
|
||||||
}
|
}
|
||||||
@ -162,9 +174,9 @@ mod test {
|
|||||||
|
|
||||||
machine.write_memory(4, 4, 0b000000000000_00000_000_10001_0010011); // r17 <- SC_SHUTDOWN
|
machine.write_memory(4, 4, 0b000000000000_00000_000_10001_0010011); // r17 <- SC_SHUTDOWN
|
||||||
machine.write_memory(4, 8, 0b000000000000_00000_000_00000_1110011); // ecall
|
machine.write_memory(4, 8, 0b000000000000_00000_000_00000_1110011); // ecall
|
||||||
|
|
||||||
|
let mut system = System::default();
|
||||||
machine.run();
|
machine.run(&mut system);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -123,8 +123,8 @@ impl ThreadManager {
|
|||||||
|
|
||||||
/// Put the thread to sleep and relinquish the processor
|
/// Put the thread to sleep and relinquish the processor
|
||||||
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: Rc<RefCell<Thread>>) {
|
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: Rc<RefCell<Thread>>) {
|
||||||
assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
||||||
assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
||||||
|
|
||||||
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() {
|
||||||
@ -141,6 +141,8 @@ impl ThreadManager {
|
|||||||
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
||||||
self.g_thread_to_be_destroyed = Option::Some(Rc::clone(&thread));
|
self.g_thread_to_be_destroyed = Option::Some(Rc::clone(&thread));
|
||||||
self.g_alive.remove(Rc::clone(&thread));
|
self.g_alive.remove(Rc::clone(&thread));
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("Sleeping thread {}", thread.borrow().get_name());
|
||||||
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
|
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
|
||||||
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);
|
||||||
@ -220,22 +222,22 @@ mod test {
|
|||||||
let thread2 = Rc::new(RefCell::new(thread2));
|
let thread2 = Rc::new(RefCell::new(thread2));
|
||||||
system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1));
|
system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1));
|
||||||
|
|
||||||
let owner2 = Process { num_thread: 0 };
|
|
||||||
system.get_thread_manager().start_thread(Rc::clone(&thread2), owner2, ptr1 + loader2.elf_header.entrypoint, ptr2 , -1);
|
|
||||||
|
|
||||||
let owner1 = Process { num_thread: 0 };
|
let owner1 = Process { num_thread: 0 };
|
||||||
system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr1, -1);
|
system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr1, -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)));
|
||||||
|
|
||||||
|
let owner2 = Process { num_thread: 0 };
|
||||||
|
system.get_thread_manager().start_thread(Rc::clone(&thread2), owner2, ptr1 + loader2.elf_header.entrypoint, ptr2 , -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();
|
||||||
debug_assert_eq!(to_run, Rc::clone(&thread2));
|
debug_assert_eq!(to_run, Rc::clone(&thread1));
|
||||||
|
|
||||||
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));
|
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));
|
||||||
debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread2)));
|
debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread1)));
|
||||||
debug_assert_eq!(machine.pc, ptr1 + loader2.elf_header.entrypoint);
|
debug_assert_eq!(machine.pc, loader.elf_header.entrypoint);
|
||||||
|
|
||||||
machine.run();
|
machine.run(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -18,6 +18,6 @@ use simulator::machine::Machine;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut machine = Machine::init_machine();
|
let mut machine = Machine::init_machine();
|
||||||
let system = System::default();
|
let mut system = System::default();
|
||||||
machine.run()
|
machine.run(&mut system);
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ use std::{
|
|||||||
io::Write,
|
io::Write,
|
||||||
fs::File
|
fs::File
|
||||||
};
|
};
|
||||||
use crate::simulator::{
|
use crate::{simulator::{
|
||||||
error::MachineError,
|
error::MachineError,
|
||||||
instruction::{*, self},
|
instruction::{*, self},
|
||||||
interrupt::Interrupt,
|
interrupt::Interrupt,
|
||||||
global::*,
|
global::*,
|
||||||
register::*
|
register::*
|
||||||
};
|
}, kernel::system::System};
|
||||||
|
|
||||||
use crate::kernel::{
|
use crate::kernel::{
|
||||||
exception
|
exception
|
||||||
@ -34,6 +34,7 @@ use super::error::MachineOk;
|
|||||||
/// Textual names of the exceptions that can be generated by user program
|
/// Textual names of the exceptions that can be generated by user program
|
||||||
/// execution, for debugging purpose.
|
/// execution, for debugging purpose.
|
||||||
/// todo: is this really supposed to stand in machine.rs?
|
/// todo: is this really supposed to stand in machine.rs?
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ExceptionType {
|
pub enum ExceptionType {
|
||||||
/// Everything ok
|
/// Everything ok
|
||||||
NoException,
|
NoException,
|
||||||
@ -226,16 +227,15 @@ impl Machine {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_exception(&mut self, exception: ExceptionType, address : u64) -> Result<MachineOk, MachineError>{
|
pub fn raise_exception(&mut self, exception: ExceptionType, address : u64, system: &mut System) -> Result<MachineOk, MachineError>{
|
||||||
|
|
||||||
self.set_status(MachineStatus::SystemMode);
|
self.set_status(MachineStatus::SystemMode);
|
||||||
// Handle the interruption
|
// Handle the interruption
|
||||||
match exception::call(exception, self) {
|
match exception::call(&exception, self, system) {
|
||||||
Ok(MachineOk::Shutdown) => {
|
Ok(MachineOk::Shutdown) => {
|
||||||
self.set_status(MachineStatus::UserMode);
|
self.set_status(MachineStatus::UserMode);
|
||||||
return Ok(MachineOk::Shutdown);
|
return Ok(MachineOk::Shutdown);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => Err(format!("Syscall {:?} invalid or not implemented", exception))?
|
||||||
} // todo: return error if the syscall code is invalid
|
} // todo: return error if the syscall code is invalid
|
||||||
self.set_status(MachineStatus::UserMode);
|
self.set_status(MachineStatus::UserMode);
|
||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
@ -246,12 +246,12 @@ impl Machine {
|
|||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
///
|
///
|
||||||
/// - **machine** which contains a table of instructions
|
/// - **machine** which contains a table of instructions
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self, system: &mut System) {
|
||||||
loop {
|
loop {
|
||||||
match self.one_instruction() {
|
match self.one_instruction(system) {
|
||||||
Ok(MachineOk::Ok) => println!("hello"),
|
Ok(MachineOk::Ok) => println!("hello"),
|
||||||
Ok(MachineOk::Shutdown) => break,
|
Ok(MachineOk::Shutdown) => break,
|
||||||
Err(e) => { if e.to_string().contains("System") { break; } panic!("FATAL at pc {} -> {}", self.pc, e) }
|
Err(e) => panic!("FATAL at pc {} -> {}", self.pc, e)
|
||||||
}
|
}
|
||||||
self.write_int_register(0, 0); // In case an instruction write on register 0
|
self.write_int_register(0, 0); // In case an instruction write on register 0
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ impl Machine {
|
|||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
///
|
///
|
||||||
/// - **machine** which contains a table of instructions and a pc to the actual instruction
|
/// - **machine** which contains a table of instructions and a pc to the actual instruction
|
||||||
pub fn one_instruction(&mut self) -> Result<MachineOk, MachineError> {
|
pub fn one_instruction(&mut self, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||||
|
|
||||||
if self.main_memory.len() <= self.pc as usize {
|
if self.main_memory.len() <= self.pc as usize {
|
||||||
panic!("ERROR : number max of instructions rushed");
|
panic!("ERROR : number max of instructions rushed");
|
||||||
@ -335,7 +335,7 @@ impl Machine {
|
|||||||
RISCV_FP => self.fp_instruction(inst),
|
RISCV_FP => self.fp_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: SYSTEM CALLS
|
// Treatment for: SYSTEM CALLS
|
||||||
RISCV_SYSTEM => self.raise_exception(ExceptionType::SyscallException, self.pc),
|
RISCV_SYSTEM => self.raise_exception(ExceptionType::SyscallException, self.pc, system),
|
||||||
|
|
||||||
// Default case
|
// Default case
|
||||||
_ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))?
|
_ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))?
|
||||||
@ -710,7 +710,8 @@ mod test {
|
|||||||
let memory_before = mem_cmp::MemChecker::from(get_full_path!("memory", $a)).unwrap();
|
let memory_before = mem_cmp::MemChecker::from(get_full_path!("memory", $a)).unwrap();
|
||||||
let memory_after = mem_cmp::MemChecker::from(get_full_path!("memory", &end_file_name)).unwrap();
|
let memory_after = mem_cmp::MemChecker::from(get_full_path!("memory", &end_file_name)).unwrap();
|
||||||
mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m);
|
mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m);
|
||||||
m.run();
|
let mut system = crate::kernel::system::System::default();
|
||||||
|
m.run(&mut system);
|
||||||
let expected_trace = fs::read_to_string(get_full_path!("reg_trace", $a)).unwrap();
|
let expected_trace = fs::read_to_string(get_full_path!("reg_trace", $a)).unwrap();
|
||||||
assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m));
|
assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m));
|
||||||
assert!(expected_trace.contains(m.registers_trace.as_str()));
|
assert!(expected_trace.contains(m.registers_trace.as_str()));
|
||||||
|
@ -113,8 +113,12 @@ impl<T: PartialEq> List<T> {
|
|||||||
let mut current: *mut Node<T> = self.head;
|
let mut current: *mut Node<T> = self.head;
|
||||||
let mut previous: *mut Node<T> = ptr::null_mut();
|
let mut previous: *mut Node<T> = ptr::null_mut();
|
||||||
while !current.is_null() {
|
while !current.is_null() {
|
||||||
if (*current).elem == item {
|
if (&*current).elem == item {
|
||||||
(*previous).next = (*current).next;
|
if !previous.is_null() {
|
||||||
|
(*previous).next = (*current).next;
|
||||||
|
} else {
|
||||||
|
self.head = (*current).next;
|
||||||
|
}
|
||||||
drop(Box::from_raw(current).elem);
|
drop(Box::from_raw(current).elem);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -320,6 +324,22 @@ mod test {
|
|||||||
assert_eq!(list.peek(), Option::None);
|
assert_eq!(list.peek(), Option::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_test2() {
|
||||||
|
let mut list = List::default();
|
||||||
|
assert_eq!(list.peek(), None);
|
||||||
|
list.push(1);
|
||||||
|
list.push(2);
|
||||||
|
list.push(3);
|
||||||
|
|
||||||
|
assert_eq!(list.contains(&1), true);
|
||||||
|
list.remove(1);
|
||||||
|
assert_eq!(list.contains(&1), false);
|
||||||
|
assert_eq!(list.pop(), Option::Some(2));
|
||||||
|
assert_eq!(list.pop(), Option::Some(3));
|
||||||
|
assert_eq!(list.peek(), Option::None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn miri_test() {
|
fn miri_test() {
|
||||||
let mut list = List::default();
|
let mut list = List::default();
|
||||||
|
Loading…
Reference in New Issue
Block a user