diff options
author | David Li <li.davidm96@gmail.com> | 2016-01-07 10:34:36 -0700 |
---|---|---|
committer | David Li <li.davidm96@gmail.com> | 2016-01-07 10:34:36 -0700 |
commit | 6f92b9ccda52387f0ab6dbfcc0d0b1bed742e9d4 (patch) | |
tree | 439cd06ad947099fba6b878fd776258ad4a7a446 | |
parent | 7a3dae00d742394a114a9fafbdf25f08cd458ce4 (diff) |
Let API user handle syscalls
-rw-r--r-- | src/lib.rs | 70 | ||||
-rw-r--r-- | src/register_file.rs | 40 | ||||
-rw-r--r-- | src/simulator.rs | 64 | ||||
-rw-r--r-- | src/syscall.rs | 23 | ||||
-rw-r--r-- | src/trap.rs | 36 |
5 files changed, 164 insertions, 69 deletions
@@ -20,7 +20,10 @@ extern crate elfloader32 as elfloader_lib; pub mod isa; pub mod binary; pub mod memory; +pub mod register_file; pub mod simulator; +pub mod syscall; +pub mod trap; pub use elfloader_lib as elfloader; @@ -31,6 +34,42 @@ fn test_elfloader() { use std::rc::Rc; use std::cell::RefCell; + use memory::MemoryInterface; + + struct SyscallHandler<'a> { + memory: memory::SharedMemory<'a>, + } + + impl<'a> syscall::SyscallHandler for SyscallHandler<'a> { + fn syscall(&mut self, registers: &mut register_file::RegisterFile) -> Option<trap::Trap> { + println!("Syscall number {}", registers.read_word(isa::Register::X10)); + let mut base = registers.read_word(isa::Register::X11); + let mut string = vec![]; + + loop { + let c = self.memory.borrow_mut().read_byte(base); + + if let Ok(0x00) = c { + break; + } + else if let Ok(c) = c { + string.push(c); + } + + base += 1; + } + + let result = std::str::from_utf8(&string); + if let Ok(string) = result { + println!("{}", string); + } + else { + println!("Error printing string: {:?}", result); + } + None + } + } + let mut f = File::open("../riscv/kernel").unwrap(); let mut buffer = Vec::new(); @@ -39,27 +78,18 @@ fn test_elfloader() { let elf = elfloader::ElfBinary::new("test", &buffer).unwrap(); let start = elf.file_header().entry as isa::Address; - let mut text = None; - let mut data = None; - for p in elf.section_headers() { - if p.name.0 == 0x1b { - text = Some((elf.section_data(p), p.addr)); - } - else if p.name.0 == 0x33 { - data = Some((elf.section_data(p), p.addr)); - } - } - - let (text, text_offset) = text.unwrap(); - let (data, data_offset) = data.unwrap(); - let mmu = memory::IdentityMmu::new(); let mmu2 = memory::ReverseMmu::new(0x8000); let mut memory = memory::Memory::new(0x10000); - memory.write_segment(&mmu, text, text_offset as usize); - memory.write_segment(&mmu, data, data_offset as usize); - memory.write_segment(&mmu2, text, text_offset as usize); - memory.write_segment(&mmu2, data, data_offset as usize); + + for p in elf.section_headers() { + let name = elf.section_name(p); + if name == ".text" || name == ".sdata" || name == ".rodata" { + println!("Loading {} section", name); + memory.write_segment(&mmu, elf.section_data(p), p.addr as usize); + memory.write_segment(&mmu2, elf.section_data(p), p.addr as usize); + } + } let memory_ref = Rc::new(RefCell::new(memory)); let cache = memory::DirectMappedCache::new(4, 4, memory_ref.clone()); @@ -71,7 +101,9 @@ fn test_elfloader() { start, 0x3000, cache_ref.clone(), Box::new(mmu2)); let cores = vec![core, core2]; - let mut simulator = simulator::Simulator::new(cores, memory_ref.clone()); + + let system = SyscallHandler { memory: memory_ref.clone(), }; + let mut simulator = simulator::Simulator::new(cores, memory_ref.clone(), system); simulator.run(); } diff --git a/src/register_file.rs b/src/register_file.rs new file mode 100644 index 0000000..6437eed --- /dev/null +++ b/src/register_file.rs @@ -0,0 +1,40 @@ +// Copyright 2016 David Li +// This file is part of rustv. + +// rustv is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// rustv is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with rustv. If not, see <http://www.gnu.org/licenses/>. + +use isa; + +pub struct RegisterFile { + registers: [isa::Word; 32], +} + +impl RegisterFile { + pub fn new() -> RegisterFile { + RegisterFile { + registers: [0; 32], + } + } + + pub fn write_word<T: Into<isa::Register>>(&mut self, reg: T, value: isa::Word) { + // TODO: should be safe to use unchecked index + let reg = reg.into(); + if reg == isa::Register::X0 { return; } + self.registers[reg.as_num()] = value; + } + + pub fn read_word<T: Into<isa::Register>>(&mut self, reg: T) -> isa::Word { + self.registers[reg.into().as_num()] + } +} diff --git a/src/simulator.rs b/src/simulator.rs index 073de67..d1c4aae 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -16,10 +16,9 @@ use isa; use memory::{MemoryInterface, MemoryError, Mmu, SharedMemory}; - -struct RegisterFile { - registers: [isa::Word; 32], -} +use register_file::RegisterFile; +use syscall::SyscallHandler; +use trap::Trap; pub struct Core<'a>{ pc: isa::Address, @@ -32,47 +31,10 @@ pub struct Core<'a>{ stall_count: u32, } -pub struct Simulator<'a> { +pub struct Simulator<'a, T: SyscallHandler> { cores: Vec<Core<'a>>, memory: SharedMemory<'a>, -} - -#[derive(Debug)] -enum Trap { - IllegalInstruction { - address: isa::Address, - instruction: isa::Instruction, - }, - IllegalRead { - address: isa::Address, - instruction: isa::Instruction, - memory_address: isa::Address, - }, - IllegalWrite { - address: isa::Address, - instruction: isa::Instruction, - memory_address: isa::Address, - memory_value: isa::Word, - } -} - -impl RegisterFile { - fn new() -> RegisterFile { - RegisterFile { - registers: [0; 32], - } - } - - fn write_word<T: Into<isa::Register>>(&mut self, reg: T, value: isa::Word) { - // TODO: should be safe to use unchecked index - let reg = reg.into(); - if reg == isa::Register::X0 { return; } - self.registers[reg.as_num()] = value; - } - - fn read_word<T: Into<isa::Register>>(&mut self, reg: T) -> isa::Word { - self.registers[reg.into().as_num()] - } + syscall: T, } impl<'a> Core<'a> { @@ -93,7 +55,7 @@ impl<'a> Core<'a> { } } - fn step(&mut self, inst: isa::Instruction) { + fn step(&mut self, inst: isa::Instruction, system: &mut SyscallHandler) { let pc = self.pc; self.cycle_count += 1; @@ -363,8 +325,9 @@ impl<'a> Core<'a> { }, isa::opcodes::SYSTEM => match inst.i_imm() { 0x0 => { - // System call - println!("System call {}:", self.registers.read_word(isa::Register::X10)); + if let Some(trap) = system.syscall(&mut self.registers) { + self.trap(trap); + } } _ => { @@ -383,13 +346,14 @@ impl<'a> Core<'a> { } } -impl<'a> Simulator<'a> { - pub fn new(cores: Vec<Core<'a>>, memory: SharedMemory<'a>) - -> Simulator<'a> { +impl<'a, T: SyscallHandler> Simulator<'a, T> { + pub fn new(cores: Vec<Core<'a>>, memory: SharedMemory<'a>, syscall: T) + -> Simulator<'a, T> { // TODO: initialize GP, registers (GP is in headers) Simulator { cores: cores, memory: memory, + syscall: syscall, } } @@ -405,7 +369,7 @@ impl<'a> Simulator<'a> { let inst = self.memory.borrow_mut().read_instruction(pc); if let Some(inst) = inst { - core.step(inst); + core.step(inst, &mut self.syscall); } else { // TODO: trap diff --git a/src/syscall.rs b/src/syscall.rs new file mode 100644 index 0000000..41a0fcd --- /dev/null +++ b/src/syscall.rs @@ -0,0 +1,23 @@ +// Copyright 2016 David Li +// This file is part of rustv. + +// rustv is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// rustv is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with rustv. If not, see <http://www.gnu.org/licenses/>. + +use register_file::RegisterFile; +use trap; + +pub trait SyscallHandler { + // Can't take cache because syscall can't stall + fn syscall(&mut self, registers: &mut RegisterFile) -> Option<trap::Trap>; +} diff --git a/src/trap.rs b/src/trap.rs new file mode 100644 index 0000000..bb7a808 --- /dev/null +++ b/src/trap.rs @@ -0,0 +1,36 @@ +// Copyright 2016 David Li +// This file is part of rustv. + +// rustv is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// rustv is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with rustv. If not, see <http://www.gnu.org/licenses/>. + +use isa; + +#[derive(Debug)] +pub enum Trap { + IllegalInstruction { + address: isa::Address, + instruction: isa::Instruction, + }, + IllegalRead { + address: isa::Address, + instruction: isa::Instruction, + memory_address: isa::Address, + }, + IllegalWrite { + address: isa::Address, + instruction: isa::Instruction, + memory_address: isa::Address, + memory_value: isa::Word, + } +} |