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::kernel::synch::{Lock, Semaphore};
use super::{system::System, thread::Thread};
use super::{system::{System, self}, thread::Thread};
/// The halt system call. Stops Burritos.
pub const SC_SHUTDOWN: u8 = 0;
@ -142,7 +142,7 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
Ok(MachineOk::Ok)
},
SC_EXEC => todo!(),
SC_JOIN => todo!(),
SC_JOIN => sc_join(machine, system),
SC_CREATE => todo!(),
SC_OPEN => 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> {
let addr_name = machine.read_int_register(10) as usize;
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);
match 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 = 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() {
Some(th) => {
Rc::clone(th)
@ -274,13 +275,36 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
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);
// 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)
} else {
return Err("Process owner of current thread is none")?;
}
}
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 c = 1;
@ -289,6 +313,7 @@ fn get_length_param(addr: usize, machine: & Machine) -> usize{
i +=1;
}
println!("addr: {:x}, i: {}", addr, i + 1);
i + 1
}
@ -300,12 +325,10 @@ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>{
while c != 0 && i < maxlen {
c = machine.read_memory(1, addr + i) as u8;
//dest.push(c as char);
dest[i] = c as char;
dest.push(c as char);
i += 1;
}
dest[maxlen - 1] = '\0';
dest.push('\0');
dest
}

View File

@ -40,7 +40,7 @@ fn main() {
let args = Args::parse();
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();

View File

@ -213,23 +213,23 @@ impl ElfHeader {
}
impl TryFrom<&Vec<u8>> for ElfHeader {
type Error = ();
type Error = String;
fn try_from(instructions: &Vec<u8>) -> Result<Self, Self::Error> {
if Self::is_elf(instructions) {
let format = Self::is_32bits(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_rv_target = Self::is_riscv_isa(instructions);
let entrypoint = Self::get_entrypoint(instructions, format).ok_or(())?;
let elf_header_size = Self::get_elf_header_size(instructions, format).ok_or(())?;
let program_header_location = Self::get_program_header_table_location(instructions, format).ok_or(())?;
let program_header_entries = Self::get_number_entries_program_header(instructions, format).ok_or(())? ;
let program_header_size = Self::get_program_header_size(instructions, format).ok_or(())?;
let section_header_location = Self::get_section_header_table_location(instructions, format).ok_or(())?;
let section_header_entries = Self::get_section_header_num_entries(instructions, format).ok_or(())?;
let section_header_size = Self::get_section_header_size(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("Cannot get elf header size")?;
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("Cannot get number of entries in program header table")? ;
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("Cannot get section header table location")?;
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("Cannot get size of section header entry")?;
Ok(ElfHeader {
endianess,
is_32bits: format,
@ -246,7 +246,7 @@ impl TryFrom<&Vec<u8>> for ElfHeader {
section_header_size
})
} else {
Err(())
Err("File doesn't have elf magic number")?
}
}
}
@ -409,7 +409,7 @@ pub enum LoaderError {
/// Correspond to std IO error
IOError(std::io::Error),
/// Others errors
ParsingError
ParsingError(String)
}
/// Global structure of the loader, one instance per loaded files
@ -455,7 +455,13 @@ impl Loader {
let mut buf: [u8; 4] = [0; 4];
#[allow(clippy::needless_range_loop)]
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);
}
@ -492,8 +498,8 @@ impl Loader {
Ok(header) => {
header
},
Err(_) => {
return Err(LoaderError::ParsingError);
Err(err) => {
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) {
@ -501,7 +507,7 @@ impl Loader {
header
},
Err(_) => {
return Err(LoaderError::ParsingError);
return Err(LoaderError::ParsingError("Cannot parse section header".to_string()));
}
};
// #[cfg(debug_assertions)]

View File

@ -2,9 +2,9 @@
//! their references. The ObjAddr struct
//! 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:
///
@ -19,7 +19,8 @@ use crate::kernel::synch::{ Semaphore, Lock };
pub struct ObjAddr {
last_id: i32,
semaphores: HashMap<i32, Semaphore>,
locks: HashMap<i32, Lock>
locks: HashMap<i32, Lock>,
threads: HashMap<i32, Rc<RefCell<Thread>>>,
}
impl ObjAddr {
@ -29,7 +30,8 @@ impl ObjAddr {
Self {
last_id: 3,
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
}
/// 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
pub fn search_semaphore(&mut self, id: i32) -> Option<&mut Semaphore> {
self.semaphores.get_mut(&id)
@ -57,6 +66,11 @@ impl ObjAddr {
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
pub fn remove_semaphore(&mut self, id: i32) -> Option<Semaphore> {
self.semaphores.remove(&id)
@ -67,5 +81,10 @@ impl ObjAddr {
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 = ../..
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);
}
}