loader now return better understanable errors, fix when compiler when to use bss section, add join exception, fix get_string_param, add support for thread in obbAddr, add a test

This commit is contained in:
Quentin Legot 2023-04-13 00:18:35 +02:00
parent 05f72af035
commit f144438490
6 changed files with 130 additions and 34 deletions

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, thread::Thread}; use super::{system::{System, self}, 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;
@ -142,7 +142,7 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
}, },
SC_EXEC => todo!(), SC_EXEC => todo!(),
SC_JOIN => todo!(), SC_JOIN => sc_join(machine, system),
SC_CREATE => todo!(), SC_CREATE => todo!(),
SC_OPEN => todo!(), SC_OPEN => todo!(),
SC_READ => todo!(), SC_READ => todo!(),
@ -231,7 +231,7 @@ fn sc_v(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Machine
fn sc_sem_create(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> { fn sc_sem_create(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
let addr_name = machine.read_int_register(10) as usize; let addr_name = machine.read_int_register(10) as usize;
let initial_count = machine.read_int_register(11) as i32; let initial_count = machine.read_int_register(11) as i32;
let size = get_length_param(addr_name as usize, machine); let size = get_length_param(addr_name, machine);
let _name = get_string_param(addr_name, size, machine); let _name = get_string_param(addr_name, size, machine);
match initial_count < 0 { match initial_count < 0 {
true => Err(format!("Initial_count < 0"))?, true => Err(format!("Initial_count < 0"))?,
@ -262,6 +262,7 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
let n_thread = Thread::new(thread_name.as_str()); let n_thread = Thread::new(thread_name.as_str());
let n_thread = Rc::new(RefCell::new(n_thread)); let n_thread = Rc::new(RefCell::new(n_thread));
let tid = system.get_thread_manager().get_obj_addrs().add_thread(Rc::clone(&n_thread));
let current_thread = match system.get_thread_manager().get_g_current_thread() { let current_thread = match system.get_thread_manager().get_g_current_thread() {
Some(th) => { Some(th) => {
Rc::clone(th) Rc::clone(th)
@ -274,25 +275,49 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
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); system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, current_thread.thread_context.int_registers[2] as u64, 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_fp_register(10, tid); // tid obtenu en faisant int32_t tid = g_object_addrs->AddObject(ptThread); machine.write_int_register(10, tid as i64);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
} else { } else {
return Err("Process owner of current thread is none")?; return Err("Process owner of current thread is none")?;
} }
} }
fn get_length_param(addr: usize, machine: & Machine) -> usize{ fn sc_join(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
let tid = machine.read_int_register(10);
let p_thread = system.get_thread_manager().get_obj_addrs().search_thread(tid as i32);
match p_thread {
Some(_) => {
if let Some(current_thread) = system.get_thread_manager().get_g_current_thread() {
let rc = Rc::clone(current_thread);
system.get_thread_manager().thread_join(machine, rc);
Ok(MachineOk::Ok)
} else {
Ok(MachineOk::Ok)
}
},
None => {
// Thread already terminated (type set to INVALID_TYPE) or call on an object
// that is not a thread
// Exit with no error code since we cannot separate the two cases
Ok(MachineOk::Ok)
}
}
}
fn get_length_param(addr: usize, machine: & Machine) -> usize {
let mut i = 0; let mut i = 0;
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
} }
fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>{ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char> {
let mut dest = Vec::with_capacity(maxlen); let mut dest = Vec::with_capacity(maxlen);
let mut i: usize = 0; let mut i: usize = 0;
@ -300,12 +325,10 @@ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>{
while c != 0 && i < maxlen { while c != 0 && i < maxlen {
c = machine.read_memory(1, addr + i) as u8; c = machine.read_memory(1, addr + i) as u8;
//dest.push(c as char); dest.push(c as char);
dest[i] = c as char;
i += 1; i += 1;
} }
dest.push('\0');
dest[maxlen - 1] = '\0';
dest dest
} }

View File

@ -40,7 +40,7 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
let mut machine = Machine::new(args.debug); let mut machine = Machine::new(args.debug);
let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("IO Error"); 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::default(); let mut system = System::default();

View File

@ -213,23 +213,23 @@ impl ElfHeader {
} }
impl TryFrom<&Vec<u8>> for ElfHeader { impl TryFrom<&Vec<u8>> for ElfHeader {
type Error = (); type Error = String;
fn try_from(instructions: &Vec<u8>) -> Result<Self, Self::Error> { fn try_from(instructions: &Vec<u8>) -> Result<Self, Self::Error> {
if Self::is_elf(instructions) { if Self::is_elf(instructions) {
let format = Self::is_32bits(instructions); let format = Self::is_32bits(instructions);
let endianess = Self::check_endianess(instructions); let endianess = Self::check_endianess(instructions);
let version = Self::get_version(instructions).ok_or(())?; let version = Self::get_version(instructions).ok_or("Cannot retrieve version")?;
let is_sys_v_abi = Self::is_system_v_elf(instructions); let is_sys_v_abi = Self::is_system_v_elf(instructions);
let is_rv_target = Self::is_riscv_isa(instructions); let is_rv_target = Self::is_riscv_isa(instructions);
let entrypoint = Self::get_entrypoint(instructions, format).ok_or(())?; let entrypoint = Self::get_entrypoint(instructions, format).ok_or("Cannot get entrypoint")?;
let elf_header_size = Self::get_elf_header_size(instructions, format).ok_or(())?; let elf_header_size = Self::get_elf_header_size(instructions, format).ok_or("Cannot get elf header size")?;
let program_header_location = Self::get_program_header_table_location(instructions, format).ok_or(())?; let program_header_location = Self::get_program_header_table_location(instructions, format).ok_or("Cannot get program header table location")?;
let program_header_entries = Self::get_number_entries_program_header(instructions, format).ok_or(())? ; let program_header_entries = Self::get_number_entries_program_header(instructions, format).ok_or("Cannot get number of entries in program header table")? ;
let program_header_size = Self::get_program_header_size(instructions, format).ok_or(())?; let program_header_size = Self::get_program_header_size(instructions, format).ok_or("Cannot get program header entry size")?;
let section_header_location = Self::get_section_header_table_location(instructions, format).ok_or(())?; let section_header_location = Self::get_section_header_table_location(instructions, format).ok_or("Cannot get section header table location")?;
let section_header_entries = Self::get_section_header_num_entries(instructions, format).ok_or(())?; let section_header_entries = Self::get_section_header_num_entries(instructions, format).ok_or("Cannot get number of entries of section header")?;
let section_header_size = Self::get_section_header_size(instructions, format).ok_or(())?; let section_header_size = Self::get_section_header_size(instructions, format).ok_or("Cannot get size of section header entry")?;
Ok(ElfHeader { Ok(ElfHeader {
endianess, endianess,
is_32bits: format, is_32bits: format,
@ -246,7 +246,7 @@ impl TryFrom<&Vec<u8>> for ElfHeader {
section_header_size section_header_size
}) })
} else { } else {
Err(()) Err("File doesn't have elf magic number")?
} }
} }
} }
@ -409,7 +409,7 @@ pub enum LoaderError {
/// Correspond to std IO error /// Correspond to std IO error
IOError(std::io::Error), IOError(std::io::Error),
/// Others errors /// Others errors
ParsingError ParsingError(String)
} }
/// Global structure of the loader, one instance per loaded files /// Global structure of the loader, one instance per loaded files
@ -455,7 +455,13 @@ impl Loader {
let mut buf: [u8; 4] = [0; 4]; let mut buf: [u8; 4] = [0; 4];
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
for k in 0..buf.len() { for k in 0..buf.len() {
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError)?; if section.does_flag_contains_key(FlagValue::ShfWrite) {
// flag WA, on doit allouer des données initialisés à 0
// généralement, ce signifie que le compilateur à ajouter une section .bss
buf[k] = 0;
} else {
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(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64);
} }
@ -492,8 +498,8 @@ impl Loader {
Ok(header) => { Ok(header) => {
header header
}, },
Err(_) => { Err(err) => {
return Err(LoaderError::ParsingError); return Err(LoaderError::ParsingError(format!("Cannot parse elf header : {}", err)));
} }
}; };
let section_header = match Self::parse_section_header(&instructions, elf_header.is_32bits, elf_header.section_header_location, elf_header.section_header_entries, elf_header.section_header_size) { let section_header = match Self::parse_section_header(&instructions, elf_header.is_32bits, elf_header.section_header_location, elf_header.section_header_entries, elf_header.section_header_size) {
@ -501,7 +507,7 @@ impl Loader {
header header
}, },
Err(_) => { Err(_) => {
return Err(LoaderError::ParsingError); return Err(LoaderError::ParsingError("Cannot parse section header".to_string()));
} }
}; };
// #[cfg(debug_assertions)] // #[cfg(debug_assertions)]

View File

@ -2,9 +2,9 @@
//! their references. The ObjAddr struct //! their references. The ObjAddr struct
//! allows to maintain this data structure. //! allows to maintain this data structure.
use std::collections::HashMap; use std::{collections::HashMap, cell::RefCell, rc::Rc};
use crate::kernel::synch::{ Semaphore, Lock }; use crate::kernel::{synch::{ Semaphore, Lock }, thread::Thread};
/// Brief Definition of object identifiers: /// Brief Definition of object identifiers:
/// ///
@ -19,7 +19,8 @@ use crate::kernel::synch::{ Semaphore, Lock };
pub struct ObjAddr { pub struct ObjAddr {
last_id: i32, last_id: i32,
semaphores: HashMap<i32, Semaphore>, semaphores: HashMap<i32, Semaphore>,
locks: HashMap<i32, Lock> locks: HashMap<i32, Lock>,
threads: HashMap<i32, Rc<RefCell<Thread>>>,
} }
impl ObjAddr { impl ObjAddr {
@ -29,7 +30,8 @@ impl ObjAddr {
Self { Self {
last_id: 3, last_id: 3,
semaphores: HashMap::<i32, Semaphore>::new(), semaphores: HashMap::<i32, Semaphore>::new(),
locks: HashMap::<i32, Lock>::new() locks: HashMap::<i32, Lock>::new(),
threads: HashMap::<i32, Rc<RefCell<Thread>>>::new(),
} }
} }
@ -47,6 +49,13 @@ impl ObjAddr {
self.last_id self.last_id
} }
/// Adds the **obj** Lock to self
pub fn add_thread(&mut self, obj: Rc<RefCell<Thread>>) -> i32 {
self.last_id +=1;
self.threads.insert(self.last_id, obj);
self.last_id
}
/// Searches for a semaphore of id **id** in self /// Searches for a semaphore of id **id** in self
pub fn search_semaphore(&mut self, id: i32) -> Option<&mut Semaphore> { pub fn search_semaphore(&mut self, id: i32) -> Option<&mut Semaphore> {
self.semaphores.get_mut(&id) self.semaphores.get_mut(&id)
@ -57,6 +66,11 @@ impl ObjAddr {
self.locks.get_mut(&id) self.locks.get_mut(&id)
} }
/// Searches for a lock of id **id** in self
pub fn search_thread(&mut self, id: i32) -> Option<&Rc<RefCell<Thread>>> {
self.threads.get(&id)
}
/// Removes the object of id **id** from self if it exists /// Removes the object of id **id** from self if it exists
pub fn remove_semaphore(&mut self, id: i32) -> Option<Semaphore> { pub fn remove_semaphore(&mut self, id: i32) -> Option<Semaphore> {
self.semaphores.remove(&id) self.semaphores.remove(&id)
@ -67,5 +81,10 @@ impl ObjAddr {
self.locks.remove(&id) self.locks.remove(&id)
} }
/// Remove the object of id **id** from self if it exists
pub fn remove_thread(&mut self, id: i32) -> Option<Rc<RefCell<Thread>>> {
self.threads.remove(&id)
}
} }

View File

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

View File

@ -0,0 +1,48 @@
#include "userlib/syscall.h"
#include "userlib/libnachos.h"
const int N = 3;
int iplein = 0;
int ivide = 0;
int tab[3];
SemId svide;
SemId splein;
void producteur();
void consommateur();
int main() {
svide = SemCreate("producteur", N);
splein = SemCreate("consommateur", 0);
ThreadId producteurTh = threadCreate("producteur", producteur);
ThreadId consommateurTh = threadCreate("consommateur", consommateur);
Join(producteurTh);
Join(consommateurTh);
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);
}
}