From 08ba0154f75460f50fbe49d658ef28c9b3dfc75a Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 27 Mar 2023 18:10:11 +0200 Subject: [PATCH 01/57] Add a bin loader --- src/kernel/mod.rs | 2 +- src/main.rs | 24 +++++++++++++++++++++--- src/simulator/loader.rs | 31 +++++++++++++++++++++++++++++++ src/simulator/machine.rs | 30 +++++++++++++++--------------- src/simulator/print.rs | 2 +- 5 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 67a43cb..1fe4f0f 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,4 +1,4 @@ -mod process; +pub mod process; pub mod thread; pub mod mgerror; pub mod system; diff --git a/src/main.rs b/src/main.rs index cc181fe..2774e7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,10 +13,28 @@ mod kernel; /// module containing useful tools which can be use in most part of the OS to ease the development of the OS pub mod utility; +use std::{rc::Rc, cell::RefCell}; + use kernel::system::System; -use simulator::machine::Machine; +use simulator::{machine::Machine, loader}; + +use crate::kernel::{thread::Thread, process::Process}; fn main() { - let machine = Machine::init_machine(); - let system = System::default(); + let mut machine = Machine::init_machine(); + loader::load("test.o", &mut machine, 0).expect("IO Error"); + let system = &mut System::default(); + let thread1 = Thread::new("th1"); + let thread1 = Rc::new(RefCell::new(thread1)); + system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); + let owner = Process { num_thread: 0 }; + system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, 0 as i64, 0); + debug_assert_eq!(thread1.borrow_mut().thread_context.pc, 0 as i64); + let to_run = system.get_thread_manager().find_next_to_run().unwrap(); + debug_assert_eq!(to_run, Rc::clone(&thread1)); + debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); + system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run)); + + machine.run(); + } diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 4b84b83..3404128 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -3,6 +3,7 @@ use crate::Machine; use std::fs; use std::io; use std::io::BufRead; +use std::io::Read; @@ -15,6 +16,7 @@ use std::io::BufRead; /// /// - **path** the path of the file to load /// - **size** the number of bytes to write (1, 2, 4 or 8) +#[deprecated] pub fn _load(path : &str, instruction_size: i32) -> Machine { let file = fs::File::open(path).expect("Wrong filename"); let reader = io::BufReader::new(file); @@ -31,4 +33,33 @@ pub fn _load(path : &str, instruction_size: i32) -> Machine { } println!("{:x}", Machine::read_memory(& mut machine, 4, 0)); machine +} + +/// load a 32-bits binary file into the machine +/// +/// ### Parameters +/// +/// - **path** path of the file to load +/// - **machine** the machine where the bin file will be loaded +/// - **start_index** at which index of machine memory you want to start to load the program +/// +/// Returns in a Result any io error +pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result<(), std::io::Error> { + let mut file = fs::File::open(path)?; + let mut instructions: Vec = Default::default(); + loop { + let mut buf: [u8; 4] = [0; 4]; + let res = file.read(&mut buf)?; + if res == 0 { + break; // eof + } else { + instructions.push(u32::from_le_bytes(buf)); + } + } + for i in 0..instructions.len() { + machine.write_memory(4, 4 * i + start_index, instructions[i] as u64); + } + #[cfg(debug_assertions)] + println!("{:04x?}", instructions); // only print loaded program in debug build + Ok(()) } \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index e54bd87..7d62e78 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -146,7 +146,7 @@ impl Machine { /// - **machine** which contains the main memory /// - **size** the number of bytes to read (1, 2, 4, 8) /// - **address** in the memory to read - pub fn read_memory(machine : &mut Machine, size : i32, address : usize) -> u64 { + pub fn read_memory(&mut self, size : i32, address : usize) -> u64 { if ![1, 2, 4, 8].contains(&size) { panic!("ERROR read_memory : wrong size parameter {size}, must be (1, 2, 4 or 8)"); } @@ -154,7 +154,7 @@ impl Machine { let mut ret: u64 = 0; for i in 0..size { ret <<= 8; - ret += machine.main_memory[address + i as usize] as u64; + ret += self.main_memory[address + i as usize] as u64; } ret } @@ -169,13 +169,13 @@ impl Machine { /// - **size** the number of bytes to write (1, 2, 4 or 8) /// - **address** the address to write to /// - **value** data to be written - pub fn write_memory(machine: &mut Machine, size: i32, address: usize, value: u64) { + pub fn write_memory(&mut self, size: i32, address: usize, value: u64) { if ![1, 2, 4, 8].contains(&size) { panic!("ERROR write_memory: WRONG `size` PARAMETER ({size}), must be 1, 2, 4 or 8") } for i in 0..size as usize { let inv_i = size as usize - i - 1; - machine.main_memory[address + i] = ((value & 0xff << (8 * inv_i)) >> (inv_i * 8)) as u8; + self.main_memory[address + i] = ((value & 0xff << (8 * inv_i)) >> (inv_i * 8)) as u8; } } @@ -185,11 +185,11 @@ impl Machine { /// ### Parameters /// /// - **machine** contains the memory - pub fn _extract_memory(machine: &mut Machine){ + pub fn _extract_memory(&mut self){ let file_path = "burritos_memory.txt"; let write_to_file = |path| -> std::io::Result { let mut file = File::create(path)?; - file.write_all(&machine.main_memory)?; + file.write_all(&self.main_memory)?; Ok(file) }; match write_to_file(file_path) { @@ -198,20 +198,20 @@ impl Machine { }; } - pub fn print_machine_status(machine: &mut Machine) { + pub fn print_machine_status(&mut self) { println!("######### Machine status #########"); for i in (0..32).step_by(3) { - print!(">{0: <4} : {1:<16x} ", print::REG_X[i], machine.int_reg.get_reg(i)); - print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], machine.int_reg.get_reg(i+1)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i], self.int_reg.get_reg(i)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], self.int_reg.get_reg(i+1)); if i+2 < 32 { - print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], machine.int_reg.get_reg(i+2)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], self.int_reg.get_reg(i+2)); } println!(); } println!("________________SP________________"); - let sp_index = machine.int_reg.get_reg(2); + let sp_index = self.int_reg.get_reg(2); for i in 0..5 { - println!("SP+{:<2} : {:16x}", i*8, Self::read_memory(machine, 8, (sp_index + i*8) as usize)); + println!("SP+{:<2} : {:16x}", i*8, Self::read_memory(self, 8, (sp_index + i*8) as usize)); } println!("##################################"); } @@ -229,9 +229,9 @@ impl Machine { /// ### Parameters /// /// - **machine** which contains a table of instructions - pub fn run(machine : &mut Machine){ - while Machine::one_instruction(machine) == 0 {} - println!("trace : \n{}", machine.registers_trace); + pub fn run(&mut self){ + while Machine::one_instruction(self) == 0 {} + println!("trace : \n{}", self.registers_trace); } /// execute the current instruction diff --git a/src/simulator/print.rs b/src/simulator/print.rs index 54bcddf..c9b62b1 100644 --- a/src/simulator/print.rs +++ b/src/simulator/print.rs @@ -216,7 +216,7 @@ pub fn print(ins: Instruction, pc: i32) -> String { //TODO pc should be u64 RISCV_SYSTEM => { "ecall".to_string() }, - _ => todo!("{:x} opcode non géré pc : {:x}, value : {:x}", ins.opcode, pc, ins.value) // Change todo! to panic! in the future, I put todo! because there's a lot of opcode currently not implemented + _ => unreachable!("{:x} opcode non géré pc : {:x}, value : {:x}", ins.opcode, pc, ins.value) } } From 2f986da7ae746d499d5bbb12d5963a79735ed582 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 27 Mar 2023 22:20:29 +0200 Subject: [PATCH 02/57] fix save_processor_state, move test to thread_manager --- src/kernel/thread.rs | 4 ++-- src/kernel/thread_manager.rs | 30 ++++++++++++++++-------------- src/main.rs | 20 +------------------- 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 92f8986..05d94ad 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -16,7 +16,7 @@ macro_rules! get_new_thread { pub struct ThreadContext { pub int_registers: [i64; NUM_INT_REGS], pub float_registers: [f32; NUM_FP_REGS], - pub pc: i64, + pub pc: u64, } #[derive(PartialEq, Debug)] @@ -47,7 +47,7 @@ impl Thread { } } - pub fn init_thread_context(&mut self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { + pub fn init_thread_context(&mut self, initial_pc_reg: u64, initial_sp: i64, arg: i64) { self.thread_context.pc = initial_pc_reg; self.thread_context.int_registers[10] = arg; self.thread_context.int_registers[STACK_REG] = initial_sp; diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 56db16b..3ffdad0 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -78,13 +78,15 @@ impl ThreadManager { } }, None => { - + self.thread_restore_processor_state(machine, Rc::clone(&next_thread)); + // next_thread.restore_simulator_state(); + self.set_g_current_thread(Some(next_thread)); } } } /// Start a thread, attaching it to a process - pub fn start_thread(&mut self, thread: Rc>, owner: Process, func_pc: i64, argument: i64) { + pub fn start_thread(&mut self, thread: Rc>, owner: Process, func_pc: u64, argument: i64) { let mut thread_m = thread.borrow_mut(); assert_eq!(thread_m.process, Option::None); thread_m.process = Option::Some(owner); @@ -153,6 +155,7 @@ impl ThreadManager { for i in 0..NUM_FP_REGS { t.thread_context.float_registers[i] = machine.read_fp_register(i); } + t.thread_context.pc = machine.pc; } /// Restore the CPU state of a user program on a context switch. @@ -161,6 +164,7 @@ impl ThreadManager { for i in 0..NUM_INT_REGS { machine.write_int_register(i, t.thread_context.int_registers[i]); } + machine.pc = t.thread_context.pc; } /// Currently running thread @@ -196,28 +200,26 @@ impl ThreadManager { mod test { use std::{rc::Rc, cell::RefCell}; - use crate::{simulator::machine::Machine, kernel::{system::System, thread::Thread, process::Process}}; + use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::Thread, process::Process}}; #[test] fn test_thread_context() { let mut machine = Machine::init_machine(); - let mut system = System::default(); + loader::load("../test.o", &mut machine, 0).expect("IO Error"); + let system = &mut System::default(); let thread1 = Thread::new("th1"); let thread1 = Rc::new(RefCell::new(thread1)); system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, thread1_func as i64, 0); - assert_eq!(thread1.borrow_mut().thread_context.pc, thread1_func as i64); + system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, 0x94 as u64, 0); + debug_assert_eq!(thread1.borrow_mut().thread_context.pc, 0x94 as u64); let to_run = system.get_thread_manager().find_next_to_run().unwrap(); - assert_eq!(to_run, Rc::clone(&thread1)); - assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); + debug_assert_eq!(to_run, Rc::clone(&thread1)); + debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run)); - - println!("{:#?}", thread1.borrow_mut().thread_context); - } - - fn thread1_func() { - println!("Hello"); + debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread1))); + debug_assert_eq!(machine.pc, 0x94); + machine.run(); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2774e7b..874aa9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,28 +13,10 @@ mod kernel; /// module containing useful tools which can be use in most part of the OS to ease the development of the OS pub mod utility; -use std::{rc::Rc, cell::RefCell}; - use kernel::system::System; -use simulator::{machine::Machine, loader}; - -use crate::kernel::{thread::Thread, process::Process}; +use simulator::machine::Machine; fn main() { let mut machine = Machine::init_machine(); - loader::load("test.o", &mut machine, 0).expect("IO Error"); let system = &mut System::default(); - let thread1 = Thread::new("th1"); - let thread1 = Rc::new(RefCell::new(thread1)); - system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); - let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, 0 as i64, 0); - debug_assert_eq!(thread1.borrow_mut().thread_context.pc, 0 as i64); - let to_run = system.get_thread_manager().find_next_to_run().unwrap(); - debug_assert_eq!(to_run, Rc::clone(&thread1)); - debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); - system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run)); - - machine.run(); - } From c9792d1a1ae3f8fc51010f3c511195fb1e2bf7bf Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 27 Mar 2023 22:24:46 +0200 Subject: [PATCH 03/57] Ignore uncomplete test --- src/kernel/thread_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 3ffdad0..4734b40 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -203,6 +203,7 @@ mod test { use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::Thread, process::Process}}; #[test] + #[ignore = "Pas encore terminé, contient des bugs"] fn test_thread_context() { let mut machine = Machine::init_machine(); loader::load("../test.o", &mut machine, 0).expect("IO Error"); From 7a32aa503c5c1411995d12e958bfa390aab82879 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Mar 2023 17:54:05 +0200 Subject: [PATCH 04/57] Trying to make bin tests files --- test/Makefile | 11 ++++++++++- test/riscv_instructions/Makefile | 12 +++++++++++- test/riscv_instructions/boolean_logic/Makefile | 2 ++ test/userlib/Makefile | 5 ++++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/test/Makefile b/test/Makefile index ad2c039..c017d08 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,9 +1,15 @@ TOPDIR=. include $(TOPDIR)/Makefile.config + +all: dumps user_lib tests # # Main targets # + +build: user_lib + $(MAKE) build -C riscv_instructions/ + dumps: $(MAKE) dumps -C riscv_instructions/ mkdir -p ${TOPDIR}/target/dumps/ @@ -18,4 +24,7 @@ tests: user_lib find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ \; clean: - rm -rf $(TOPDIR)/target \ No newline at end of file + $(MAKE) clean -C userlib/ + $(MAKE) clean -C riscv_instructions/ + $(RM) -rf $(TOPDIR)/target + \ No newline at end of file diff --git a/test/riscv_instructions/Makefile b/test/riscv_instructions/Makefile index 22a1303..cabd3bb 100644 --- a/test/riscv_instructions/Makefile +++ b/test/riscv_instructions/Makefile @@ -1,3 +1,8 @@ +build: + make build -C boolean_logic/ +# make build -C jump_instructions/ +# make build -C simple_arithmetics/ + dumps: make dumps -C boolean_logic/ make dumps -C jump_instructions/ @@ -6,4 +11,9 @@ dumps: tests: make tests -C boolean_logic/ make tests -C jump_instructions/ - make tests -C simple_arithmetics/ \ No newline at end of file + make tests -C simple_arithmetics/ + +clean: + $(MAKE) clean -C boolean_logic/ + $(MAKE) clean -C jump_instructions/ + $(MAKE) clean -C simple_arithmetics/ \ No newline at end of file diff --git a/test/riscv_instructions/boolean_logic/Makefile b/test/riscv_instructions/boolean_logic/Makefile index 5f738e9..b1f6312 100644 --- a/test/riscv_instructions/boolean_logic/Makefile +++ b/test/riscv_instructions/boolean_logic/Makefile @@ -1,6 +1,8 @@ TOPDIR = ../.. include $(TOPDIR)/Makefile.tests +build: comparisons if switch + dumps: comparisons.dump if.dump switch.dump tests: comparisons.guac if.guac switch.guac diff --git a/test/userlib/Makefile b/test/userlib/Makefile index 903f3b5..6a5c70f 100644 --- a/test/userlib/Makefile +++ b/test/userlib/Makefile @@ -1,4 +1,7 @@ TOPDIR = ../ include $(TOPDIR)/Makefile.tests -default: sys.o libnachos.o \ No newline at end of file +default: sys.o libnachos.o + +clean: + $(RM) libnachos.o sys.o \ No newline at end of file From e170256c9b9f75cb144f213edda05af0f5c8b0f4 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Mar 2023 19:35:24 +0200 Subject: [PATCH 05/57] Fix build makefiles --- test/Makefile.tests | 15 ++++++++++++--- test/riscv_instructions/.gitignore | 5 +++++ test/riscv_instructions/Makefile | 4 ++-- test/riscv_instructions/boolean_logic/Makefile | 12 +++++++++--- .../jump_instructions/Makefile | 15 ++++++++++++--- .../simple_arithmetics/Makefile | 16 +++++++++++++--- 6 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 test/riscv_instructions/.gitignore diff --git a/test/Makefile.tests b/test/Makefile.tests index 681d31f..14dba3d 100644 --- a/test/Makefile.tests +++ b/test/Makefile.tests @@ -1,5 +1,11 @@ include $(TOPDIR)/Makefile.config + USERLIB = $(TOPDIR)/userlib + +AS = $(RISCV_AS) -c +GCC = $(RISCV_GCC) +LD = $(RISCV_LD) + INCPATH += -I$(TOPDIR) -I$(USERLIB) LDFLAGS = $(RISCV_LDFLAGS) -T $(USERLIB)/ldscript.lds ASFLAGS = $(RISCV_ASFLAGS) $(INCPATH) @@ -7,16 +13,16 @@ CFLAGS = $(RISCV_CFLAGS) $(INCPATH) # Rules %.o: %.s - $(RISCV_AS) $(ASFLAGS) -c $< + $(AS) $(ASFLAGS) -c $< %.o: %.c - $(RISCV_GCC) $(CFLAGS) -c $< + $(GCC) $(CFLAGS) -c $< %.dump: %.o $(RISCV_OBJCOPY) -j .text -O $(DUMP_FORMAT) $< $@ %.guac: %.o - $(RISCV_LD) $(LDFLAGS) $+ -o $@ + $(LD) $(LDFLAGS) $+ -o $@ # Dependencies .%.d: %.s @@ -31,6 +37,9 @@ CFLAGS = $(RISCV_CFLAGS) $(INCPATH) | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \ [ -s $@ ] || rm -f $@' +$(PROGRAMS): + $(LD) $(LDFLAGS) $+ -o $@ + # Targets #clean: # rm -rf *.o 2> /dev/null diff --git a/test/riscv_instructions/.gitignore b/test/riscv_instructions/.gitignore new file mode 100644 index 0000000..140fad6 --- /dev/null +++ b/test/riscv_instructions/.gitignore @@ -0,0 +1,5 @@ +* +!.gitignore +!*.c +!*.md +!**/Makefile \ No newline at end of file diff --git a/test/riscv_instructions/Makefile b/test/riscv_instructions/Makefile index cabd3bb..7c9a691 100644 --- a/test/riscv_instructions/Makefile +++ b/test/riscv_instructions/Makefile @@ -1,7 +1,7 @@ build: make build -C boolean_logic/ -# make build -C jump_instructions/ -# make build -C simple_arithmetics/ + make build -C jump_instructions/ + make build -C simple_arithmetics/ dumps: make dumps -C boolean_logic/ diff --git a/test/riscv_instructions/boolean_logic/Makefile b/test/riscv_instructions/boolean_logic/Makefile index b1f6312..e9b0a52 100644 --- a/test/riscv_instructions/boolean_logic/Makefile +++ b/test/riscv_instructions/boolean_logic/Makefile @@ -1,11 +1,17 @@ -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests -build: comparisons if switch +PROGRAMS = comparisons if switch + +build: $(PROGRAMS) dumps: comparisons.dump if.dump switch.dump tests: comparisons.guac if.guac switch.guac +TOPDIR = ../.. +include $(TOPDIR)/Makefile.tests + +clean: + $(RM) comparisons comparisons.o if if.o + # Dependances $(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/riscv_instructions/jump_instructions/Makefile b/test/riscv_instructions/jump_instructions/Makefile index ce69447..71ce3c0 100644 --- a/test/riscv_instructions/jump_instructions/Makefile +++ b/test/riscv_instructions/jump_instructions/Makefile @@ -1,6 +1,15 @@ -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests +PROGRAMS = jump ret + +build: $(PROGRAMS) dumps: jump.dump ret.dump -tests: jump.guac ret.guac \ No newline at end of file +tests: jump.guac ret.guac + +clean: + $(RM) jump jump.o ret ret.o + +TOPDIR = ../.. +include $(TOPDIR)/Makefile.tests + +$(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/riscv_instructions/simple_arithmetics/Makefile b/test/riscv_instructions/simple_arithmetics/Makefile index 623b297..9b42a4b 100644 --- a/test/riscv_instructions/simple_arithmetics/Makefile +++ b/test/riscv_instructions/simple_arithmetics/Makefile @@ -1,6 +1,16 @@ -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests + +PROGRAMS = unsigned_addition unsigned_division unsigned_multiplication unsigned_substraction + +build: $(PROGRAMS) dumps: unsigned_addition.dump unsigned_division.dump unsigned_multiplication.dump unsigned_substraction.dump -tests: unsigned_addition.guac unsigned_division.guac unsigned_multiplication.guac unsigned_substraction.guac \ No newline at end of file +tests: unsigned_addition.guac unsigned_division.guac unsigned_multiplication.guac unsigned_substraction.guac + +clean: + $(RM) unsigned_addition unsigned_addition.o unsigned_division unsigned_division.o unsigned_multiplication unsigned_multiplication.o unsigned_substraction unsigned_substraction.o + +TOPDIR = ../.. +include $(TOPDIR)/Makefile.tests + +$(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file From cfcdce750bffcde5b7660b3b1af490b132774b09 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Mar 2023 19:47:42 +0200 Subject: [PATCH 06/57] Change filename in thread_manager::test-thread_context --- src/kernel/thread_manager.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 4734b40..07390a6 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -206,20 +206,21 @@ mod test { #[ignore = "Pas encore terminé, contient des bugs"] fn test_thread_context() { let mut machine = Machine::init_machine(); - loader::load("../test.o", &mut machine, 0).expect("IO Error"); + loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + let start_pc = 0x4000; let system = &mut System::default(); let thread1 = Thread::new("th1"); let thread1 = Rc::new(RefCell::new(thread1)); system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, 0x94 as u64, 0); - debug_assert_eq!(thread1.borrow_mut().thread_context.pc, 0x94 as u64); + system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, 0); + debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc); let to_run = system.get_thread_manager().find_next_to_run().unwrap(); debug_assert_eq!(to_run, Rc::clone(&thread1)); debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); 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(&thread1))); - debug_assert_eq!(machine.pc, 0x94); + debug_assert_eq!(machine.pc, start_pc); machine.run(); } From 703c8e5448a92333b18b875178847259e3a17612 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Mar 2023 21:26:58 +0200 Subject: [PATCH 07/57] Loader seem to work, be seem we have a problem with jalr --- src/kernel/thread_manager.rs | 9 +++++++-- src/simulator/loader.rs | 4 ++-- src/simulator/machine.rs | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 07390a6..e88cf59 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -207,20 +207,25 @@ mod test { fn test_thread_context() { let mut machine = Machine::init_machine(); loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); - let start_pc = 0x4000; + let start_pc = 0x1000; let system = &mut System::default(); + let thread1 = Thread::new("th1"); let thread1 = Rc::new(RefCell::new(thread1)); system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); + let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, 0); + system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, -1); debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc); + let to_run = system.get_thread_manager().find_next_to_run().unwrap(); debug_assert_eq!(to_run, Rc::clone(&thread1)); debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); + 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(&thread1))); debug_assert_eq!(machine.pc, start_pc); + machine.run(); } diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 3404128..4ed2b64 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -59,7 +59,7 @@ pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result<(), for i in 0..instructions.len() { machine.write_memory(4, 4 * i + start_index, instructions[i] as u64); } - #[cfg(debug_assertions)] - println!("{:04x?}", instructions); // only print loaded program in debug build + // #[cfg(debug_assertions)] + // println!("{:04x?}", instructions); // only print loaded program in debug build Ok(()) } \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 0d9619b..1a8775a 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -240,7 +240,7 @@ impl Machine { let val = u32::from_be_bytes(val) as u64; let inst : Instruction = decode(val); self.print_status(); - println!("executing instruction : {:016x} at pc {:x}", val, self.pc); + println!("executing instruction : {:016x} at pc 0x{:x}", val, self.pc); println!("{}", print::print(decode(val), self.pc as i32)); let trace = Self::string_registers(self); self.registers_trace.push_str(format!("{}\n", trace).as_str()); From b4b7eb69c27414e944e77f3fd3bf34d9c0285433 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 31 Mar 2023 15:18:58 +0200 Subject: [PATCH 08/57] Add elf header parsing --- src/simulator/loader.rs | 198 ++++++++++++++++++++++++++++++++++------ 1 file changed, 168 insertions(+), 30 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 4ed2b64..2f8a292 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -1,40 +1,11 @@ use crate::Machine; +use std::f32::consts::E; use std::fs; use std::io; use std::io::BufRead; use std::io::Read; - - - /// Load a file into a new machine - /// - /// `panic!` when size is not 1, 2, 4 or 8 - /// `panic!` when the text does not represents instructions in hexadecimal - /// - /// ### Parameters - /// - /// - **path** the path of the file to load - /// - **size** the number of bytes to write (1, 2, 4 or 8) -#[deprecated] -pub fn _load(path : &str, instruction_size: i32) -> Machine { - let file = fs::File::open(path).expect("Wrong filename"); - let reader = io::BufReader::new(file); - let mut machine = Machine::init_machine(); - - for (i,line) in reader.lines().enumerate() { - let res = u64::from_str_radix(&line.unwrap(), 16); - match res { - Ok(value) => { - Machine::write_memory(&mut machine, instruction_size, i*instruction_size as usize, value); - }, - _ => panic!() - } - } - println!("{:x}", Machine::read_memory(& mut machine, 4, 0)); - machine -} - /// load a 32-bits binary file into the machine /// /// ### Parameters @@ -62,4 +33,171 @@ pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result<(), // #[cfg(debug_assertions)] // println!("{:04x?}", instructions); // only print loaded program in debug build Ok(()) +} + +struct Loader { + bytes: Vec +} + +impl Loader { + + pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result { + let mut file = fs::File::open(path)?; + let mut instructions: Vec = Default::default(); + loop { + let mut buf: [u8; 1] = [0; 1]; + let res = file.read(&mut buf)?; + if res == 0 { + break; // eof + } else { + instructions.push(buf[0]); + } + } + // #[cfg(debug_assertions)] + // println!("{:04x?}", instructions); // only print loaded program in debug build + Ok(Self { bytes: instructions }) + } + + fn parse(&mut self) -> Result<(), ()> { + todo!(); + Ok(()) + } + + /// return true if the 4 first bytes constitude the elf magic number + fn is_elf(&self) -> bool { + self.bytes.get(0..4) == Option::Some(&[0x7f, 0x45, 0x4c, 0x46]) + } + + /// return true if big endian, false otherwise + fn check_endianess(&self) -> bool { + self.bytes.get(5) == Option::Some(&2) + } + + /// return true if file is 32 bits, false if 64 bits + fn is_32bits(&self) -> bool { + self.bytes.get(4) == Option::Some(&1) + } + + /// return the version of the elf file (should be 1) + /// Can be None if the file is smaller than 7 bytes -> the file is invalid + fn get_version(&self) -> Option { + self.bytes.get(6).copied() // work as primitives implements Copy + } + + /// return true if target abi of the binary file is System V, false otherwise + fn is_system_v_elf(&self) -> bool{ + self.bytes.get(7) == Option::Some(&0) + } + + /// return true if specified target instruction set architecture is RISCV + fn is_riscv_isa(&self) -> bool { + self.bytes.get(0x12) == Option::Some(&0xf7) + } + + /// memory address of the entry point from where the process starts its execution + fn get_entrypoint(&self, is_32bits: bool) -> Option { + if is_32bits { + self.get_address_point(0x18, true) + } else { + self.get_address_point(0x18, false) + } + } + + /// Memory address of the start of the program header table + fn get_program_header_table_location(&self, is_32bits: bool) -> Option { + if is_32bits { + self.get_address_point(0x1c, true) + } else { + self.get_address_point(0x20, false) + } + } + + /// Memory address of the start of the section header table + fn get_section_header_table_location(&self, is_32bits: bool) -> Option { + if is_32bits { + self.get_address_point(0x20, true) + } else { + self.get_address_point(0x28, false) + } + } + + /// Return the size of the header, normally, 0x40 for 64 bits bin and 0x34 for 32 bits + fn get_elf_header_size(&self, is_32bits: bool) -> Option { + let address = if is_32bits { 0x28 } else { 0x34 }; + self.get_u16_value(address) + } + + /// return the size of the program header + fn get_program_header_size(&self, is_32bits: bool) -> Option { + let address = if is_32bits { 0x2a } else { 0x34 }; + self.get_u16_value(address) + } + + /// return the number of entries in the program header + fn get_number_entries_program_header(&self, is_32bits: bool) -> Option { + let address = if is_32bits { 0x2c } else { 0x38 }; + self.get_u16_value(address) + } + + /// Return the size of the section header + fn get_section_header_size(&self, is_32bits: bool) -> Option { + let address = if is_32bits { 0x2e } else { 0x3a }; + self.get_u16_value(address) + } + + /// Return the number of entries in the section header + fn get_section_header_num_entries(&self, is_32bits: bool) -> Option { + let address = if is_32bits { 0x30 } else { 0x3c }; + self.get_u16_value(address) + } + + /// Return a u16 value, usually for the size or the number of entries inside a header + fn get_u16_value(&self, address: usize) -> Option { + let mut bytes: [u8; 2] = [0; 2]; + bytes[0] = self.bytes.get(address).copied()?; + bytes[1] = self.bytes.get(address + 1).copied()?; + Option::Some(u16::from_le_bytes(bytes)) + } + + /// return the memory address of something stored at address + /// Can return None if the file is smaller than adress + 4 (or 7 if 64 bits), in this case, the elf header is incorrect + fn get_address_point(&self, address: usize, is_32bits: bool) -> Option { + if is_32bits { + let mut bytes: [u8; 4] = [0; 4]; + bytes[0] = self.bytes.get(address).copied()?; + bytes[0] = self.bytes.get(address + 1).copied()?; + bytes[0] = self.bytes.get(address + 2).copied()?; + bytes[0] = self.bytes.get(address + 3).copied()?; + Option::Some(u32::from_le_bytes(bytes) as u64) + } else { + let mut bytes: [u8; 8] = [0; 8]; + bytes[0] = self.bytes.get(address).copied()?; + bytes[0] = self.bytes.get(address + 1).copied()?; + bytes[0] = self.bytes.get(address + 2).copied()?; + bytes[0] = self.bytes.get(address + 3).copied()?; + bytes[0] = self.bytes.get(address + 4).copied()?; + bytes[0] = self.bytes.get(address + 5).copied()?; + bytes[0] = self.bytes.get(address + 6).copied()?; + bytes[0] = self.bytes.get(address + 7).copied()?; + Option::Some(u64::from_le_bytes(bytes)) + } + } + + +} + +#[cfg(test)] +mod test { + use crate::simulator::{loader::Loader, machine::Machine}; + + + #[test] + fn test_parse() { + let mut machine = Machine::init_machine(); + let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + assert_eq!(true, loader.is_elf()); + assert_eq!(false, loader.is_32bits()); + assert_eq!(false, loader.check_endianess()); + } + } \ No newline at end of file From 453de4b704ea2dda6cc02cfa5f991e70e9945130 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 31 Mar 2023 15:34:04 +0200 Subject: [PATCH 09/57] Fix is_riscv_isa --- src/simulator/loader.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 2f8a292..904bc87 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -91,7 +91,7 @@ impl Loader { /// return true if specified target instruction set architecture is RISCV fn is_riscv_isa(&self) -> bool { - self.bytes.get(0x12) == Option::Some(&0xf7) + self.get_u16_value(0x12) == Option::Some(0xf3) } /// memory address of the entry point from where the process starts its execution @@ -198,6 +198,9 @@ mod test { assert_eq!(true, loader.is_elf()); assert_eq!(false, loader.is_32bits()); assert_eq!(false, loader.check_endianess()); + assert_eq!(true, loader.is_system_v_elf()); + assert_eq!(true, loader.is_riscv_isa()); + assert_eq!(Option::Some(1), loader.get_version()); } } \ No newline at end of file From 35c81e5269afa4f3203d1fe9f9dcf6f5c193a528 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 31 Mar 2023 19:34:45 +0200 Subject: [PATCH 10/57] Fix get_address_point --- src/simulator/loader.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 904bc87..2eac03c 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -160,25 +160,25 @@ impl Loader { } /// return the memory address of something stored at address - /// Can return None if the file is smaller than adress + 4 (or 7 if 64 bits), in this case, the elf header is incorrect + /// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect fn get_address_point(&self, address: usize, is_32bits: bool) -> Option { if is_32bits { let mut bytes: [u8; 4] = [0; 4]; bytes[0] = self.bytes.get(address).copied()?; - bytes[0] = self.bytes.get(address + 1).copied()?; - bytes[0] = self.bytes.get(address + 2).copied()?; - bytes[0] = self.bytes.get(address + 3).copied()?; + bytes[1] = self.bytes.get(address + 1).copied()?; + bytes[2] = self.bytes.get(address + 2).copied()?; + bytes[3] = self.bytes.get(address + 3).copied()?; Option::Some(u32::from_le_bytes(bytes) as u64) } else { let mut bytes: [u8; 8] = [0; 8]; bytes[0] = self.bytes.get(address).copied()?; - bytes[0] = self.bytes.get(address + 1).copied()?; - bytes[0] = self.bytes.get(address + 2).copied()?; - bytes[0] = self.bytes.get(address + 3).copied()?; - bytes[0] = self.bytes.get(address + 4).copied()?; - bytes[0] = self.bytes.get(address + 5).copied()?; - bytes[0] = self.bytes.get(address + 6).copied()?; - bytes[0] = self.bytes.get(address + 7).copied()?; + bytes[1] = self.bytes.get(address + 1).copied()?; + bytes[2] = self.bytes.get(address + 2).copied()?; + bytes[3] = self.bytes.get(address + 3).copied()?; + bytes[4] = self.bytes.get(address + 4).copied()?; + bytes[5] = self.bytes.get(address + 5).copied()?; + bytes[6] = self.bytes.get(address + 6).copied()?; + bytes[7] = self.bytes.get(address + 7).copied()?; Option::Some(u64::from_le_bytes(bytes)) } } @@ -201,6 +201,9 @@ mod test { assert_eq!(true, loader.is_system_v_elf()); assert_eq!(true, loader.is_riscv_isa()); assert_eq!(Option::Some(1), loader.get_version()); + assert_eq!(Option::Some(0x4000), loader.get_entrypoint(false)); + assert_eq!(Option::Some(64), loader.get_program_header_table_location(false)); + assert_eq!(Option::Some(18984), loader.get_section_header_table_location(false)); } } \ No newline at end of file From 443556b18a4753a99822cf1beb0661784a7be367 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 31 Mar 2023 21:49:26 +0200 Subject: [PATCH 11/57] Refactor loader into multiple struct --- src/simulator/loader.rs | 321 ++++++++++++++++++++++++++++------------ 1 file changed, 224 insertions(+), 97 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 2eac03c..1a968c8 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -1,9 +1,6 @@ use crate::Machine; - -use std::f32::consts::E; +use std::fmt::Error; use std::fs; -use std::io; -use std::io::BufRead; use std::io::Read; /// load a 32-bits binary file into the machine @@ -35,154 +32,279 @@ pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result<(), Ok(()) } -struct Loader { - bytes: Vec +pub struct ElfHeader { + pub endianess: bool, + pub is_32bits: bool, + pub version: u8, + pub sys_v_abi: bool, + pub is_riscv_target: bool, + pub entrypoint: u64, + pub elf_header_size: u16, + pub program_header_location: u64, + pub program_header_entries: u16, + pub program_header_size: u16, + pub section_header_location: u64, + pub section_header_entries: u16, + pub section_header_size: u16, } -impl Loader { - - pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result { - let mut file = fs::File::open(path)?; - let mut instructions: Vec = Default::default(); - loop { - let mut buf: [u8; 1] = [0; 1]; - let res = file.read(&mut buf)?; - if res == 0 { - break; // eof - } else { - instructions.push(buf[0]); - } - } - // #[cfg(debug_assertions)] - // println!("{:04x?}", instructions); // only print loaded program in debug build - Ok(Self { bytes: instructions }) - } - - fn parse(&mut self) -> Result<(), ()> { - todo!(); - Ok(()) - } - +impl ElfHeader { + /// return true if the 4 first bytes constitude the elf magic number - fn is_elf(&self) -> bool { - self.bytes.get(0..4) == Option::Some(&[0x7f, 0x45, 0x4c, 0x46]) + fn is_elf(instructions: &Vec) -> bool { + instructions.get(0..4) == Option::Some(&[0x7f, 0x45, 0x4c, 0x46]) } /// return true if big endian, false otherwise - fn check_endianess(&self) -> bool { - self.bytes.get(5) == Option::Some(&2) + fn check_endianess(instructions: &Vec) -> bool { + instructions.get(5) == Option::Some(&2) } /// return true if file is 32 bits, false if 64 bits - fn is_32bits(&self) -> bool { - self.bytes.get(4) == Option::Some(&1) + fn is_32bits(instructions: &Vec) -> bool { + instructions.get(4) == Option::Some(&1) } /// return the version of the elf file (should be 1) /// Can be None if the file is smaller than 7 bytes -> the file is invalid - fn get_version(&self) -> Option { - self.bytes.get(6).copied() // work as primitives implements Copy + fn get_version(instructions: &Vec) -> Option { + instructions.get(6).copied() // work as primitives implements Copy } /// return true if target abi of the binary file is System V, false otherwise - fn is_system_v_elf(&self) -> bool{ - self.bytes.get(7) == Option::Some(&0) + fn is_system_v_elf(instructions: &Vec) -> bool { + instructions.get(7) == Option::Some(&0) } /// return true if specified target instruction set architecture is RISCV - fn is_riscv_isa(&self) -> bool { - self.get_u16_value(0x12) == Option::Some(0xf3) + fn is_riscv_isa(instructions: &Vec) -> bool { + Self::get_u16_value(instructions, 0x12) == Option::Some(0xf3) } /// memory address of the entry point from where the process starts its execution - fn get_entrypoint(&self, is_32bits: bool) -> Option { + fn get_entrypoint(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - self.get_address_point(0x18, true) + Self::get_address_point(instructions, 0x18, true) } else { - self.get_address_point(0x18, false) + Self::get_address_point(instructions, 0x18, false) } } /// Memory address of the start of the program header table - fn get_program_header_table_location(&self, is_32bits: bool) -> Option { + fn get_program_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - self.get_address_point(0x1c, true) + Self::get_address_point(instructions, 0x1c, true) } else { - self.get_address_point(0x20, false) + Self::get_address_point(instructions, 0x20, false) } } /// Memory address of the start of the section header table - fn get_section_header_table_location(&self, is_32bits: bool) -> Option { + fn get_section_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - self.get_address_point(0x20, true) + Self::get_address_point(instructions, 0x20, true) } else { - self.get_address_point(0x28, false) + Self::get_address_point(instructions, 0x28, false) } } /// Return the size of the header, normally, 0x40 for 64 bits bin and 0x34 for 32 bits - fn get_elf_header_size(&self, is_32bits: bool) -> Option { + fn get_elf_header_size(instructions: &Vec, is_32bits: bool) -> Option { let address = if is_32bits { 0x28 } else { 0x34 }; - self.get_u16_value(address) + Self::get_u16_value(instructions, address) } - /// return the size of the program header - fn get_program_header_size(&self, is_32bits: bool) -> Option { - let address = if is_32bits { 0x2a } else { 0x34 }; - self.get_u16_value(address) + /// return the size of a program header table entry + fn get_program_header_size(instructions: &Vec, is_32bits: bool) -> Option { + let address = if is_32bits { 0x2a } else { 0x36 }; + Self::get_u16_value(instructions, address) } /// return the number of entries in the program header - fn get_number_entries_program_header(&self, is_32bits: bool) -> Option { + fn get_number_entries_program_header(instructions: &Vec, is_32bits: bool) -> Option { let address = if is_32bits { 0x2c } else { 0x38 }; - self.get_u16_value(address) + Self::get_u16_value(instructions, address) } - /// Return the size of the section header - fn get_section_header_size(&self, is_32bits: bool) -> Option { + /// Return the size of a section header table entry + fn get_section_header_size(instructions: &Vec, is_32bits: bool) -> Option { let address = if is_32bits { 0x2e } else { 0x3a }; - self.get_u16_value(address) + Self::get_u16_value(instructions, address) } /// Return the number of entries in the section header - fn get_section_header_num_entries(&self, is_32bits: bool) -> Option { + fn get_section_header_num_entries(instructions: &Vec, is_32bits: bool) -> Option { let address = if is_32bits { 0x30 } else { 0x3c }; - self.get_u16_value(address) - } - - /// Return a u16 value, usually for the size or the number of entries inside a header - fn get_u16_value(&self, address: usize) -> Option { - let mut bytes: [u8; 2] = [0; 2]; - bytes[0] = self.bytes.get(address).copied()?; - bytes[1] = self.bytes.get(address + 1).copied()?; - Option::Some(u16::from_le_bytes(bytes)) + Self::get_u16_value(instructions, address) } /// return the memory address of something stored at address /// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect - fn get_address_point(&self, address: usize, is_32bits: bool) -> Option { + fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { if is_32bits { let mut bytes: [u8; 4] = [0; 4]; - bytes[0] = self.bytes.get(address).copied()?; - bytes[1] = self.bytes.get(address + 1).copied()?; - bytes[2] = self.bytes.get(address + 2).copied()?; - bytes[3] = self.bytes.get(address + 3).copied()?; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; Option::Some(u32::from_le_bytes(bytes) as u64) } else { let mut bytes: [u8; 8] = [0; 8]; - bytes[0] = self.bytes.get(address).copied()?; - bytes[1] = self.bytes.get(address + 1).copied()?; - bytes[2] = self.bytes.get(address + 2).copied()?; - bytes[3] = self.bytes.get(address + 3).copied()?; - bytes[4] = self.bytes.get(address + 4).copied()?; - bytes[5] = self.bytes.get(address + 5).copied()?; - bytes[6] = self.bytes.get(address + 6).copied()?; - bytes[7] = self.bytes.get(address + 7).copied()?; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; + bytes[4] = instructions.get(address + 4).copied()?; + bytes[5] = instructions.get(address + 5).copied()?; + bytes[6] = instructions.get(address + 6).copied()?; + bytes[7] = instructions.get(address + 7).copied()?; Option::Some(u64::from_le_bytes(bytes)) } } + /// Return a u16 value, usually for the size or the number of entries inside a header + fn get_u16_value(instructions: &Vec, address: usize) -> Option { + let mut bytes: [u8; 2] = [0; 2]; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + Option::Some(u16::from_le_bytes(bytes)) + } + +} + +impl TryFrom<&Vec> for ElfHeader { + type Error = (); + + fn try_from(instructions: &Vec) -> Result { + 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 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(())?; + Ok(ElfHeader { + endianess, + is_32bits: format, + version, + sys_v_abi: is_sys_v_abi, + is_riscv_target: is_rv_target, + entrypoint, + elf_header_size, + program_header_location, + program_header_entries, + program_header_size, + section_header_location, + section_header_entries, + section_header_size + }) + } else { + Err(()) + } + } +} + +pub struct SectionHeader { + pub name_offset: u32, + pub header_type: u32, + pub attribute: u64, + pub virt_addr: u64, + pub image_offset: u64, + pub section_size: u64, + pub section_index: u32, + pub section_info: u32, + pub required_align: u64, + pub entry_size: u64 +} + +impl TryFrom<(&Vec, u64)> for SectionHeader { + type Error = (); + + fn try_from(value: (&Vec, u64)) -> Result { + todo!() + } +} + +pub struct Loader { + bytes: Vec, + pub elf_header: ElfHeader, + pub sections: Vec +} + +pub enum LoaderError { + IOError(std::io::Error), + ParsingError +} + +impl Loader { + + pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result { + let file = fs::File::open(path); + match file { + Ok(mut file) => { + let mut instructions: Vec = Default::default(); + loop { + let mut buf: [u8; 1] = [0; 1]; + let res = file.read(&mut buf); + match res { + Ok(res) => { + if res == 0 { + break; // eof + } else { + instructions.push(buf[0]); + } + }, + Err(err) => { + return Err(LoaderError::IOError(err)) + } + } + + } + let elf_header = match ElfHeader::try_from(&instructions) { + Ok(header) => { + header + }, + Err(_) => { + return Err(LoaderError::ParsingError); + } + }; + 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) { + Ok(header) => { + header + }, + Err(_) => { + return Err(LoaderError::ParsingError); + } + }; + // #[cfg(debug_assertions)] + // println!("{:04x?}", instructions); // only print loaded program in debug build + return Ok(Self { bytes: instructions, elf_header, sections: section_header }); + }, + Err(err) => { + return Err(LoaderError::IOError(err)); + } + }; + } + + fn parse_section_header(instructions: &Vec, is_32bits: bool, header_location: u64, num_of_entries: u16, entry_size: u16) -> Result, ()> { + let mut sections: Vec = Default::default(); + for i in 0..num_of_entries as u64 { + sections.push(Self::parse_section_entry(instructions, is_32bits, header_location + i * entry_size as u64)?); + } + Ok(sections) + } + + fn parse_section_entry(instructions: &Vec, is_32bits: bool, location: u64) -> Result { + SectionHeader::try_from((instructions, location)) + } + } @@ -192,18 +314,23 @@ mod test { #[test] - fn test_parse() { - let mut machine = Machine::init_machine(); - let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); - assert_eq!(true, loader.is_elf()); - assert_eq!(false, loader.is_32bits()); - assert_eq!(false, loader.check_endianess()); - assert_eq!(true, loader.is_system_v_elf()); - assert_eq!(true, loader.is_riscv_isa()); - assert_eq!(Option::Some(1), loader.get_version()); - assert_eq!(Option::Some(0x4000), loader.get_entrypoint(false)); - assert_eq!(Option::Some(64), loader.get_program_header_table_location(false)); - assert_eq!(Option::Some(18984), loader.get_section_header_table_location(false)); + fn test_parse_elf() { + // let mut machine = Machine::init_machine(); + // let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + // assert_eq!(true, loader.is_elf()); + // assert_eq!(false, loader.is_32bits()); + // assert_eq!(false, loader.check_endianess()); + // assert_eq!(true, loader.is_system_v_elf()); + // assert_eq!(true, loader.is_riscv_isa()); + // assert_eq!(Option::Some(1), loader.get_version()); + // assert_eq!(Option::Some(0x4000), loader.get_entrypoint(false)); + // assert_eq!(Option::Some(64), loader.get_elf_header_size(false)); + // assert_eq!(Option::Some(64), loader.get_program_header_table_location(false)); + // assert_eq!(Option::Some(18984), loader.get_section_header_table_location(false)); + // assert_eq!(Option::Some(56), loader.get_program_header_size(false)); + // assert_eq!(Option::Some(64), loader.get_section_header_size(false)); + // assert_eq!(Option::Some(4), loader.get_number_entries_program_header(false)); + // assert_eq!(Option::Some(9), loader.get_section_header_num_entries(false)); } } \ No newline at end of file From 0a744f0f94f0250cdd74f2ca29c8c054b97b4e95 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 31 Mar 2023 22:48:02 +0200 Subject: [PATCH 12/57] Add parsing of sections --- src/simulator/loader.rs | 174 ++++++++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 51 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 1a968c8..cf77546 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -84,27 +84,27 @@ impl ElfHeader { /// memory address of the entry point from where the process starts its execution fn get_entrypoint(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x18, true) + get_address_point(instructions, 0x18, true) } else { - Self::get_address_point(instructions, 0x18, false) + get_address_point(instructions, 0x18, false) } } /// Memory address of the start of the program header table fn get_program_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x1c, true) + get_address_point(instructions, 0x1c, true) } else { - Self::get_address_point(instructions, 0x20, false) + get_address_point(instructions, 0x20, false) } } /// Memory address of the start of the section header table fn get_section_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { if is_32bits { - Self::get_address_point(instructions, 0x20, true) + get_address_point(instructions, 0x20, true) } else { - Self::get_address_point(instructions, 0x28, false) + get_address_point(instructions, 0x28, false) } } @@ -138,30 +138,6 @@ impl ElfHeader { Self::get_u16_value(instructions, address) } - /// return the memory address of something stored at address - /// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect - fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { - if is_32bits { - let mut bytes: [u8; 4] = [0; 4]; - bytes[0] = instructions.get(address).copied()?; - bytes[1] = instructions.get(address + 1).copied()?; - bytes[2] = instructions.get(address + 2).copied()?; - bytes[3] = instructions.get(address + 3).copied()?; - Option::Some(u32::from_le_bytes(bytes) as u64) - } else { - let mut bytes: [u8; 8] = [0; 8]; - bytes[0] = instructions.get(address).copied()?; - bytes[1] = instructions.get(address + 1).copied()?; - bytes[2] = instructions.get(address + 2).copied()?; - bytes[3] = instructions.get(address + 3).copied()?; - bytes[4] = instructions.get(address + 4).copied()?; - bytes[5] = instructions.get(address + 5).copied()?; - bytes[6] = instructions.get(address + 6).copied()?; - bytes[7] = instructions.get(address + 7).copied()?; - Option::Some(u64::from_le_bytes(bytes)) - } - } - /// Return a u16 value, usually for the size or the number of entries inside a header fn get_u16_value(instructions: &Vec, address: usize) -> Option { let mut bytes: [u8; 2] = [0; 2]; @@ -211,6 +187,7 @@ impl TryFrom<&Vec> for ElfHeader { } } +#[derive(Debug)] pub struct SectionHeader { pub name_offset: u32, pub header_type: u32, @@ -218,17 +195,86 @@ pub struct SectionHeader { pub virt_addr: u64, pub image_offset: u64, pub section_size: u64, - pub section_index: u32, + pub section_link: u32, pub section_info: u32, pub required_align: u64, pub entry_size: u64 } -impl TryFrom<(&Vec, u64)> for SectionHeader { +impl SectionHeader { + + fn get_name_offset(instructions: &Vec, address: usize) -> Option { + get_address_point(instructions, address, true).map(|v| { v as u32 }) + // set true to return a u32 + } + + fn get_header_type(instructions: &Vec, address: usize) -> Option { + get_address_point(instructions, address + 0x4, true).map(|v| { v as u32 }) + } + + fn get_attribute(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + 0x8, is_32bits) + } + + fn get_virtual_address(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x0C } else { 0x10 }, is_32bits) + } + + fn get_image_offset(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x10 } else { 0x18 }, is_32bits) + } + + fn get_section_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x14 } else { 0x20 }, is_32bits) + } + + fn get_section_link(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x18 } else { 0x28 }, false).map(|v| { v as u32 }) + } + + fn get_section_info(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x1C } else { 0x2C }, false).map(|v| { v as u32 }) + } + + fn get_required_align(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x20 } else { 0x30 }, is_32bits) + } + + fn get_entry_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + get_address_point(instructions, address + if is_32bits { 0x24 } else { 0x38 }, is_32bits) + } + +} + +impl TryFrom<(&Vec, u64, bool)> for SectionHeader { type Error = (); - fn try_from(value: (&Vec, u64)) -> Result { - todo!() + fn try_from(value: (&Vec, u64, bool)) -> Result { + let instructions = value.0; + let address = value.1 as usize; + let is_32bits = value.2; + + let name_offset = Self::get_name_offset(instructions, address).ok_or(())?; + let header_type = Self::get_header_type(instructions, address).ok_or(())?; + let attribute = Self::get_attribute(instructions, address, is_32bits).ok_or(())?; + let virt_addr = Self::get_virtual_address(instructions, address, is_32bits).ok_or(())?; + let image_offset = Self::get_image_offset(instructions, address, is_32bits).ok_or(())?; + let section_size = Self::get_section_size(instructions, address, is_32bits).ok_or(())?; + let section_link = Self::get_section_link(instructions, address, is_32bits).ok_or(())?; + let section_info = Self::get_section_info(instructions, address, is_32bits).ok_or(())?; + let required_align = Self::get_required_align(instructions, address, is_32bits).ok_or(())?; + let entry_size = Self::get_entry_size(instructions, address, is_32bits).ok_or(())?; + Ok(Self { name_offset, + header_type, + attribute, + virt_addr, + image_offset, + section_size, + section_link, + section_info, + required_align, + entry_size + }) } } @@ -238,6 +284,7 @@ pub struct Loader { pub sections: Vec } +#[derive(Debug)] pub enum LoaderError { IOError(std::io::Error), ParsingError @@ -302,35 +349,60 @@ impl Loader { } fn parse_section_entry(instructions: &Vec, is_32bits: bool, location: u64) -> Result { - SectionHeader::try_from((instructions, location)) + SectionHeader::try_from((instructions, location, is_32bits)) } } +/// return the memory address of something stored at address +/// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect +fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + if is_32bits { + let mut bytes: [u8; 4] = [0; 4]; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; + Option::Some(u32::from_le_bytes(bytes) as u64) + } else { + let mut bytes: [u8; 8] = [0; 8]; + bytes[0] = instructions.get(address).copied()?; + bytes[1] = instructions.get(address + 1).copied()?; + bytes[2] = instructions.get(address + 2).copied()?; + bytes[3] = instructions.get(address + 3).copied()?; + bytes[4] = instructions.get(address + 4).copied()?; + bytes[5] = instructions.get(address + 5).copied()?; + bytes[6] = instructions.get(address + 6).copied()?; + bytes[7] = instructions.get(address + 7).copied()?; + Option::Some(u64::from_le_bytes(bytes)) + } +} + #[cfg(test)] mod test { use crate::simulator::{loader::Loader, machine::Machine}; #[test] + #[ignore = "CI gitlab a modifié"] fn test_parse_elf() { - // let mut machine = Machine::init_machine(); - // let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); - // assert_eq!(true, loader.is_elf()); - // assert_eq!(false, loader.is_32bits()); - // assert_eq!(false, loader.check_endianess()); - // assert_eq!(true, loader.is_system_v_elf()); - // assert_eq!(true, loader.is_riscv_isa()); - // assert_eq!(Option::Some(1), loader.get_version()); - // assert_eq!(Option::Some(0x4000), loader.get_entrypoint(false)); - // assert_eq!(Option::Some(64), loader.get_elf_header_size(false)); - // assert_eq!(Option::Some(64), loader.get_program_header_table_location(false)); - // assert_eq!(Option::Some(18984), loader.get_section_header_table_location(false)); - // assert_eq!(Option::Some(56), loader.get_program_header_size(false)); - // assert_eq!(Option::Some(64), loader.get_section_header_size(false)); - // assert_eq!(Option::Some(4), loader.get_number_entries_program_header(false)); - // assert_eq!(Option::Some(9), loader.get_section_header_num_entries(false)); + let mut machine = Machine::init_machine(); + let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + assert_eq!(false, loader.elf_header.is_32bits); + assert_eq!(false, loader.elf_header.endianess); + assert_eq!(true, loader.elf_header.sys_v_abi); + assert_eq!(true, loader.elf_header.is_riscv_target); + assert_eq!(1, loader.elf_header.version); + assert_eq!(0x4000, loader.elf_header.entrypoint); + assert_eq!(64, loader.elf_header.elf_header_size); + assert_eq!(64, loader.elf_header.program_header_location); + assert_eq!(18984, loader.elf_header.section_header_location); + assert_eq!(56, loader.elf_header.program_header_size); + assert_eq!(64, loader.elf_header.section_header_size); + assert_eq!(4, loader.elf_header.program_header_entries); + assert_eq!(9, loader.elf_header.section_header_entries); + println!("{:#x?}", loader.sections); } } \ No newline at end of file From 8239079130c174e029a02df4b335b709bdfa93e0 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Sat, 1 Apr 2023 00:14:09 +0200 Subject: [PATCH 13/57] Add section flag support, loader now ready to run binary files --- src/kernel/thread_manager.rs | 4 +-- src/simulator/loader.rs | 53 ++++++++++++++++++++++++++++++++---- src/simulator/machine.rs | 4 +-- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index e88cf59..acecc5b 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -206,8 +206,8 @@ mod test { #[ignore = "Pas encore terminé, contient des bugs"] fn test_thread_context() { let mut machine = Machine::init_machine(); - loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); - let start_pc = 0x1000; + let loader = loader::Loader::new("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + let start_pc = loader.elf_header.entrypoint; let system = &mut System::default(); let thread1 = Thread::new("th1"); diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index cf77546..9bbe132 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -187,11 +187,22 @@ impl TryFrom<&Vec> for ElfHeader { } } + +pub enum FlagValue { + ShfWrite = 0x1, + ShfAlloc = 0x2, + ShfExecinstr = 0x4, + ShfMerge = 0x10, + ShfStrings = 0x20, + ShfInfoLink = 0x40, + ShfLinkOrder = 0x80, + // There is others but are unrelevant (I think) +} #[derive(Debug)] pub struct SectionHeader { pub name_offset: u32, pub header_type: u32, - pub attribute: u64, + pub flags: u64, pub virt_addr: u64, pub image_offset: u64, pub section_size: u64, @@ -203,6 +214,11 @@ pub struct SectionHeader { impl SectionHeader { + /// return true if flag of this section contains / have `key`, false otherwise + pub fn does_flag_contains_key(&self, key: FlagValue) -> bool { + self.flags & key as u64 != 0 + } + fn get_name_offset(instructions: &Vec, address: usize) -> Option { get_address_point(instructions, address, true).map(|v| { v as u32 }) // set true to return a u32 @@ -212,7 +228,7 @@ impl SectionHeader { get_address_point(instructions, address + 0x4, true).map(|v| { v as u32 }) } - fn get_attribute(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + fn get_flags(instructions: &Vec, address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + 0x8, is_32bits) } @@ -256,7 +272,7 @@ impl TryFrom<(&Vec, u64, bool)> for SectionHeader { let name_offset = Self::get_name_offset(instructions, address).ok_or(())?; let header_type = Self::get_header_type(instructions, address).ok_or(())?; - let attribute = Self::get_attribute(instructions, address, is_32bits).ok_or(())?; + let attribute = Self::get_flags(instructions, address, is_32bits).ok_or(())?; let virt_addr = Self::get_virtual_address(instructions, address, is_32bits).ok_or(())?; let image_offset = Self::get_image_offset(instructions, address, is_32bits).ok_or(())?; let section_size = Self::get_section_size(instructions, address, is_32bits).ok_or(())?; @@ -266,7 +282,7 @@ impl TryFrom<(&Vec, u64, bool)> for SectionHeader { let entry_size = Self::get_entry_size(instructions, address, is_32bits).ok_or(())?; Ok(Self { name_offset, header_type, - attribute, + flags: attribute, virt_addr, image_offset, section_size, @@ -292,7 +308,31 @@ pub enum LoaderError { impl Loader { - pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result { + pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result { + let loader = Self::load_and_parse(path)?; + loader.load_into_machine(machine, start_index)?; + Ok(loader) + } + + fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result{ + for i in 0..self.sections.len() { + let section = &self.sections[i]; + if section.does_flag_contains_key(FlagValue::ShfAlloc) { + // Can allocate to machine memory + for j in (0..section.section_size as usize).step_by(4) { + let mut buf: [u8; 4] = [0; 4]; + for k in 0..4 { + buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError)?; + } + machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64); + } + } + } + let last = self.sections.last().ok_or(LoaderError::ParsingError)?; + Ok(start_index as u64 + last.virt_addr + last.section_size) + } + + fn load_and_parse(path: &str) -> Result { let file = fs::File::open(path); match file { Ok(mut file) => { @@ -388,7 +428,8 @@ mod test { #[ignore = "CI gitlab a modifié"] fn test_parse_elf() { let mut machine = Machine::init_machine(); - let loader = Loader::load("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + let loader = Loader::load_and_parse("./test/riscv_instructions/simple_arithmetics/unsigned_addition").expect("IO Error"); + loader.load_into_machine(&mut machine, 0).expect("Parsing error"); assert_eq!(false, loader.elf_header.is_32bits); assert_eq!(false, loader.elf_header.endianess); assert_eq!(true, loader.elf_header.sys_v_abi); diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 1a8775a..1ab9087 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -188,9 +188,9 @@ impl Machine { } println!("________________SP________________"); let sp_index = self.int_reg.get_reg(2); - for i in 0..5 { + /* for i in 0..5 { println!("SP+{:<2} : {:16x}", i*8, self.read_memory(8, (sp_index + i*8) as usize)); - } + } */ println!("##################################"); } From 8c844c3e5cbea14c0e320ac21457df602d10b678 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Sun, 2 Apr 2023 19:55:06 +0200 Subject: [PATCH 14/57] Initialize sp value for each threads (temporary workaround) --- src/kernel/thread.rs | 4 ++-- src/kernel/thread_manager.rs | 8 ++++---- src/simulator/loader.rs | 13 +++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 05d94ad..4b856c2 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -47,10 +47,10 @@ impl Thread { } } - pub fn init_thread_context(&mut self, initial_pc_reg: u64, initial_sp: i64, arg: i64) { + pub fn init_thread_context(&mut self, initial_pc_reg: u64, initial_sp: u64, arg: i64) { self.thread_context.pc = initial_pc_reg; self.thread_context.int_registers[10] = arg; - self.thread_context.int_registers[STACK_REG] = initial_sp; + self.thread_context.int_registers[STACK_REG] = initial_sp as i64; } pub fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index acecc5b..e5b0e14 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -86,11 +86,11 @@ impl ThreadManager { } /// Start a thread, attaching it to a process - pub fn start_thread(&mut self, thread: Rc>, owner: Process, func_pc: u64, argument: i64) { + pub fn start_thread(&mut self, thread: Rc>, owner: Process, func_pc: u64, sp_loc: u64, argument: i64) { let mut thread_m = thread.borrow_mut(); assert_eq!(thread_m.process, Option::None); thread_m.process = Option::Some(owner); - let ptr = 0; // todo addrspace + let ptr = sp_loc; // todo addrspace thread_m.init_thread_context(func_pc, ptr, argument); let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray thread_m.init_simulator_context(base_stack_addr); @@ -206,7 +206,7 @@ mod test { #[ignore = "Pas encore terminé, contient des bugs"] fn test_thread_context() { let mut machine = Machine::init_machine(); - let loader = loader::Loader::new("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + let (loader, ptr) = loader::Loader::new("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); let start_pc = loader.elf_header.entrypoint; let system = &mut System::default(); @@ -215,7 +215,7 @@ mod test { system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, -1); + system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, ptr, -1); debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc); let to_run = system.get_thread_manager().find_next_to_run().unwrap(); diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 9bbe132..a3350e9 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -308,16 +308,18 @@ pub enum LoaderError { impl Loader { - pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result { + pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result<(Self, u64), LoaderError> { let loader = Self::load_and_parse(path)?; - loader.load_into_machine(machine, start_index)?; - Ok(loader) + let end_alloc = loader.load_into_machine(machine, start_index)?; + Ok((loader, end_alloc)) } - fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result{ + fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result { + let mut end_index = 0; for i in 0..self.sections.len() { let section = &self.sections[i]; if section.does_flag_contains_key(FlagValue::ShfAlloc) { + end_index = section.virt_addr + section.section_size; // Can allocate to machine memory for j in (0..section.section_size as usize).step_by(4) { let mut buf: [u8; 4] = [0; 4]; @@ -328,8 +330,7 @@ impl Loader { } } } - let last = self.sections.last().ok_or(LoaderError::ParsingError)?; - Ok(start_index as u64 + last.virt_addr + last.section_size) + Ok(start_index as u64 + end_index) } fn load_and_parse(path: &str) -> Result { From 025ede6080b3e92a876cbdea058cbe28f5c6b99c Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 3 Apr 2023 15:26:55 +0200 Subject: [PATCH 15/57] Add some comments --- src/simulator/loader.rs | 194 +++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 30 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index a3350e9..3952013 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -1,5 +1,4 @@ use crate::Machine; -use std::fmt::Error; use std::fs; use std::io::Read; @@ -24,65 +23,117 @@ pub fn load(path: &str, machine: &mut Machine, start_index: usize) -> Result<(), instructions.push(u32::from_le_bytes(buf)); } } - for i in 0..instructions.len() { - machine.write_memory(4, 4 * i + start_index, instructions[i] as u64); + for (i, inst) in instructions.iter().enumerate() { + machine.write_memory(4, 4 * i + start_index, inst.to_owned() as u64); } // #[cfg(debug_assertions)] // println!("{:04x?}", instructions); // only print loaded program in debug build Ok(()) } +/// The elf header defines principes aspects of the binary files, it's place at the start of the file +/// see for more informations pub struct ElfHeader { + /// Defines whether the file is big or little endian + /// true correspond to big endian, false otherwise + /// + /// Offset: 0x05, size: 1 byte pub endianess: bool, + /// Defines whether the file is 32 bits or 64 bits + /// + /// Offset: 0x04, size: 1 byte pub is_32bits: bool, + /// Version of the elf file, current version is 1 + /// + /// Offset: 0x06, size: 1 byte pub version: u8, + /// Identifies the target ABI. + /// + /// In this implementation: Defines if the target abi is system V compliant + /// + /// Offset: 0x07, size: 1 byte pub sys_v_abi: bool, + /// Identifies target ISA, 0xF3 correspond to RISC-V + /// + /// In this implementatio, true if target isa is RISC-V, false otherwise + /// + /// Offset: 0x12, size: 2 bytes pub is_riscv_target: bool, + /// Memory address of the entry point from w) -> bool { + fn is_elf(instructions: &[u8]) -> bool { instructions.get(0..4) == Option::Some(&[0x7f, 0x45, 0x4c, 0x46]) } /// return true if big endian, false otherwise - fn check_endianess(instructions: &Vec) -> bool { + fn check_endianess(instructions: &[u8]) -> bool { instructions.get(5) == Option::Some(&2) } /// return true if file is 32 bits, false if 64 bits - fn is_32bits(instructions: &Vec) -> bool { + fn is_32bits(instructions: &[u8]) -> bool { instructions.get(4) == Option::Some(&1) } /// return the version of the elf file (should be 1) /// Can be None if the file is smaller than 7 bytes -> the file is invalid - fn get_version(instructions: &Vec) -> Option { + fn get_version(instructions: &[u8]) -> Option { instructions.get(6).copied() // work as primitives implements Copy } /// return true if target abi of the binary file is System V, false otherwise - fn is_system_v_elf(instructions: &Vec) -> bool { + fn is_system_v_elf(instructions: &[u8]) -> bool { instructions.get(7) == Option::Some(&0) } /// return true if specified target instruction set architecture is RISCV - fn is_riscv_isa(instructions: &Vec) -> bool { + fn is_riscv_isa(instructions: &[u8]) -> bool { Self::get_u16_value(instructions, 0x12) == Option::Some(0xf3) } /// memory address of the entry point from where the process starts its execution - fn get_entrypoint(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_entrypoint(instructions: &[u8], is_32bits: bool) -> Option { if is_32bits { get_address_point(instructions, 0x18, true) } else { @@ -91,7 +142,12 @@ impl ElfHeader { } /// Memory address of the start of the program header table - fn get_program_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_program_header_table_location(instructions: &[u8], is_32bits: bool) -> Option { if is_32bits { get_address_point(instructions, 0x1c, true) } else { @@ -99,8 +155,13 @@ impl ElfHeader { } } - /// Memory address of the start of the section header table - fn get_section_header_table_location(instructions: &Vec, is_32bits: bool) -> Option { + /// Memory address of the start of the section header table + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_section_header_table_location(instructions: &[u8], is_32bits: bool) -> Option { if is_32bits { get_address_point(instructions, 0x20, true) } else { @@ -109,37 +170,69 @@ impl ElfHeader { } /// Return the size of the header, normally, 0x40 for 64 bits bin and 0x34 for 32 bits - fn get_elf_header_size(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_elf_header_size(instructions: &[u8], is_32bits: bool) -> Option { let address = if is_32bits { 0x28 } else { 0x34 }; Self::get_u16_value(instructions, address) } /// return the size of a program header table entry - fn get_program_header_size(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_program_header_size(instructions: &[u8], is_32bits: bool) -> Option { let address = if is_32bits { 0x2a } else { 0x36 }; Self::get_u16_value(instructions, address) } /// return the number of entries in the program header - fn get_number_entries_program_header(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_number_entries_program_header(instructions: &[u8], is_32bits: bool) -> Option { let address = if is_32bits { 0x2c } else { 0x38 }; Self::get_u16_value(instructions, address) } /// Return the size of a section header table entry - fn get_section_header_size(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_section_header_size(instructions: &[u8], is_32bits: bool) -> Option { let address = if is_32bits { 0x2e } else { 0x3a }; Self::get_u16_value(instructions, address) } /// Return the number of entries in the section header - fn get_section_header_num_entries(instructions: &Vec, is_32bits: bool) -> Option { + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **is_32bits** defines whether the binary file is 32 bits or 64 bits + fn get_section_header_num_entries(instructions: &[u8], is_32bits: bool) -> Option { let address = if is_32bits { 0x30 } else { 0x3c }; Self::get_u16_value(instructions, address) } /// Return a u16 value, usually for the size or the number of entries inside a header - fn get_u16_value(instructions: &Vec, address: usize) -> Option { + /// + /// This method retrieve 2 bytes and concatenate them assuming the file is little endian + /// + /// ## Arguments: + /// + /// **instructions** List of bytes of the loaded binary file + /// **address** Position of the first byte + fn get_u16_value(instructions: &[u8], address: usize) -> Option { let mut bytes: [u8; 2] = [0; 2]; bytes[0] = instructions.get(address).copied()?; bytes[1] = instructions.get(address + 1).copied()?; @@ -188,27 +281,63 @@ impl TryFrom<&Vec> for ElfHeader { } +/// Flag of a section, a section can have multiples flags by adding the values +#[allow(clippy::enum_variant_names)] +#[allow(dead_code)] pub enum FlagValue { + /// The section is writable ShfWrite = 0x1, + /// The section need to be allocate/occupe memory during execution ShfAlloc = 0x2, + /// The section need to be executable ShfExecinstr = 0x4, + /// Section might ber merged ShfMerge = 0x10, + /// Contain null-terminated (\0) strings ShfStrings = 0x20, - ShfInfoLink = 0x40, - ShfLinkOrder = 0x80, // There is others but are unrelevant (I think) } + +/// Section header entry, contains useful informations for each sections of the binary file +/// +/// see #[derive(Debug)] pub struct SectionHeader { + /// Offset to a string in .shstrtab section that represent the name of this section + /// + /// Offset: 0x0, size: 4 bytes pub name_offset: u32, + /// Identify the type of this header + /// + /// Offset: 0x4, size: 4 bytes pub header_type: u32, + /// Identify the atributes of this section + /// + /// see `Self::does_flag_contains_key(self, FlagValue)` + /// + /// Offset: 0x8, size: 4 (32 bits) or 8 (64 bits) bytes pub flags: u64, + /// Virtual address of the section in memory if section is loaded, 0x0 otherwise + /// + /// Offset: 0x0C (32 bits) or 0x10 (64 bits), size: 4 (32 bits) or 8 (64 bits) bytes pub virt_addr: u64, + /// Offset of the section in the file image (binary file) + /// + /// Offset: 0x10 (32 bits) or 0x18 (64 bits), size: 4 (32 bits) or 8 (64 bits) bytes pub image_offset: u64, + /// Size of the section in the file image, may be 0 + /// + /// Offset: 0x14 (32 bits) or 0x20 (64 bits), size: 4 (32 bits) or 8 (64 bits) bytes pub section_size: u64, pub section_link: u32, pub section_info: u32, + /// Contain the required alignment of the section, must be a power of 2 + /// + /// Offset: 0x20 (32 bits) or 0x30 (64 bits), size: 4 (32 bits) or 8 (64 bits) bytes pub required_align: u64, + /// Contain the size of each entry, for sections that contain fixed size entries, otherwise 0 + /// + /// Offset: 0x24 (32 bits) or 0x38 (64 bits), size: 4 (32 bits) or 8 (64 bits) bytes pub entry_size: u64 } @@ -219,20 +348,25 @@ impl SectionHeader { self.flags & key as u64 != 0 } - fn get_name_offset(instructions: &Vec, address: usize) -> Option { + /// Return the offset to a string in .shstrtab that represents the name of this section + fn get_name_offset(instructions: &[u8], address: usize) -> Option { get_address_point(instructions, address, true).map(|v| { v as u32 }) // set true to return a u32 } - fn get_header_type(instructions: &Vec, address: usize) -> Option { + /// Return the type of header of the section + fn get_header_type(instructions: &[u8], address: usize) -> Option { get_address_point(instructions, address + 0x4, true).map(|v| { v as u32 }) } - fn get_flags(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + /// Return the flags of the section, can hold multiples values, see [`FlagValue`] + fn get_flags(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + 0x8, is_32bits) } - fn get_virtual_address(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + + /// Return the virtual address of the section in memory if the sectino is loaded(see section flag), otherwise 0 + fn get_virtual_address(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x0C } else { 0x10 }, is_32bits) } @@ -398,7 +532,7 @@ impl Loader { /// return the memory address of something stored at address /// Can return None if the file is smaller than adress + 3 (or 7 if 64 bits), in this case, the elf header is incorrect -fn get_address_point(instructions: &Vec, address: usize, is_32bits: bool) -> Option { +fn get_address_point(instructions: &[u8], address: usize, is_32bits: bool) -> Option { if is_32bits { let mut bytes: [u8; 4] = [0; 4]; bytes[0] = instructions.get(address).copied()?; @@ -431,10 +565,10 @@ mod test { let mut machine = Machine::init_machine(); let loader = Loader::load_and_parse("./test/riscv_instructions/simple_arithmetics/unsigned_addition").expect("IO Error"); loader.load_into_machine(&mut machine, 0).expect("Parsing error"); - assert_eq!(false, loader.elf_header.is_32bits); - assert_eq!(false, loader.elf_header.endianess); - assert_eq!(true, loader.elf_header.sys_v_abi); - assert_eq!(true, loader.elf_header.is_riscv_target); + assert!(!loader.elf_header.is_32bits); + assert!(!loader.elf_header.endianess); + assert!(loader.elf_header.sys_v_abi); + assert!(loader.elf_header.is_riscv_target); assert_eq!(1, loader.elf_header.version); assert_eq!(0x4000, loader.elf_header.entrypoint); assert_eq!(64, loader.elf_header.elf_header_size); From aef8d219d025c8833629532a6afeb1dfd4391245 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 3 Apr 2023 15:58:57 +0200 Subject: [PATCH 16/57] Continue to add comments --- src/simulator/loader.rs | 106 +++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 3952013..82be5e7 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -129,7 +129,7 @@ impl ElfHeader { /// memory address of the entry point from where the process starts its execution /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -143,7 +143,7 @@ impl ElfHeader { /// Memory address of the start of the program header table /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -157,7 +157,7 @@ impl ElfHeader { /// Memory address of the start of the section header table /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -171,7 +171,7 @@ impl ElfHeader { /// Return the size of the header, normally, 0x40 for 64 bits bin and 0x34 for 32 bits /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -182,7 +182,7 @@ impl ElfHeader { /// return the size of a program header table entry /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -193,7 +193,7 @@ impl ElfHeader { /// return the number of entries in the program header /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -204,7 +204,7 @@ impl ElfHeader { /// Return the size of a section header table entry /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -215,7 +215,7 @@ impl ElfHeader { /// Return the number of entries in the section header /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **is_32bits** defines whether the binary file is 32 bits or 64 bits @@ -228,7 +228,7 @@ impl ElfHeader { /// /// This method retrieve 2 bytes and concatenate them assuming the file is little endian /// - /// ## Arguments: + /// ## Paramters: /// /// **instructions** List of bytes of the loaded binary file /// **address** Position of the first byte @@ -370,36 +370,40 @@ impl SectionHeader { get_address_point(instructions, address + if is_32bits { 0x0C } else { 0x10 }, is_32bits) } - fn get_image_offset(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + /// Return the offset of the section in the file image (binary file) + fn get_image_offset(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x10 } else { 0x18 }, is_32bits) } - fn get_section_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + /// Return the size of the section in the file image (binary file), may be 0 + fn get_section_size(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x14 } else { 0x20 }, is_32bits) } - fn get_section_link(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + fn get_section_link(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x18 } else { 0x28 }, false).map(|v| { v as u32 }) } - fn get_section_info(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + fn get_section_info(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x1C } else { 0x2C }, false).map(|v| { v as u32 }) } - fn get_required_align(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + /// Return the required alignment of the section, must be a power of 2 + fn get_required_align(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x20 } else { 0x30 }, is_32bits) } - fn get_entry_size(instructions: &Vec, address: usize, is_32bits: bool) -> Option { + /// Contain the size of each entry for sections that contain fixed-size entries, otherwise 0 + fn get_entry_size(instructions: &[u8], address: usize, is_32bits: bool) -> Option { get_address_point(instructions, address + if is_32bits { 0x24 } else { 0x38 }, is_32bits) } } -impl TryFrom<(&Vec, u64, bool)> for SectionHeader { +impl TryFrom<(&[u8], u64, bool)> for SectionHeader { type Error = (); - fn try_from(value: (&Vec, u64, bool)) -> Result { + fn try_from(value: (&[u8], u64, bool)) -> Result { let instructions = value.0; let address = value.1 as usize; let is_32bits = value.2; @@ -428,26 +432,47 @@ impl TryFrom<(&Vec, u64, bool)> for SectionHeader { } } -pub struct Loader { - bytes: Vec, - pub elf_header: ElfHeader, - pub sections: Vec -} - +/// Error enum for [`Loader`] #[derive(Debug)] pub enum LoaderError { + /// Correspond to std IO error IOError(std::io::Error), + /// Others errors ParsingError } +/// Global structure of the loader, one instance per loaded files +pub struct Loader { + /// List of bytes inside the binary file + bytes: Vec, + /// Elf header, see [`ElfHeader`] for more informations + pub elf_header: ElfHeader, + /// Section header table entries, see [`SectionHeader`] for more informations + pub sections: Vec +} impl Loader { + /// # Loader constructor + /// + /// Load the binary file given in parameter, parse it and load inside the machine memory + /// return the loader instance and the location of the end of the last a allocated section in memory + /// + /// ## Parameters + /// + /// **path**: location of the binary file on disk + /// **machine**: well, the risc-v simulator + /// **start_index**: The position at which you want to start to allocate the program pub fn new(path: &str, machine: &mut Machine, start_index: usize) -> Result<(Self, u64), LoaderError> { let loader = Self::load_and_parse(path)?; let end_alloc = loader.load_into_machine(machine, start_index)?; Ok((loader, end_alloc)) } + /// Try to load the binary file in memory after it been parsed + /// + /// Binary file is loaded according to sections order and rules, see [`SectionHeader`] + /// + /// Return the location of the end of the last a allocated section in memory fn load_into_machine(&self, machine: &mut Machine, start_index: usize) -> Result { let mut end_index = 0; for i in 0..self.sections.len() { @@ -457,7 +482,8 @@ impl Loader { // Can allocate to machine memory for j in (0..section.section_size as usize).step_by(4) { let mut buf: [u8; 4] = [0; 4]; - for k in 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)?; } machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64); @@ -467,6 +493,8 @@ impl Loader { Ok(start_index as u64 + end_index) } + /// Load the binary file and store it inside an array and try to parse it, + /// useful for a lot of thing like to know which sections to allocate memory and where fn load_and_parse(path: &str) -> Result { let file = fs::File::open(path); match file { @@ -507,15 +535,27 @@ impl Loader { }; // #[cfg(debug_assertions)] // println!("{:04x?}", instructions); // only print loaded program in debug build - return Ok(Self { bytes: instructions, elf_header, sections: section_header }); + Ok(Self { bytes: instructions, elf_header, sections: section_header }) }, Err(err) => { - return Err(LoaderError::IOError(err)); + Err(LoaderError::IOError(err)) } - }; + } } - fn parse_section_header(instructions: &Vec, is_32bits: bool, header_location: u64, num_of_entries: u16, entry_size: u16) -> Result, ()> { + + /// Try to parse sections header table + /// + /// Create one instance of [`SectionHeader`] for each entry and store it inside an array + /// + /// ## Parameters + /// + /// **instructions**: array of bytes of the binary file + /// **is_32bits**: contain whether the binary file is 32 bits or 64 bits + /// **header_location**: represent the position of the first entry of the header + /// **num_of_entries**: defines the number of section header entries + /// **entry_size**: Defines the size of an entry (each entry have the exact same size), value vary depending of if this binary file is 32 or 64 bits + fn parse_section_header(instructions: &[u8], is_32bits: bool, header_location: u64, num_of_entries: u16, entry_size: u16) -> Result, ()> { let mut sections: Vec = Default::default(); for i in 0..num_of_entries as u64 { sections.push(Self::parse_section_entry(instructions, is_32bits, header_location + i * entry_size as u64)?); @@ -523,7 +563,15 @@ impl Loader { Ok(sections) } - fn parse_section_entry(instructions: &Vec, is_32bits: bool, location: u64) -> Result { + + /// Parse one entry of the section header + /// + /// ## Parameters: + /// + /// **instructions**: array of bytes of the binary file + /// **is_32bits**: contain whether the binary file is 32 bits or 64 bits + /// **location**: represent the position of the entry on the file image + fn parse_section_entry(instructions: &[u8], is_32bits: bool, location: u64) -> Result { SectionHeader::try_from((instructions, location, is_32bits)) } From fc3237c4ad1ad63b028767e897406f3025b1667c Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 4 Apr 2023 11:50:29 +0200 Subject: [PATCH 17/57] Adding test to loader, update ci (hope it work) --- .gitlab-ci.yml | 2 ++ src/simulator/loader.rs | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0746ff7..e6b0a50 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,8 @@ stages: unit-test-job: stage: test script: + - echo "Compiling c files" + - cd test && make build && cd .. - echo "Running unit tests..." - cargo test diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 82be5e7..7185c29 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -602,13 +602,15 @@ fn get_address_point(instructions: &[u8], address: usize, is_32bits: bool) -> Op } } +/// Tests has been made for C program compiled with RISC-V GCC 12.2.0, target: riscv64-unknown-elf +/// +/// It may not pass in the future if future gcc version modify order of the binary or something else #[cfg(test)] mod test { - use crate::simulator::{loader::Loader, machine::Machine}; + use crate::simulator::{loader::{Loader, SectionHeader}, machine::Machine}; #[test] - #[ignore = "CI gitlab a modifié"] fn test_parse_elf() { let mut machine = Machine::init_machine(); let loader = Loader::load_and_parse("./test/riscv_instructions/simple_arithmetics/unsigned_addition").expect("IO Error"); @@ -629,4 +631,20 @@ mod test { println!("{:#x?}", loader.sections); } + #[test] + fn test_parse_section() { + let mut machine = Machine::init_machine(); + let loader = Loader::load_and_parse("./test/riscv_instructions/simple_arithmetics/unsigned_addition").expect("IO Error"); + loader.load_into_machine(&mut machine, 0).expect("Parsing error"); + assert_eq!(9, loader.sections.len()); + let n = loader.sections.iter().filter(|p| { p.does_flag_contains_key(crate::simulator::loader::FlagValue::ShfAlloc)}).collect::>().len(); + assert_eq!(3, n); + assert_eq!(loader.sections[1].virt_addr, 0x4000); + assert_eq!(loader.sections[1].image_offset, 0x1000); + assert!(loader.sections[1].does_flag_contains_key(crate::simulator::loader::FlagValue::ShfAlloc)); + assert_eq!(loader.sections[2].virt_addr, 0x400_000); + assert_eq!(loader.sections[2].image_offset, 0x2000); + assert!(loader.sections[2].does_flag_contains_key(crate::simulator::loader::FlagValue::ShfAlloc)); + } + } \ No newline at end of file From 57e3ef397bb852917f41c90ed28d85c3fabee1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:16:00 +0200 Subject: [PATCH 18/57] Updated .gitignore to exclude .vscode folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b81b510..58e09e4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.idea *.iml /*.txt +/.vscode From f19515f6e85b02e10f5d391ea5c040a22d199e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:35:33 +0200 Subject: [PATCH 19/57] Update .gitlab-ci.yml --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0746ff7..66a7f8c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,9 @@ default: image: rust:1.68 + before_script: + - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - tar xzf https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - mv riscv64-unknown-elf /opt/riscv stages: - test From ba8e7fe2054127a098ccc6957f45c51c1f4ca756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:36:40 +0200 Subject: [PATCH 20/57] i am stupid i reckon --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 66a7f8c..a089067 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ default: image: rust:1.68 before_script: - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - - tar xzf https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - tar xzf riscv64-cross-compiler-multilib.tar.gz - mv riscv64-unknown-elf /opt/riscv stages: From 2eee88c1d353acbb1ec2912351070259d5d21737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:35:33 +0200 Subject: [PATCH 21/57] Update .gitlab-ci.yml --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e6b0a50..0bf305f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,9 @@ default: image: rust:1.68 + before_script: + - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - tar xzf https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - mv riscv64-unknown-elf /opt/riscv stages: - test From 025c62b243c7314ec44e7cc3a1c5ad30f3665961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:36:40 +0200 Subject: [PATCH 22/57] i am stupid i reckon --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0bf305f..994f1d8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ default: image: rust:1.68 before_script: - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - - tar xzf https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - tar xzf riscv64-cross-compiler-multilib.tar.gz - mv riscv64-unknown-elf /opt/riscv stages: From 4be02a2a03a6daf8a017b473ab90bc69190899cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:41:14 +0200 Subject: [PATCH 23/57] Calmly asked wget to shut the fuck up --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a089067..d427948 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ default: image: rust:1.68 before_script: - - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - tar xzf riscv64-cross-compiler-multilib.tar.gz - mv riscv64-unknown-elf /opt/riscv From aa5ba94842f8f7cb8c410037ffda698a68420fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:41:14 +0200 Subject: [PATCH 24/57] Calmly asked wget to shut the fuck up --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 994f1d8..dfc8b5c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ default: image: rust:1.68 before_script: - - wget https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz + - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - tar xzf riscv64-cross-compiler-multilib.tar.gz - mv riscv64-unknown-elf /opt/riscv From d4f8ba2e3279881079c34b83aa8af678175b97ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Tue, 4 Apr 2023 14:50:25 +0200 Subject: [PATCH 25/57] fixed dumps not properly move into target --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index ad2c039..5aa4443 100644 --- a/test/Makefile +++ b/test/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/Makefile.config dumps: $(MAKE) dumps -C riscv_instructions/ mkdir -p ${TOPDIR}/target/dumps/ - find . -name '*.dump' -exec mv {} ${TOPDIR}/target/dumps/ \; + find . -path ${TOPDIR}/target -prune -o -name '*.dump' -exec mv {} ${TOPDIR}/target/dumps/ \; user_lib: $(MAKE) -C userlib/ From 9f937ff81f3b2d9c29f93f31dbc0367b6ffd79f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:54:28 +0200 Subject: [PATCH 26/57] fixed compiler not being copied to /opt/riscv --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d427948..d9484f7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,8 +2,8 @@ default: image: rust:1.68 before_script: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - - tar xzf riscv64-cross-compiler-multilib.tar.gz - - mv riscv64-unknown-elf /opt/riscv + - mkdir /opt/riscv + - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv stages: - test From 72743ded87d3fa2b7a3f7e43ff47d6d9641d5f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 14:54:28 +0200 Subject: [PATCH 27/57] fixed compiler not being copied to /opt/riscv --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dfc8b5c..6bbde90 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,8 +2,8 @@ default: image: rust:1.68 before_script: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - - tar xzf riscv64-cross-compiler-multilib.tar.gz - - mv riscv64-unknown-elf /opt/riscv + - mkdir /opt/riscv + - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv stages: - test From 793bf482fc075149c81e18f242d0065e313c419e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:02:35 +0200 Subject: [PATCH 28/57] Added glibc dependency --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d9484f7..bc55ae4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv + - sudo apt install glibc stages: - test From aeb5cacb4e8fb00a04e5d816411416388ca07cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:02:35 +0200 Subject: [PATCH 29/57] Added glibc dependency --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6bbde90..d2d304c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv + - sudo apt install glibc stages: - test From d1d3ae64a6726fd5214ab6632e10016e5a98fd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:03:47 +0200 Subject: [PATCH 30/57] Ok no sudo i get it --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc55ae4..e810da0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - - sudo apt install glibc + - apt install glibc stages: - test From 63c2f62a19e8a572d3c9011a64d69c69c032bb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:03:47 +0200 Subject: [PATCH 31/57] Ok no sudo i get it --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d2d304c..4072fd0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - - sudo apt install glibc + - apt install glibc stages: - test From 45647a784ccfa4454abaf8201262dc33ea6eb378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:05:45 +0200 Subject: [PATCH 32/57] UPDATING APT --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e810da0..a06604a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv + - apt update - apt install glibc stages: From e7178f4490c06da35335dc94b432f24d4ee71b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:09:52 +0200 Subject: [PATCH 33/57] Correct package name --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a06604a..1a68a86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ default: - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - apt update - - apt install glibc + - apt install libc6 stages: - test From f3f88e9beec9e2b2cad3a67947cda32bb8a324f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:05:45 +0200 Subject: [PATCH 34/57] UPDATING APT --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4072fd0..b7f3679 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ default: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv + - apt update - apt install glibc stages: From 64c8104668906ea8b4b96146dbe6461dc90bb9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:09:52 +0200 Subject: [PATCH 35/57] Correct package name --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7f3679..b18d1af 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ default: - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - apt update - - apt install glibc + - apt install libc6 stages: - test From bcc16dcec0d2a27245a301575659e233dd08edef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:16:41 +0200 Subject: [PATCH 36/57] Updated to debian bookworm --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1a68a86..9fb1212 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,9 @@ default: - image: rust:1.68 + image: rust:1.68-bookworm before_script: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - - apt update - - apt install libc6 stages: - test From 2b10da1d7d1f273b422cacc99d8b02a3fb0a274b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Tue, 4 Apr 2023 15:16:41 +0200 Subject: [PATCH 37/57] Updated to debian bookworm --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b18d1af..7f4eb4f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,9 @@ default: - image: rust:1.68 + image: rust:1.68-bookworm before_script: - wget -q https://cloud.cuwott.fr/s/9fyrejDxMdNRQNn/download/riscv64-cross-compiler-multilib.tar.gz - mkdir /opt/riscv - tar xzf riscv64-cross-compiler-multilib.tar.gz -C /opt/riscv - - apt update - - apt install libc6 stages: - test From b8cba1abd732d5ae6bbc3567269002e7bd1aafca Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 4 Apr 2023 17:25:51 +0200 Subject: [PATCH 38/57] Change Halt to Shutdown in sys.s --- test/userlib/sys.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/userlib/sys.s b/test/userlib/sys.s index 970117b..7b7e3da 100644 --- a/test/userlib/sys.s +++ b/test/userlib/sys.s @@ -63,8 +63,8 @@ __start: * ------------------------------------------------------------- */ - .globl Halt - .type __Halt, @function + .globl Shutdown + .type __Shutdown, @function Shutdown: addi a7,zero,SC_HALT ecall From 99b0128cfe7c6e6641e3fd73fdc83f2d4cfbb6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Tue, 4 Apr 2023 17:59:05 +0200 Subject: [PATCH 39/57] Implemented calls for sys.s, problem with compilation of riscV code, need to fix it later --- test/userlib/syscall.rs | 175 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 166 insertions(+), 9 deletions(-) diff --git a/test/userlib/syscall.rs b/test/userlib/syscall.rs index 4350f5a..54b82ba 100644 --- a/test/userlib/syscall.rs +++ b/test/userlib/syscall.rs @@ -1,21 +1,178 @@ +use std::str::Chars; + +/// Define the BurritOS running time basic unit pub struct Burritos_Time { seconds: i64, nanos: i64 } + +/// A unique identifier for a thread executed within a user program pub struct ThreadId{ id: u64 } + +/// The system call interface. These are the operations the BurritOS +/// kernel needs to support, to be able to run user programs. pub struct t_error{ t: i32 } -extern "C"{ - fn Shutdown() -> (); - fn SysTime(t: Burritos_Time) -> (); - fn Exit(status: i32) -> (); - fn Exec(name: String) -> ThreadId; - fn newThread(debug_name: String, func: i32, arg: i32) -> ThreadId; - fn Join (id: ThreadId) -> t_error; - fn Yield() -> (); - fn Perror(mess: String) -> (); +/// A unique identifier for an open BurritOS file. +pub struct OpenFiledId{ + id: u64 +} + +/// System calls concerning semaphores management +pub struct SemId{ + id: u64 +} + +/// System calls concerning locks management +pub struct LockId{ + id: u64 +} + +/// System calls concerning conditions variables. +pub struct CondId{ + id: u64 +} +extern "C"{ + + ///Stop Nachos, and print out performance stats + fn Shutdown() -> (); + + /// Return the time spent running Nachos + fn SysTime(t: Burritos_Time) -> (); + + /// This user program is done (status = 0 means exited normally). + fn Exit(status: i32) -> (); + + /// Run the executable, stored in the Nachos file "name", and return the + /// master thread identifier + fn Exec(name: *char) -> ThreadId; + + /// Create a new thread in the current process + /// Return thread identifier + fn newThread(debug_name: *char, func: i32, arg: i32) -> ThreadId; + + /// Only return once the the thread "id" has finished. + fn Join (id: ThreadId) -> t_error; + + /// Yield the CPU to another runnable thread, whether in this address space + /// or not. + fn Yield() -> (); + + /// Print the last error message with the personalized one "mess" + fn PError(mess: *char) -> (); + + /// Create a BurritOS file, with "name" + fn Create(name: *char, size: i32) -> t_error; + + /// Open the Nachos file "name", and return an "OpenFileId" that can + /// be used to read and write to the file. + fn Open(name: *char) -> OpenFiledId; + + /// Write "size" bytes from "buffer" to the open file. + fn Write(buffer: *char, size: i32, id: OpenFiledId) -> t_error; + + /// Read "size" bytes from the open file into "buffer". + /// Return the number of bytes actually read -- if the open file isn't + /// long enough, or if it is an I/O device, and there aren't enough + /// characters to read, return whatever is available (for I/O devices, + /// you should always wait until you can return at least one character). + fn Read(buffer: *char, size: i32, id:OpenFiledId) -> t_error; + + /// Seek to a specified offset into an opened file + fn Seek(offset: i32, id: OpenFiledId) -> t_error; + + /// Close the file, we're done reading and writing to it. + fn Close(id: OpenFiledId) -> t_error; + + /// Remove the file + fn Remove(name: *char) -> t_error; + + //////////////////////////////////////////////////// + /// system calls concerning directory management /// + //////////////////////////////////////////////////// + + /// Create a new repertory + /// Return a negative number if an error ocurred. + fn mkdir(name: *char) -> t_length; + + /// Destroy a repertory, which must be empty. + /// Return a negative number if an error ocurred. + fn Rmdir(name: *char) -> t_error; + + /// List the content of BurritOS FileSystem + fn FSList() -> t_error; + + /// Create a semaphore, initialising it at count. + /// Return a Semid, which will enable to do operations on this + /// semaphore + fn SemCreate(debug_name: *char, count: i32) -> SemId; + + /// Destroy a semaphore identified by sema. + /// Return a negative number if an error occured during the destruction + fn SemDestroy(sema: SemId) -> t_error; + + /// Do the operation P() on the semaphore sema + fn P(sema: SemId) -> t_error; + + /// Do the operation V() on the semaphore sema + fn V(sema: SemId) -> t_error; + + /// Create a lock. + /// Return an identifier + fn LockCreate(debug_name: *char) -> LockId; + + /// Destroy a lock. + /// Return a negative number if an error ocurred + /// during the destruction. + fn LockDestroy(id: LockId) -> t_error; + + /// Do the operation Acquire on the lock id. + /// Return a negative number if an error ocurred. + fn LockAcquire(id: LockId) -> t_error; + + /// Do the operation Release on the lock id. + /// Return a negative number if an error ocurred. + fn LockRelease(id: LockId) -> t_error; + + /// Create a new condition variable + fn CondCreate(debug_name: *char) -> CondId; + + /// Destroy a condition variable. + /// Return a negative number if an error ocurred. + fn CondDestroy(id: CondId) -> t_error; + + /// Do the operation Wait on a condition variable. + /// Returns a negative number if an error ocurred. + fn CondWait(id: CondId) -> t_error; + + /// Do the operation Signal on a condition variable (wake up only one thread). + /// Return a negative number if an error ocurred. + fn CondSignal(id: CondId) -> t_error; + + /// Do the operation Signal on a condition variable (wake up all threads). + /// Return a negative number if an error ocurred. + fn CondBroadcast(id: CondId) -> t_error; + + /////////////////////////////////////////////////////// + /// System calls concerning serial port and console /// + /////////////////////////////////////////////////////// + + ///Send the message on the serial communication link. + /// Returns the number of bytes successfully sent. + fn TtySend(mess: *char) -> i32; + + /// Wait for a message comming from the serial communication link. + /// The length of the buffer where the bytes will be copied is given as a parameter. + /// Returns the number of characters actually received. + fn TtyReceive(mess: *char, length: i32) -> i32; + + /// Map an opened file in memory. Size is the size to be mapped in bytes. + fn Mmap(id: OpenFiledId, size: i32) -> *mut (); + + /// For debug purpose + fn Debug(param: i32)-> (); } \ No newline at end of file From a001e45c3f0b08bb7a064c14408e60515362193c Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 4 Apr 2023 20:55:27 +0200 Subject: [PATCH 40/57] Add tests files --- test/riscv_instructions/.gitignore | 1 + test/riscv_instructions/Makefile | 6 +++++- test/riscv_instructions/syscall_tests/Makefile | 16 ++++++++++++++++ test/riscv_instructions/syscall_tests/halt.c | 7 +++++++ test/riscv_instructions/syscall_tests/prints.c | 10 ++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/riscv_instructions/syscall_tests/Makefile create mode 100644 test/riscv_instructions/syscall_tests/halt.c create mode 100644 test/riscv_instructions/syscall_tests/prints.c diff --git a/test/riscv_instructions/.gitignore b/test/riscv_instructions/.gitignore index 140fad6..6c5f286 100644 --- a/test/riscv_instructions/.gitignore +++ b/test/riscv_instructions/.gitignore @@ -1,5 +1,6 @@ * !.gitignore !*.c +!*/ !*.md !**/Makefile \ No newline at end of file diff --git a/test/riscv_instructions/Makefile b/test/riscv_instructions/Makefile index 7c9a691..029a205 100644 --- a/test/riscv_instructions/Makefile +++ b/test/riscv_instructions/Makefile @@ -2,18 +2,22 @@ build: make build -C boolean_logic/ make build -C jump_instructions/ make build -C simple_arithmetics/ + make build -C syscall_tests/ dumps: make dumps -C boolean_logic/ make dumps -C jump_instructions/ make dumps -C simple_arithmetics/ + make dumps -C syscall_tests/ tests: make tests -C boolean_logic/ make tests -C jump_instructions/ make tests -C simple_arithmetics/ + make tests -C syscall_tests/ clean: $(MAKE) clean -C boolean_logic/ $(MAKE) clean -C jump_instructions/ - $(MAKE) clean -C simple_arithmetics/ \ No newline at end of file + $(MAKE) clean -C simple_arithmetics/ + $(MAKE) clean -C syscall_tests/ \ No newline at end of file diff --git a/test/riscv_instructions/syscall_tests/Makefile b/test/riscv_instructions/syscall_tests/Makefile new file mode 100644 index 0000000..62b3741 --- /dev/null +++ b/test/riscv_instructions/syscall_tests/Makefile @@ -0,0 +1,16 @@ + +PROGRAMS = halt prints + +build: $(PROGRAMS) + +dumps: halt.dump prints.dump + +tests: halt.guac prints.guac + +clean: + $(RM) halt.o halt prints prints.o + +TOPDIR = ../.. +include $(TOPDIR)/Makefile.tests + +$(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/riscv_instructions/syscall_tests/halt.c b/test/riscv_instructions/syscall_tests/halt.c new file mode 100644 index 0000000..7b3cd62 --- /dev/null +++ b/test/riscv_instructions/syscall_tests/halt.c @@ -0,0 +1,7 @@ + +#include "userlib/syscall.h" + +int main() { + Shutdown(); + return 0; +} \ No newline at end of file diff --git a/test/riscv_instructions/syscall_tests/prints.c b/test/riscv_instructions/syscall_tests/prints.c new file mode 100644 index 0000000..c2f296a --- /dev/null +++ b/test/riscv_instructions/syscall_tests/prints.c @@ -0,0 +1,10 @@ +#include "userlib/syscall.h" +#include "userlib/libnachos.h" + +int main() { + n_printf("Hello World 1"); + n_printf("Hello World 2"); + n_printf("Hello World 3"); + n_printf("Hello World 4"); + return 0; +} \ No newline at end of file From 0fd2815a59fe500a66685b34915ac5df11098a92 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 4 Apr 2023 22:01:49 +0200 Subject: [PATCH 41/57] Improve test in thread_manager, increase memory size to make it fit --- src/kernel/exception.rs | 2 -- src/kernel/thread_manager.rs | 27 ++++++++++++++++++--------- src/simulator/loader.rs | 2 +- src/simulator/machine.rs | 2 +- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index 24555fe..5a96b44 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -1,5 +1,3 @@ -use libc::printf; - use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}; diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index e5b0e14..ad123f3 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -200,13 +200,15 @@ impl ThreadManager { mod test { use std::{rc::Rc, cell::RefCell}; - use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::Thread, process::Process}}; + use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::{Thread, self}, process::Process}}; #[test] #[ignore = "Pas encore terminé, contient des bugs"] fn test_thread_context() { let mut machine = Machine::init_machine(); - let (loader, ptr) = loader::Loader::new("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + let (loader, ptr1) = loader::Loader::new("./test/riscv_instructions/simple_arithmetics/unsigned_addition", &mut machine, 0).expect("IO Error"); + println!("{}", ptr1); + let (loader2, ptr2) = loader::Loader::new("./test/riscv_instructions/syscall_tests/halt", &mut machine, ptr1 as usize).expect("IO Error"); let start_pc = loader.elf_header.entrypoint; let system = &mut System::default(); @@ -214,17 +216,24 @@ mod test { let thread1 = Rc::new(RefCell::new(thread1)); system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); - let owner = Process { num_thread: 0 }; - system.get_thread_manager().start_thread(Rc::clone(&thread1), owner, start_pc, ptr, -1); - debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc); + let thread2 = Thread::new("th2"); + let thread2 = Rc::new(RefCell::new(thread2)); + system.get_thread_manager().get_g_alive().push(Rc::clone(&thread1)); - let to_run = system.get_thread_manager().find_next_to_run().unwrap(); - debug_assert_eq!(to_run, 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 }; + 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!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1))); + let to_run = system.get_thread_manager().find_next_to_run().unwrap(); + debug_assert_eq!(to_run, Rc::clone(&thread2)); + 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(&thread1))); - debug_assert_eq!(machine.pc, start_pc); + debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread2))); + debug_assert_eq!(machine.pc, ptr1 + loader2.elf_header.entrypoint); machine.run(); } diff --git a/src/simulator/loader.rs b/src/simulator/loader.rs index 7185c29..6916705 100644 --- a/src/simulator/loader.rs +++ b/src/simulator/loader.rs @@ -490,7 +490,7 @@ impl Loader { } } } - Ok(start_index as u64 + end_index) + Ok(start_index as u64 + end_index + 4) } /// Load the binary file and store it inside an array and try to parse it, diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index a5dc3e4..cf320a5 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -75,7 +75,7 @@ pub const NUM_PHY_PAGE : u64 = 400; /// Must be 2^x pub const PAGE_SIZE : u64 = 128; /// Must be a multiple of PAGE_SIZE -pub const MEM_SIZE : usize = (PAGE_SIZE*NUM_PHY_PAGE*100) as usize; +pub const MEM_SIZE : usize = (PAGE_SIZE*NUM_PHY_PAGE*100_000) as usize; /// RISC-V Simulator pub struct Machine { From 24be35547e5c227ea764e8c68c265639fa9dbbce Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 5 Apr 2023 12:01:31 +0200 Subject: [PATCH 42/57] Add Exit Exception --- src/kernel/exception.rs | 34 +++++++++++++++++++++++++--------- src/kernel/thread_manager.rs | 18 +++++++++--------- src/main.rs | 4 ++-- src/simulator/machine.rs | 19 ++++++++++--------- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index 5a96b44..0cf5921 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -1,5 +1,9 @@ +use std::rc::Rc; + use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}; +use super::system::System; + pub const SC_SHUTDOWN: u8 = 0; pub const SC_EXIT: u8 = 1; @@ -40,11 +44,11 @@ pub const SC_DEBUG: u8 = 34; pub const CONSOLE_OUTPUT: u8 = 1; // todo : returns new types, not just machine errors and machine ok -pub fn call(exception: ExceptionType, machine: &Machine) -> Result { +pub fn call(exception: ExceptionType, machine: &mut Machine, system: &mut System) -> Result { match exception { ExceptionType::NoException => todo!(), - ExceptionType::SyscallException => syscall(machine), + ExceptionType::SyscallException => syscall(machine, system), ExceptionType::PagefaultException => todo!(), ExceptionType::ReadOnlyException => todo!(), ExceptionType::BusErrorException => todo!(), @@ -55,12 +59,23 @@ pub fn call(exception: ExceptionType, machine: &Machine) -> Result Result { +fn syscall(machine: &mut Machine, system: &mut System) -> Result { let call_type = machine.read_int_register(17) as u8; match call_type { SC_SHUTDOWN => Ok(MachineOk::Shutdown), - SC_EXIT => todo!(), + SC_EXIT => { + match &system.get_thread_manager().g_current_thread { + Some(th) => { + let th = Rc::clone(th); + system.get_thread_manager().thread_finish(machine, th); + Ok(MachineOk::Ok) + }, + None => { + Err("Current thread is None".into()) + } + } + }, SC_EXEC => todo!(), SC_JOIN => todo!(), SC_CREATE => todo!(), @@ -121,6 +136,7 @@ fn syscall(machine: &Machine) -> Result { #[cfg(test)] mod test { use crate::kernel::exception::{SC_SHUTDOWN, SC_WRITE}; + use crate::kernel::system::System; use crate::simulator::instruction::Instruction; use crate::simulator::machine::Machine; @@ -132,8 +148,8 @@ mod test { machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10 - - machine.run(); + let mut system = System::default(); + machine.run(&mut system); // 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 } @@ -162,9 +178,9 @@ mod test { 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.run(); + + let mut system = System::default(); + machine.run(&mut system); } } \ No newline at end of file diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index ad123f3..3b558bc 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -123,8 +123,8 @@ impl ThreadManager { /// Put the thread to sleep and relinquish the processor pub fn thread_sleep(&mut self, machine: &mut Machine, thread: Rc>) { - assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); - assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff); + debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); + debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff); let mut next_thread = self.find_next_to_run(); while next_thread.is_none() { @@ -220,22 +220,22 @@ mod test { let thread2 = Rc::new(RefCell::new(thread2)); 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 }; 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!(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(); - 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)); - debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread2))); - debug_assert_eq!(machine.pc, ptr1 + loader2.elf_header.entrypoint); + debug_assert_eq!(system.get_thread_manager().g_current_thread, Option::Some(Rc::clone(&thread1))); + debug_assert_eq!(machine.pc, loader.elf_header.entrypoint); - machine.run(); + machine.run(system); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9fe5976..73a439f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,6 @@ use simulator::machine::Machine; fn main() { let mut machine = Machine::init_machine(); - let system = System::default(); - machine.run() + let mut system = System::default(); + machine.run(&mut system); } diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index cf320a5..123b43b 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -15,13 +15,13 @@ use std::{ io::Write, fs::File }; -use crate::simulator::{ +use crate::{simulator::{ error::MachineError, instruction::{*, self}, interrupt::Interrupt, global::*, register::* -}; +}, kernel::system::System}; use crate::kernel::{ exception @@ -226,11 +226,11 @@ impl Machine { s } - pub fn raise_exception(&mut self, exception: ExceptionType, address : u64) -> Result{ + pub fn raise_exception(&mut self, exception: ExceptionType, address : u64, system: &mut System) -> Result{ self.set_status(MachineStatus::SystemMode); // Handle the interruption - match exception::call(exception, self) { + match exception::call(exception, self, system) { Ok(MachineOk::Shutdown) => { self.set_status(MachineStatus::UserMode); return Ok(MachineOk::Shutdown); @@ -246,9 +246,9 @@ impl Machine { /// ### Parameters /// /// - **machine** which contains a table of instructions - pub fn run(&mut self) { + pub fn run(&mut self, system: &mut System) { loop { - match self.one_instruction() { + match self.one_instruction(system) { Ok(MachineOk::Ok) => println!("hello"), Ok(MachineOk::Shutdown) => break, Err(e) => { if e.to_string().contains("System") { break; } panic!("FATAL at pc {} -> {}", self.pc, e) } @@ -262,7 +262,7 @@ impl Machine { /// ### Parameters /// /// - **machine** which contains a table of instructions and a pc to the actual instruction - pub fn one_instruction(&mut self) -> Result { + pub fn one_instruction(&mut self, system: &mut System) -> Result { if self.main_memory.len() <= self.pc as usize { panic!("ERROR : number max of instructions rushed"); @@ -335,7 +335,7 @@ impl Machine { RISCV_FP => self.fp_instruction(inst), // 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 _ => 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_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); - 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(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); From 411caac86f43a9567eff2d8c3ea0d52831356310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 10:53:34 +0000 Subject: [PATCH 43/57] Assembly lib --- .gitignore | 2 ++ test/Makefile => Makefile | 11 ++++--- test/Makefile.config => Makefile.config | 0 test/Makefile.tests => Makefile.rules | 3 ++ Makefile.userlib | 0 build.rs | 3 -- {test/userlib => src/kernel}/syscall.rs | 33 ++++++++++--------- .../riscv_instructions/boolean_logic/Makefile | 4 +-- .../jump_instructions/Makefile | 4 +-- .../simple_arithmetics/Makefile | 4 +-- .../riscv_instructions/syscall_tests/Makefile | 4 +-- test/userlib/Makefile | 7 ---- userlib/Makefile | 7 ++++ {test/userlib => userlib}/ldscript.lds | 0 {test/userlib => userlib}/libnachos.c | 0 {test/userlib => userlib}/libnachos.h | 0 {test/userlib => userlib}/sys.s | 0 {test/userlib => userlib}/syscall.h | 0 18 files changed, 43 insertions(+), 39 deletions(-) rename test/Makefile => Makefile (64%) rename test/Makefile.config => Makefile.config (100%) rename test/Makefile.tests => Makefile.rules (96%) create mode 100644 Makefile.userlib rename {test/userlib => src/kernel}/syscall.rs (86%) delete mode 100644 test/userlib/Makefile create mode 100644 userlib/Makefile rename {test/userlib => userlib}/ldscript.lds (100%) rename {test/userlib => userlib}/libnachos.c (100%) rename {test/userlib => userlib}/libnachos.h (100%) rename {test/userlib => userlib}/sys.s (100%) rename {test/userlib => userlib}/syscall.h (100%) diff --git a/.gitignore b/.gitignore index 58e09e4..a60c662 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ *.iml /*.txt /.vscode +*.a +*.o diff --git a/test/Makefile b/Makefile similarity index 64% rename from test/Makefile rename to Makefile index 2cf5313..9daf3b6 100644 --- a/test/Makefile +++ b/Makefile @@ -7,24 +7,25 @@ all: dumps user_lib tests # Main targets # -build: user_lib - $(MAKE) build -C riscv_instructions/ +instruction_tests: + $(MAKE) build -C test/riscv_instructions/ dumps: - $(MAKE) dumps -C riscv_instructions/ + $(MAKE) dumps -C test/riscv_instructions/ mkdir -p ${TOPDIR}/target/dumps/ find . -path ${TOPDIR}/target -prune -o -name '*.dump' -exec mv {} ${TOPDIR}/target/dumps/ \; user_lib: $(MAKE) -C userlib/ + mv ${TOPDIR}/userlib/sys.a ${TOPDIR}/src/sys.a tests: user_lib - $(MAKE) tests -C riscv_instructions/ + $(MAKE) tests -C test/riscv_instructions/ mkdir -p ${TOPDIR}/target/guac/ find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ \; clean: $(MAKE) clean -C userlib/ - $(MAKE) clean -C riscv_instructions/ + $(MAKE) clean -C test/riscv_instructions/ $(RM) -rf $(TOPDIR)/target \ No newline at end of file diff --git a/test/Makefile.config b/Makefile.config similarity index 100% rename from test/Makefile.config rename to Makefile.config diff --git a/test/Makefile.tests b/Makefile.rules similarity index 96% rename from test/Makefile.tests rename to Makefile.rules index 14dba3d..58fab4b 100644 --- a/test/Makefile.tests +++ b/Makefile.rules @@ -18,6 +18,9 @@ CFLAGS = $(RISCV_CFLAGS) $(INCPATH) %.o: %.c $(GCC) $(CFLAGS) -c $< +%.a: %.o + $(AR) $(ARFLAGS) $@ $< + %.dump: %.o $(RISCV_OBJCOPY) -j .text -O $(DUMP_FORMAT) $< $@ diff --git a/Makefile.userlib b/Makefile.userlib new file mode 100644 index 0000000..e69de29 diff --git a/build.rs b/build.rs index 7b5ec8a..ea3850b 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,2 @@ fn main() { - cc::Build::new() - .file("test/userlib/sys.s") - .compile("my-asm-lib"); } \ No newline at end of file diff --git a/test/userlib/syscall.rs b/src/kernel/syscall.rs similarity index 86% rename from test/userlib/syscall.rs rename to src/kernel/syscall.rs index 54b82ba..14ceeb7 100644 --- a/test/userlib/syscall.rs +++ b/src/kernel/syscall.rs @@ -36,7 +36,8 @@ pub struct LockId{ pub struct CondId{ id: u64 } -extern "C"{ + +extern "C" { ///Stop Nachos, and print out performance stats fn Shutdown() -> (); @@ -49,11 +50,11 @@ extern "C"{ /// Run the executable, stored in the Nachos file "name", and return the /// master thread identifier - fn Exec(name: *char) -> ThreadId; + fn Exec(name: *const char) -> ThreadId; /// Create a new thread in the current process /// Return thread identifier - fn newThread(debug_name: *char, func: i32, arg: i32) -> ThreadId; + fn newThread(debug_name: *const char, func: i32, arg: i32) -> ThreadId; /// Only return once the the thread "id" has finished. fn Join (id: ThreadId) -> t_error; @@ -63,24 +64,24 @@ extern "C"{ fn Yield() -> (); /// Print the last error message with the personalized one "mess" - fn PError(mess: *char) -> (); + fn PError(mess: *const char) -> (); /// Create a BurritOS file, with "name" - fn Create(name: *char, size: i32) -> t_error; + fn Create(name: *const char, size: i32) -> t_error; /// Open the Nachos file "name", and return an "OpenFileId" that can /// be used to read and write to the file. - fn Open(name: *char) -> OpenFiledId; + fn Open(name: *const char) -> OpenFiledId; /// Write "size" bytes from "buffer" to the open file. - fn Write(buffer: *char, size: i32, id: OpenFiledId) -> t_error; + fn Write(buffer: *const char, size: i32, id: OpenFiledId) -> t_error; /// Read "size" bytes from the open file into "buffer". /// Return the number of bytes actually read -- if the open file isn't /// long enough, or if it is an I/O device, and there aren't enough /// characters to read, return whatever is available (for I/O devices, /// you should always wait until you can return at least one character). - fn Read(buffer: *char, size: i32, id:OpenFiledId) -> t_error; + fn Read(buffer: *const char, size: i32, id:OpenFiledId) -> t_error; /// Seek to a specified offset into an opened file fn Seek(offset: i32, id: OpenFiledId) -> t_error; @@ -89,7 +90,7 @@ extern "C"{ fn Close(id: OpenFiledId) -> t_error; /// Remove the file - fn Remove(name: *char) -> t_error; + fn Remove(name: *const char) -> t_error; //////////////////////////////////////////////////// /// system calls concerning directory management /// @@ -97,11 +98,11 @@ extern "C"{ /// Create a new repertory /// Return a negative number if an error ocurred. - fn mkdir(name: *char) -> t_length; + fn mkdir(name: *const char) -> t_length; /// Destroy a repertory, which must be empty. /// Return a negative number if an error ocurred. - fn Rmdir(name: *char) -> t_error; + fn Rmdir(name: *const char) -> t_error; /// List the content of BurritOS FileSystem fn FSList() -> t_error; @@ -109,7 +110,7 @@ extern "C"{ /// Create a semaphore, initialising it at count. /// Return a Semid, which will enable to do operations on this /// semaphore - fn SemCreate(debug_name: *char, count: i32) -> SemId; + fn SemCreate(debug_name: *const char, count: i32) -> SemId; /// Destroy a semaphore identified by sema. /// Return a negative number if an error occured during the destruction @@ -123,7 +124,7 @@ extern "C"{ /// Create a lock. /// Return an identifier - fn LockCreate(debug_name: *char) -> LockId; + fn LockCreate(debug_name: *const char) -> LockId; /// Destroy a lock. /// Return a negative number if an error ocurred @@ -139,7 +140,7 @@ extern "C"{ fn LockRelease(id: LockId) -> t_error; /// Create a new condition variable - fn CondCreate(debug_name: *char) -> CondId; + fn CondCreate(debug_name: *const char) -> CondId; /// Destroy a condition variable. /// Return a negative number if an error ocurred. @@ -163,12 +164,12 @@ extern "C"{ ///Send the message on the serial communication link. /// Returns the number of bytes successfully sent. - fn TtySend(mess: *char) -> i32; + fn TtySend(mess: *const char) -> i32; /// Wait for a message comming from the serial communication link. /// The length of the buffer where the bytes will be copied is given as a parameter. /// Returns the number of characters actually received. - fn TtyReceive(mess: *char, length: i32) -> i32; + fn TtyReceive(mess: *const char, length: i32) -> i32; /// Map an opened file in memory. Size is the size to be mapped in bytes. fn Mmap(id: OpenFiledId, size: i32) -> *mut (); diff --git a/test/riscv_instructions/boolean_logic/Makefile b/test/riscv_instructions/boolean_logic/Makefile index e9b0a52..b0d2554 100644 --- a/test/riscv_instructions/boolean_logic/Makefile +++ b/test/riscv_instructions/boolean_logic/Makefile @@ -7,8 +7,8 @@ dumps: comparisons.dump if.dump switch.dump tests: comparisons.guac if.guac switch.guac -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests +TOPDIR = ../../.. +include $(TOPDIR)/Makefile.rules clean: $(RM) comparisons comparisons.o if if.o diff --git a/test/riscv_instructions/jump_instructions/Makefile b/test/riscv_instructions/jump_instructions/Makefile index 71ce3c0..72523a3 100644 --- a/test/riscv_instructions/jump_instructions/Makefile +++ b/test/riscv_instructions/jump_instructions/Makefile @@ -9,7 +9,7 @@ tests: jump.guac ret.guac clean: $(RM) jump jump.o ret ret.o -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests +TOPDIR = ../../.. +include $(TOPDIR)/Makefile.rules $(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/riscv_instructions/simple_arithmetics/Makefile b/test/riscv_instructions/simple_arithmetics/Makefile index 9b42a4b..1d3dcf2 100644 --- a/test/riscv_instructions/simple_arithmetics/Makefile +++ b/test/riscv_instructions/simple_arithmetics/Makefile @@ -10,7 +10,7 @@ tests: unsigned_addition.guac unsigned_division.guac unsigned_multiplication.gua clean: $(RM) unsigned_addition unsigned_addition.o unsigned_division unsigned_division.o unsigned_multiplication unsigned_multiplication.o unsigned_substraction unsigned_substraction.o -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests +TOPDIR = ../../.. +include $(TOPDIR)/Makefile.rules $(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/riscv_instructions/syscall_tests/Makefile b/test/riscv_instructions/syscall_tests/Makefile index 62b3741..e528387 100644 --- a/test/riscv_instructions/syscall_tests/Makefile +++ b/test/riscv_instructions/syscall_tests/Makefile @@ -10,7 +10,7 @@ tests: halt.guac prints.guac clean: $(RM) halt.o halt prints prints.o -TOPDIR = ../.. -include $(TOPDIR)/Makefile.tests +TOPDIR = ../../.. +include $(TOPDIR)/Makefile.rules $(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/userlib/Makefile b/test/userlib/Makefile deleted file mode 100644 index 6a5c70f..0000000 --- a/test/userlib/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -TOPDIR = ../ -include $(TOPDIR)/Makefile.tests - -default: sys.o libnachos.o - -clean: - $(RM) libnachos.o sys.o \ No newline at end of file diff --git a/userlib/Makefile b/userlib/Makefile new file mode 100644 index 0000000..79d7bd9 --- /dev/null +++ b/userlib/Makefile @@ -0,0 +1,7 @@ +TOPDIR = ../ +include $(TOPDIR)/Makefile.rules + +default: sys.a libnachos.a + +clean: + $(RM) libnachos.a sys.a libnachos.o sys.o \ No newline at end of file diff --git a/test/userlib/ldscript.lds b/userlib/ldscript.lds similarity index 100% rename from test/userlib/ldscript.lds rename to userlib/ldscript.lds diff --git a/test/userlib/libnachos.c b/userlib/libnachos.c similarity index 100% rename from test/userlib/libnachos.c rename to userlib/libnachos.c diff --git a/test/userlib/libnachos.h b/userlib/libnachos.h similarity index 100% rename from test/userlib/libnachos.h rename to userlib/libnachos.h diff --git a/test/userlib/sys.s b/userlib/sys.s similarity index 100% rename from test/userlib/sys.s rename to userlib/sys.s diff --git a/test/userlib/syscall.h b/userlib/syscall.h similarity index 100% rename from test/userlib/syscall.h rename to userlib/syscall.h From 743299fcdb40f1dd419b26515cc032192df8b1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:02:29 +0200 Subject: [PATCH 44/57] repo clean-up --- Makefile.userlib | 0 build.rs | 2 -- 2 files changed, 2 deletions(-) delete mode 100644 Makefile.userlib delete mode 100644 build.rs diff --git a/Makefile.userlib b/Makefile.userlib deleted file mode 100644 index e69de29..0000000 diff --git a/build.rs b/build.rs deleted file mode 100644 index ea3850b..0000000 --- a/build.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { -} \ No newline at end of file From 8b3a3bebe79d9bdff2e97af755014350706d1fb4 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 5 Apr 2023 13:07:10 +0200 Subject: [PATCH 45/57] Fix list::remove when trying to remove first element of the list (SIGSEGV) --- src/kernel/thread_manager.rs | 2 ++ src/utility/list.rs | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 3b558bc..e7b1288 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -141,6 +141,8 @@ impl ThreadManager { let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff); self.g_thread_to_be_destroyed = Option::Some(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 self.thread_sleep(machine, Rc::clone(&thread)); machine.interrupt.set_status(old_status); diff --git a/src/utility/list.rs b/src/utility/list.rs index 801a74e..db514de 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -113,8 +113,12 @@ impl List { let mut current: *mut Node = self.head; let mut previous: *mut Node = ptr::null_mut(); while !current.is_null() { - if (*current).elem == item { - (*previous).next = (*current).next; + if (&*current).elem == item { + if !previous.is_null() { + (*previous).next = (*current).next; + } else { + self.head = (*current).next; + } drop(Box::from_raw(current).elem); return true; } else { @@ -320,6 +324,22 @@ mod test { 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] fn miri_test() { let mut list = List::default(); From 8470dcc04fd76b3a2a5cbf1959bf31f609d9ab52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:08:27 +0200 Subject: [PATCH 46/57] Fixed in order to build object files instead of archives --- userlib/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/userlib/Makefile b/userlib/Makefile index 79d7bd9..73d3ed9 100644 --- a/userlib/Makefile +++ b/userlib/Makefile @@ -1,7 +1,7 @@ TOPDIR = ../ include $(TOPDIR)/Makefile.rules -default: sys.a libnachos.a +default: sys.o libnachos.o clean: - $(RM) libnachos.a sys.a libnachos.o sys.o \ No newline at end of file + $(RM) libnachos.o sys.o \ No newline at end of file From 70d7893bed5a57ef636bc6dc0b1443b27f413c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:12:25 +0200 Subject: [PATCH 47/57] Moved userlib.rs back into ./userlib --- {src/kernel => userlib}/syscall.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src/kernel => userlib}/syscall.rs (100%) diff --git a/src/kernel/syscall.rs b/userlib/syscall.rs similarity index 100% rename from src/kernel/syscall.rs rename to userlib/syscall.rs From 69f91170f6a216afa438bc292460295d2af0cae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:34:06 +0200 Subject: [PATCH 48/57] Optimized to avoid cloning heap values --- src/kernel/exception.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index 0cf5921..de4defe 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -65,16 +65,12 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result Ok(MachineOk::Shutdown), SC_EXIT => { - match &system.get_thread_manager().g_current_thread { - Some(th) => { - let th = Rc::clone(th); - system.get_thread_manager().thread_finish(machine, th); - Ok(MachineOk::Ok) - }, - None => { - Err("Current thread is None".into()) - } - } + let th = match &system.get_thread_manager().g_current_thread { + Some(th) => th, + None => Err("Current thread is None".into()) + }?; + system.get_thread_manager().thread_finish(machine, th); + Ok(MachineOk::Ok) }, SC_EXEC => todo!(), SC_JOIN => todo!(), From 3685bb6590ea084a8b2467ef26772a5451bcf5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:41:56 +0200 Subject: [PATCH 49/57] Added general failure case in raise exception and removed break in main loop for system exceptions --- src/simulator/machine.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 123b43b..9baf651 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -227,7 +227,6 @@ impl Machine { } pub fn raise_exception(&mut self, exception: ExceptionType, address : u64, system: &mut System) -> Result{ - self.set_status(MachineStatus::SystemMode); // Handle the interruption match exception::call(exception, self, system) { @@ -235,7 +234,7 @@ impl Machine { self.set_status(MachineStatus::UserMode); return Ok(MachineOk::Shutdown); } - _ => () + _ => Err(format!("Syscall {:?} invalid or not implemented", exception))? } // todo: return error if the syscall code is invalid self.set_status(MachineStatus::UserMode); Ok(MachineOk::Ok) @@ -251,7 +250,7 @@ impl Machine { match self.one_instruction(system) { Ok(MachineOk::Ok) => println!("hello"), 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 } From b96808b55f51145086e36a723769d54f87ccba16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:44:43 +0200 Subject: [PATCH 50/57] Fixed incorrect flow control --- src/kernel/exception.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index de4defe..17599f2 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -67,9 +67,9 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result { let th = match &system.get_thread_manager().g_current_thread { Some(th) => th, - None => Err("Current thread is None".into()) - }?; - system.get_thread_manager().thread_finish(machine, th); + None => Err("Current thread is None")? + }; + system.get_thread_manager().thread_finish(machine, *th); Ok(MachineOk::Ok) }, SC_EXEC => todo!(), From 2756477e67208aa8d69f46839380845399ac29f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 13:49:32 +0200 Subject: [PATCH 51/57] Project now builds --- src/kernel/exception.rs | 6 +++--- src/simulator/machine.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index 17599f2..b020f6e 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -44,7 +44,7 @@ pub const SC_DEBUG: u8 = 34; pub const CONSOLE_OUTPUT: u8 = 1; // todo : returns new types, not just machine errors and machine ok -pub fn call(exception: ExceptionType, machine: &mut Machine, system: &mut System) -> Result { +pub fn call(exception: &ExceptionType, machine: &mut Machine, system: &mut System) -> Result { match exception { ExceptionType::NoException => todo!(), @@ -66,10 +66,10 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result Ok(MachineOk::Shutdown), SC_EXIT => { let th = match &system.get_thread_manager().g_current_thread { - Some(th) => th, + Some(th) => th.clone(), None => Err("Current thread is None")? }; - system.get_thread_manager().thread_finish(machine, *th); + system.get_thread_manager().thread_finish(machine, th); Ok(MachineOk::Ok) }, SC_EXEC => todo!(), diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 9baf651..166fbce 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -34,6 +34,7 @@ use super::error::MachineOk; /// Textual names of the exceptions that can be generated by user program /// execution, for debugging purpose. /// todo: is this really supposed to stand in machine.rs? +#[derive(Debug)] pub enum ExceptionType { /// Everything ok NoException, @@ -229,7 +230,7 @@ impl Machine { pub fn raise_exception(&mut self, exception: ExceptionType, address : u64, system: &mut System) -> Result{ self.set_status(MachineStatus::SystemMode); // Handle the interruption - match exception::call(exception, self, system) { + match exception::call(&exception, self, system) { Ok(MachineOk::Shutdown) => { self.set_status(MachineStatus::UserMode); return Ok(MachineOk::Shutdown); From 5a5c5a914176c6993621c36f6c0c15899ff372bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 5 Apr 2023 14:50:58 +0200 Subject: [PATCH 52/57] Doc and Makefile update --- Makefile | 1 - userlib/syscall.rs | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 9daf3b6..4adde13 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,6 @@ dumps: user_lib: $(MAKE) -C userlib/ - mv ${TOPDIR}/userlib/sys.a ${TOPDIR}/src/sys.a tests: user_lib $(MAKE) tests -C test/riscv_instructions/ diff --git a/userlib/syscall.rs b/userlib/syscall.rs index 14ceeb7..0f1befd 100644 --- a/userlib/syscall.rs +++ b/userlib/syscall.rs @@ -42,14 +42,18 @@ extern "C" { ///Stop Nachos, and print out performance stats fn Shutdown() -> (); - /// Return the time spent running Nachos + /// Return the time spent running BurritOS + /// ## Param + /// - **t** a struct to define the time unit fn SysTime(t: Burritos_Time) -> (); - /// This user program is done (status = 0 means exited normally). + /// This user program is done + /// ## Param + /// - **status** status at the end of execution *(status = 0 means exited normally)*. fn Exit(status: i32) -> (); - /// Run the executable, stored in the Nachos file "name", and return the - /// master thread identifier + /// Run the executable, stored in the BurritOS file "name", and return the + /// master thread identifier fn Exec(name: *const char) -> ThreadId; /// Create a new thread in the current process @@ -159,7 +163,7 @@ extern "C" { fn CondBroadcast(id: CondId) -> t_error; /////////////////////////////////////////////////////// - /// System calls concerning serial port and console /// + /// # System calls concerning serial port and console /////////////////////////////////////////////////////// ///Send the message on the serial communication link. From 81302b67a1ceee1c56bc6c9e7ae58fff36ef90c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 5 Apr 2023 14:51:50 +0200 Subject: [PATCH 53/57] Struct refractore --- userlib/syscall.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/userlib/syscall.rs b/userlib/syscall.rs index 0f1befd..0615261 100644 --- a/userlib/syscall.rs +++ b/userlib/syscall.rs @@ -1,7 +1,7 @@ use std::str::Chars; /// Define the BurritOS running time basic unit -pub struct Burritos_Time { +pub struct BurritosTime { seconds: i64, nanos: i64 } @@ -13,7 +13,7 @@ pub struct ThreadId{ /// The system call interface. These are the operations the BurritOS /// kernel needs to support, to be able to run user programs. -pub struct t_error{ +pub struct TError { t: i32 } @@ -45,7 +45,7 @@ extern "C" { /// Return the time spent running BurritOS /// ## Param /// - **t** a struct to define the time unit - fn SysTime(t: Burritos_Time) -> (); + fn SysTime(t: BurritosTime) -> (); /// This user program is done /// ## Param @@ -61,7 +61,7 @@ extern "C" { fn newThread(debug_name: *const char, func: i32, arg: i32) -> ThreadId; /// Only return once the the thread "id" has finished. - fn Join (id: ThreadId) -> t_error; + fn Join (id: ThreadId) -> TError; /// Yield the CPU to another runnable thread, whether in this address space /// or not. @@ -71,30 +71,30 @@ extern "C" { fn PError(mess: *const char) -> (); /// Create a BurritOS file, with "name" - fn Create(name: *const char, size: i32) -> t_error; + fn Create(name: *const char, size: i32) -> TError; /// Open the Nachos file "name", and return an "OpenFileId" that can /// be used to read and write to the file. fn Open(name: *const char) -> OpenFiledId; /// Write "size" bytes from "buffer" to the open file. - fn Write(buffer: *const char, size: i32, id: OpenFiledId) -> t_error; + fn Write(buffer: *const char, size: i32, id: OpenFiledId) -> TError; /// Read "size" bytes from the open file into "buffer". /// Return the number of bytes actually read -- if the open file isn't /// long enough, or if it is an I/O device, and there aren't enough /// characters to read, return whatever is available (for I/O devices, /// you should always wait until you can return at least one character). - fn Read(buffer: *const char, size: i32, id:OpenFiledId) -> t_error; + fn Read(buffer: *const char, size: i32, id:OpenFiledId) -> TError; /// Seek to a specified offset into an opened file - fn Seek(offset: i32, id: OpenFiledId) -> t_error; + fn Seek(offset: i32, id: OpenFiledId) -> TError; /// Close the file, we're done reading and writing to it. - fn Close(id: OpenFiledId) -> t_error; + fn Close(id: OpenFiledId) -> TError; /// Remove the file - fn Remove(name: *const char) -> t_error; + fn Remove(name: *const char) -> TError; //////////////////////////////////////////////////// /// system calls concerning directory management /// @@ -106,10 +106,10 @@ extern "C" { /// Destroy a repertory, which must be empty. /// Return a negative number if an error ocurred. - fn Rmdir(name: *const char) -> t_error; + fn Rmdir(name: *const char) -> TError; /// List the content of BurritOS FileSystem - fn FSList() -> t_error; + fn FSList() -> TError; /// Create a semaphore, initialising it at count. /// Return a Semid, which will enable to do operations on this @@ -118,13 +118,13 @@ extern "C" { /// Destroy a semaphore identified by sema. /// Return a negative number if an error occured during the destruction - fn SemDestroy(sema: SemId) -> t_error; + fn SemDestroy(sema: SemId) -> TError; /// Do the operation P() on the semaphore sema - fn P(sema: SemId) -> t_error; + fn P(sema: SemId) -> TError; /// Do the operation V() on the semaphore sema - fn V(sema: SemId) -> t_error; + fn V(sema: SemId) -> TError; /// Create a lock. /// Return an identifier @@ -133,34 +133,34 @@ extern "C" { /// Destroy a lock. /// Return a negative number if an error ocurred /// during the destruction. - fn LockDestroy(id: LockId) -> t_error; + fn LockDestroy(id: LockId) -> TError; /// Do the operation Acquire on the lock id. /// Return a negative number if an error ocurred. - fn LockAcquire(id: LockId) -> t_error; + fn LockAcquire(id: LockId) -> TError; /// Do the operation Release on the lock id. /// Return a negative number if an error ocurred. - fn LockRelease(id: LockId) -> t_error; + fn LockRelease(id: LockId) -> TError; /// Create a new condition variable fn CondCreate(debug_name: *const char) -> CondId; /// Destroy a condition variable. /// Return a negative number if an error ocurred. - fn CondDestroy(id: CondId) -> t_error; + fn CondDestroy(id: CondId) -> TError; /// Do the operation Wait on a condition variable. /// Returns a negative number if an error ocurred. - fn CondWait(id: CondId) -> t_error; + fn CondWait(id: CondId) -> TError; /// Do the operation Signal on a condition variable (wake up only one thread). /// Return a negative number if an error ocurred. - fn CondSignal(id: CondId) -> t_error; + fn CondSignal(id: CondId) -> TError; /// Do the operation Signal on a condition variable (wake up all threads). /// Return a negative number if an error ocurred. - fn CondBroadcast(id: CondId) -> t_error; + fn CondBroadcast(id: CondId) -> TError; /////////////////////////////////////////////////////// /// # System calls concerning serial port and console From cb25b09cffb921bd77773977894742b119f8e381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 5 Apr 2023 14:52:46 +0200 Subject: [PATCH 54/57] Documentation --- userlib/syscall.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/userlib/syscall.rs b/userlib/syscall.rs index 0615261..94c7c44 100644 --- a/userlib/syscall.rs +++ b/userlib/syscall.rs @@ -39,7 +39,7 @@ pub struct CondId{ extern "C" { - ///Stop Nachos, and print out performance stats + ///Stop BurritOS, and print out performance stats fn Shutdown() -> (); /// Return the time spent running BurritOS From 7179931224f0f183dbb101fbbb749afacf53d6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 5 Apr 2023 15:09:10 +0200 Subject: [PATCH 55/57] Makefile fixes --- Makefile | 7 ++++--- test/riscv_instructions/Makefile | 6 +----- .../syscall_tests/Makefile | 2 +- test/syscall_tests/halt | Bin 0 -> 19552 bytes .../syscall_tests/halt.c | 0 test/syscall_tests/prints | Bin 0 -> 19616 bytes .../syscall_tests/prints.c | 0 7 files changed, 6 insertions(+), 9 deletions(-) rename test/{riscv_instructions => }/syscall_tests/Makefile (93%) create mode 100755 test/syscall_tests/halt rename test/{riscv_instructions => }/syscall_tests/halt.c (100%) create mode 100755 test/syscall_tests/prints rename test/{riscv_instructions => }/syscall_tests/prints.c (100%) diff --git a/Makefile b/Makefile index 4adde13..cdbbde4 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ TOPDIR=. include $(TOPDIR)/Makefile.config -all: dumps user_lib tests +all: dumps user_lib instruction_tests # # Main targets # @@ -18,8 +18,9 @@ dumps: user_lib: $(MAKE) -C userlib/ -tests: user_lib - $(MAKE) tests -C test/riscv_instructions/ +syscall: user_lib + $(MAKE) build -C test/syscall_tests/ + $(RM) test/syscall_tests/*.o mkdir -p ${TOPDIR}/target/guac/ find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ \; diff --git a/test/riscv_instructions/Makefile b/test/riscv_instructions/Makefile index 029a205..7c9a691 100644 --- a/test/riscv_instructions/Makefile +++ b/test/riscv_instructions/Makefile @@ -2,22 +2,18 @@ build: make build -C boolean_logic/ make build -C jump_instructions/ make build -C simple_arithmetics/ - make build -C syscall_tests/ dumps: make dumps -C boolean_logic/ make dumps -C jump_instructions/ make dumps -C simple_arithmetics/ - make dumps -C syscall_tests/ tests: make tests -C boolean_logic/ make tests -C jump_instructions/ make tests -C simple_arithmetics/ - make tests -C syscall_tests/ clean: $(MAKE) clean -C boolean_logic/ $(MAKE) clean -C jump_instructions/ - $(MAKE) clean -C simple_arithmetics/ - $(MAKE) clean -C syscall_tests/ \ No newline at end of file + $(MAKE) clean -C simple_arithmetics/ \ No newline at end of file diff --git a/test/riscv_instructions/syscall_tests/Makefile b/test/syscall_tests/Makefile similarity index 93% rename from test/riscv_instructions/syscall_tests/Makefile rename to test/syscall_tests/Makefile index e528387..13adddc 100644 --- a/test/riscv_instructions/syscall_tests/Makefile +++ b/test/syscall_tests/Makefile @@ -10,7 +10,7 @@ tests: halt.guac prints.guac clean: $(RM) halt.o halt prints prints.o -TOPDIR = ../../.. +TOPDIR = ../.. include $(TOPDIR)/Makefile.rules $(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file diff --git a/test/syscall_tests/halt b/test/syscall_tests/halt new file mode 100755 index 0000000000000000000000000000000000000000..351625f7403bfeb9dfb536c54141c538b8d9d7fa GIT binary patch literal 19552 zcmeHPeQXrh5udwVdkHvTaPL#?l#3!HE{XAhvCsX@ zdvEXd_RfSTX{AWJ(%pMIZ{Ezj-n7M*>8LVd<1+1d<1+1d<1+1d<1+1d<1+1d<1+1zSIZ|jenc6 zX=(}KVf->#fxT&>%p#&5tV;IlUH!1D-{k6Bu6~=V|AecbaP`x!{!v#y7bxi+anUch z=%-xtQCEN5)xY5C=Ujbq$)R9LSG|iKcJ-TFeaqEvbM>Ea^%Jgs+SNbm>W{ekr(FF} zSAX2quXouQF806FPUjo%Bj6+8Bj6+8Bj6+8Bj6+8Bj6+8Bj6+Oe@7q`2+Wzy%Y$aq z)4`A)(9A6-XZtq|fHqY?Tgavj;&%f>*64gTot_WD!hY~-&4D21YW$7>ZNc2KoXpKn z6J!L<=92}p=}h5u!=lWfLBsfHoAkm;1F~uj$~=Sn4Fd%!b2N}KYA6I6E{^`+8Uow4=HIAyAB&OtS64Yg2))y*H5z#w#A78EWapgFWUrNYELF#G_dZ4)>`g& zyua{^xy!j%uCY%rR=jW81|78at3{f^lJSKf2pmG-Wqi*Xd5hu)W% z=F>_ci`Rs`+L0HSDF3YD_tNLtHo4zp1)dN5YVE&f;g8P!h+)6u;BE-njI#?Hx8Eb4 z7Lq$sW54B=OS=8{qTC?cd;_`V{-u12p}WUVP@b)i4kH zuVT&RlTO?n=D5=Z_V#n^FU+44{vt7h-b$apjvS;Tuhk&0%_6VOW{g@g8>iSWX3Z^A z$d~%8xp``q^Ghi|(W0Bm8UN#4WB*d(f_=Hp7)|cUPxBtBb?V4HH7eKMc%4mr9$=kV zugIgw=fF_se1W{ABM)fK-j{NYURWsSXt1GZQ%9aLL@bx(9k*>|ew!J@dBJ-^Azi6-BQ=+3SM_6 zpJzW*XHdyUGw`R^w^<^WUZ(MH0w-ZxCf_UhaX!iMLA-w--^8-qF*1C98@*Zs?6;jM zg!1`i8RIC~A0pmy4}BVsi5x8MdutqCllZ(Tm&G=k;P2md(j)7nki}zC7T@>QIJ~by zmKo3y`}maB6M(&ISqJBSUORt^I6N=n3)tr8SAs72fY0%)vtFLx;LLY&r_95xb6hL1 zyvh6XA9BsHK;3Z#vAGzrxdgE}E%s&0*p#_>VhZQ&G<;&(J_6mF2CmqLg+0?O(|(up zT5dj0M{gJLDtu;K>?5$h;+$Q~EAvoWaPp3Po!3?`Z{}I>8*M@R$VJ`hPyYEL$$r|H zeCWLDH`PwQb&-ajJ%4Q_>Wz%i7QmkVBr{YS%$zrZA>=&viOk?&P}uSt1OFD|*ze#u zzl22F7*Rou4;xCaE){(sn+7UD#-t6EckX^~NCTpuuZi zoZK>HAO1IC%%Illy3yXR#6D!Wt~IP$`|vc{v|-ofZ^OKAl;Qq5aOeEFMi=?Y{v4RY z_vSLj2%ToU8yW90h4)wqZ$+1Qx6TbS-fJdiEAUQduNLJo*5XVXn45f=amGBx8Tsz! zaYnu^;%r>4#JMC>%6D*1ud2YSd1?lEcGhgrS$_!oGRHN66PwuInbSjALhi?Ttj}c5 zpVNwc&UcD#zl5`D_1LV4nY6JKdMo{DFJ>XTiag7s;ud~^8Bi;ZoO6w zbI888OeV*AldKKxmknL!a|6%W97m(o_t~op^;WfYK+kN3_gBg1XJ6z*hQ#yd=ZK%Q zjGwhqr}WKFi6Pkbg~U)*ISa)Q*UP||>wI7)?M%>Qj$=sSaMVCeP{n6%E|2i@!50@p zpE(w&M#jPoa*nJYZz{Hck*qhw`vg&U7V9YcnDHU<^t35zm;vY6V=7e4p^bzr^!7&M+S58XxbPG`wrlV1uD-xC9%P!iJ@=p&s>Q&TKvd{bSHS0sZd> zp#wHT?-tl$=sNW0pg#xwcrIl9Tq6&Br1a-9HR(FmbvgIK-`wv9WUZ8_v!}DD6%ut$ z?JMG}Ef>^)CCdrb)>EbiH6>&WHSzm5`je`Im%;XBuziKH{bSf(2ixml`%=vPI8;lR zEA`8{>2re4_FQ;np6yXM+zMH@Le^3xYaY)#Sg&~h5Rh}N-#hPv`auUjzw;A+D};3F zUp@jp0zLvh0zLvh0zLvh0zLvh0$&mY?ml#jurwSFi}vmw*)A4$L=D{sIy>(ny1LY& z4{ovOspaJ#H?3hw`Iwt``?AWhanM@UKv6Q*V;`hI7+t--CV6mUb8KCrslAK8_V8B+ zzG&Olt=|ea>|Ga)ZiqIoZ)&=4^F87F)-|qcY{I-7T^j$QfmO+&Q4qw+0gZpvz^X>q zD}{if$zL)k8{^+8(CMT3G9qs9&+51;?P0vD@qZQcpv%ryo{me(skHx2j4}V4i!5fN zx8?RyBl^|kJ96q*Sj=9$HlSAzJD+MPl0?T+^m-3{JLtDT?=g)zh#nW;M316nIY%r- zP|Xhny%OgR&{@tUB?ph1;@U6x19Zxg_s;i|ihj~VKcwhuJ@g+7dL?fCivMxXx}I0` zeI7Z-6#e@i`Y%9d`^Q3ZfN|mLBtG?^TOOQW6Z8PJS?IW~Q|L2pS1lJ2-8b-I`G-6QAUptC)#WC;n* zzF$)GMYWQCLW~k!LCbbtl4M0iBlHHS*&}}m=qx{sza`@91n&9zilVO#T6{|m&UYyK z31v@Cj1sK|o%N2iD1y_#6{@Xwt&oE+%VCr)`y@eN6r~Ruk_oq z3(!ZEoC{LCl1}uFq91E1l0;`*(SPfqzpLmekDPxfy5-@|g3kDF(c}atUOrO%Z+ql? zqWBl7eDbEShGJGk&d0INHRs;?FW0h z6UkV2Y7gy;bfz%8E7i9nYDZ%SqqIG4?{AIvq>}MIaHis&@!n{X9^AP-){~<4Jspu$ z1oTKM9;5HYqMaSIBia?myax_NZHgw6@lM(r@9x+c+uI%Kq{ou6R1_?c4oqSb+M$-( zqp9ej6n!@l?WUc5J-cFEQ4B+;9Z8AV_b20#4m$#k565HO!ltd54N-C->ZZHBE81lz z`ejYKKln)e#Csh99q;OjVxzu*Yb9jBRSB=7 z}tdvs+2?-5jSZ|QWpAsD~F%iSih4W9r|lLfQ#{QU(CywyDi!-hs3v&Cl<*9PSk@- rG2+<&HO0&2AMCHV#b7_syyMe>T$XqU+o(sam0mv#XK0n4P^o{^+QQx?f>8+13 z=<@sGZqc3YA-7A^|)4G1E)1+KCSr$Pc8F~z@8Rh`Yn@1eWhBg z81o0%AzqpUmuLIgN*@?3>=7DwnH2>gRoG~BiFX`G%KEak;lZmG_%zM7MR_;4m zU+jz73;E|S)1Dx#Xx)@MRq#45m3R_M!Wa91;}C=_;d@Fe7&MOefz7&%nCsQ&-(GZ# zXDhfaniJM)TY+OD_h*fLFZMk7Cf0kjNaKNDz4>Mi`_b+XYvvzq+%>M7aCTth-1ms5 z`ScFgnXftZGS&QBNw1%LzKY(;{U!Gn#giVQ*r;4P!X&GW`OQF~k;hPIvdCMG`^ZAK zy!j->Uo9PZznK?4JNJgre@HPemE#8MSx2!Z?jd&^Ud2vf4TlcfF;uCa=8MlPwF<^z z{bj5<_M{zm2Pp1Tj=lL)+Ak!Z=lexq2D{aJ{t9xCio8~byf%ZpHj~xrnI4{`eKDhN zoJ77pl22U)!Vs}sk$0TFRqWer2ImE>!Rkq@ z1#(0atpUy~_(;A%kKBi_kNtpsF&peJEOF;O;e*Qe&P2EHp~m{dc4eL-`(#_#8d*m3 z&K3%^59JwD-lJLUr<0ovo=Y#Vv9ALs?pwCdFXVAPiTfG6e;?aGx|}gGbY?Sqp$^z@ zK2Z!73QMxuA!dGnct;=h6uQTAFz@%**|IvL^QKZ4`KUvFVDmATu47ym-4nW~-(P3T zz5rdiPettGQ=X3x{;nY#l>2G!^eN%+B#$p(TbNq`zK{bxM{@RjX?&AC-p-vO54X=! ztw8!F?kaphHOD-4$3?{ELd51G#O4%VmyM&7dh7Tk&f6*Mi7E3SY;PF6XddAHOp#9W zEy`>8xi~wtoX0EQGh=)mf&E4M>>^o_hdTTdUnw-YeRa!bpMbp9;WrPSQ*Ci^i!S_I1RH?y9<7O&EzGV#g~W96xtND>rUqwoy#_#_A$@HPr$#>IMsy; z#b-97%^fEn59To5p>s2I@-tufI&nn9eHDHe=5(A%^316Aoz7neHVVcBHEnL4mO&kq zx$MTtsZ-F{f8*LTYOUDS)_w)nAxm|wX4IPprqHG}v$1d^#(k{<_mjY#^5<%m=PUC% zFvs4T&1%E!IN=>8yhkP8qh-7$U*O$7J4AS|9-pbgJDs~!(nnbHGi`8o;yJ<@;|OQu zyKBc8`L=|!cBvZYvQDAj#yP#R3a^&QY2?`%y-6keL9ELx)dY5IVtuENAI>r4ew@eZ zboR_?r9@M{lYH}8oK>qvXL!t{wZ*VoyH) z&GE-R%o6@B<5M>N)wXi&X+JadOaA7(6iSy z;8&fCu5H{%y&IdF<79n}y?c?@91e`j&pBmWsJ@_c1aaA1vCk+UuBI5OF{gJb^Q*F| z{cT6tWvKGojL8ZX*$Pkn#T-}pFv(j;`#GB z;wLTQXN|Ba_U5O=5PbVwVyLE``C^FbWnfHoJ}?u0CfG!tVo2g}NJC9fW6xY$9--%h z&o72Pb1bkr5erwzIih~Nrq}{TqTb-|6L{TOs-w(jv=5M{r*vM!4BF2g3-Ro+NIrX9 z#`_~b-XHl<%c=AZN^cp(XPoL4Iy14?RYh-Err5PNYEjDb^xS}0$e>1_q`Db3Z~H8r z#mf4@8LCyq`-G?7=FjIi!{|QM_;}Z(;9ZjfA2jL1dHApxJ}ib00o0Ruz2yY#kHY>q z?7!=W4fqJV8{vnhs<5Aj{XFdBxsdErjXd~~w4cw`r5nlCh5S>0alRiAwNj$doXVkA zNHp5DFORd1yk7y9q$gM(VA(p4kV#b6(PmF6965FZ;dG0LDWvy&L5JQ-rkZT^<4+0v-Y$0v-Y$0v-Y$0v-Y$0{>?O zZr!(ldk_kRczbJ~XczJxV@hn^guk>(-pb{Hl6*ouKqe#zlF7}1}houGxsuI2&5XQOYU9Y5?z~U?u^mbF8b=i z7u&pP(>Fp*yVqLQomR`b=H@$EZwuYAHoP|6jB!`L6#7L3qgqB`elV+VDDJ(7Q=!5}gA zy4W5p47!$nTTft_LE@!r1E>J}e59?!;>2B&A8_%%3;vC;`;206xd-_-W7LwKgMux& zjCFE;HO{-hCq3t-9z25bE5_x0>}5mr?e9LxKjz{;Ect6({6{&z8n?%#{DZD}9g_TR zm!4-O{|7Gq5cuT(Xi(hPiauSxz$XBHw+rW&IN!%Q3=od%SD*>EONN69^0)Yq{(XJ} z6l0_Oo3R{Pl5aO8LpHyc{4UqL{w(>eh7^>|N#Gs8j(*jsyzv(9lYZ5u=bzw{KkZD& z+w1wd{UVmO!}cSyc#yRj(vgy%t@7%(h{B_;ouT(3tY|3^~Km)j&m zHW?{z=M8(^4@&u0j7s^e>%l>A@1_8TIHg2Ct`PW@~ zE=u_ZnNMEf-Y`~_@`*Odu$#X9ec?E}WgqK_?(B`2-SNJ#$x_`(E7G++6-lO8Z|B~= z-b6Cmo7%;ALjw1u_HVOHE4tTWTjSqm zwp%gVXEI*8-L)r{fQV4u18c%cEWz%LMG~wNHVKpa*`}U&AI%|3bL7qu4%@6AD*}G6 z)qfv{kZteYlj@51+lpYC`_N~lxRY(>5BEfq7K=sTb;sSwWIW04eW)v%B*Ql9!fW_I zu09YUlNN`y)9US_sYv&?#b{u=wR6vIaIJ^9ygf}?nmvgGmZk%`<$7Wnx04PQ?%N+r zMRuZ1B}Lm^qW1T(FrQ&K8RurhyaEeHQmJHg=bn^>`(`{Av#?OteXW27Y*kioYceDe z5N+xAp(INVaQfArQeGZUHl?e Date: Wed, 5 Apr 2023 15:09:10 +0200 Subject: [PATCH 56/57] Makefile fixes --- test/syscall_tests/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/syscall_tests/Makefile b/test/syscall_tests/Makefile index 13adddc..40e1364 100644 --- a/test/syscall_tests/Makefile +++ b/test/syscall_tests/Makefile @@ -1,5 +1,5 @@ -PROGRAMS = halt prints +PROGRAMS = halt.guac prints.guac build: $(PROGRAMS) @@ -8,9 +8,9 @@ dumps: halt.dump prints.dump tests: halt.guac prints.guac clean: - $(RM) halt.o halt prints prints.o + $(RM) halt.o prints.o TOPDIR = ../.. include $(TOPDIR)/Makefile.rules -$(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o \ No newline at end of file +$(PROGRAMS): %.guac : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o From 77086155b5ecc5802475669efeabaa1d5ef78a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 5 Apr 2023 15:47:46 +0200 Subject: [PATCH 57/57] started to implement sc_sem_create and auxiliar function --- src/kernel/exception.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs index b020f6e..bb99263 100644 --- a/src/kernel/exception.rs +++ b/src/kernel/exception.rs @@ -105,7 +105,13 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result todo!(), SC_P => todo!(), SC_V => todo!(), - SC_SEM_CREATE => todo!(), + SC_SEM_CREATE => { + let addr_name = machine.read_int_register(10); + let initial_count = machine.read_int_register((11)); + let size = get_length_param(addr_name as usize, machine); + Ok(MachineOk::Ok) + + }, SC_SEM_DESTROY => todo!(), SC_LOCK_CREATE => todo!(), SC_LOCK_DESTROY => todo!(), @@ -129,6 +135,17 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result usize{ + let mut i = 0; + let mut c = 1; + while c!= 0 { + c = machine.read_memory(1, addr + i); + i+=1; + + } + i + 1 +} + #[cfg(test)] mod test { use crate::kernel::exception::{SC_SHUTDOWN, SC_WRITE};