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:
parent
05f72af035
commit
f144438490
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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)]
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -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
|
||||||
|
|
||||||
|
48
test/syscall_tests/producteur_consommateur.c
Normal file
48
test/syscall_tests/producteur_consommateur.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user