From bf83601cdf04fd475760d6c85bbb81c2f83a4e85 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Wed, 4 Mar 2020 16:41:37 -0500 Subject: [PATCH] Add interrupt struct and IVT reader Signed-off-by: Alek Ratzloff --- src/libvm/src/interrupt.rs | 31 ++++++++++++++++++++++++++++ src/libvm/src/obj/assemble.rs | 17 +++++++-------- src/libvm/src/obj/assemble/error.rs | 1 + src/libvm/src/state.rs | 32 ++++++++++++++++++++++++++++- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/libvm/src/interrupt.rs b/src/libvm/src/interrupt.rs index aa92f3c..45d4e43 100644 --- a/src/libvm/src/interrupt.rs +++ b/src/libvm/src/interrupt.rs @@ -1,3 +1,5 @@ +use crate::addr::Addr; + macro_rules! interrupts { { $($variant:ident = $value:expr),* $(,)? @@ -17,3 +19,32 @@ interrupts! { ILLEGAL_MEMORY_ADDRESS = 2, HARDWARE_EVENT = 3, } + +pub const IVT_LENGTH: usize = 512; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Interrupt(u64); + +const ENABLED_MASK: u64 = 0x8000_0000_0000_0000; +const ADDR_MASK: u64 = 0x07ff_ffff_ffff_ffff; + +impl Interrupt { + pub fn enabled(&self) -> bool { + (self.0 & ENABLED_MASK) != 0 + } + + pub fn set_enabled(&mut self, enabled: bool) { + let enabled = (enabled as u64) << 63; + self.0 |= enabled; + } + + pub fn addr(&self) -> Addr { + Addr((self.0 & ADDR_MASK) << 5) + } + + pub fn set_addr(&mut self, addr: Addr) { + let addr = (addr.0 >> 5) & ADDR_MASK; + self.0 &= !ADDR_MASK; + self.0 |= addr; + } +} diff --git a/src/libvm/src/obj/assemble.rs b/src/libvm/src/obj/assemble.rs index 7d631f0..f9f44b2 100644 --- a/src/libvm/src/obj/assemble.rs +++ b/src/libvm/src/obj/assemble.rs @@ -58,31 +58,32 @@ impl Asm for DataSection { fn assemble(&self, session: &mut AsmSession) -> Result { let names = names::get_section_names(self)?; session.name_stack.push(names); - let section_len = self.len() as u64; + let content_len = self.len() as u64; let (start, end) = match self.org { - SectionOrg::Start(start) => (start, start + (section_len as u64)), + SectionOrg::Start(start) => (start, start + (content_len as u64)), SectionOrg::StartEnd(start, end) => (start, end), }; session.pos = Addr(start); if start > end { return Err(AsmError::StartGreaterThanEnd { start, end }); } - let len = end - start - 1; - if len > section_len { + let len = end - start; + if content_len > len { return Err(AsmError::SectionTooShort { + name: self.name.clone(), section_end: end, - section_size: start + section_len, + section_size: start + content_len, }); } - let mut contents = Vec::with_capacity(section_len as usize); + let mut contents = Vec::with_capacity(content_len as usize); for line in self.lines.iter() { contents.extend(line.assemble(session)?); session.pos += line.len(); } assert_eq!( contents.len() as u64, - section_len, + content_len, "in section {}", self.name ); @@ -90,7 +91,7 @@ impl Asm for DataSection { Ok(obj::DataSection { name: self.name.clone(), start, - len: section_len, + len: content_len, contents, }) } diff --git a/src/libvm/src/obj/assemble/error.rs b/src/libvm/src/obj/assemble/error.rs index a1f0e03..0ddc932 100644 --- a/src/libvm/src/obj/assemble/error.rs +++ b/src/libvm/src/obj/assemble/error.rs @@ -51,6 +51,7 @@ pub enum AsmError { section_size ))] SectionTooShort { + name: String, section_end: u64, section_size: u64, }, diff --git a/src/libvm/src/state.rs b/src/libvm/src/state.rs index a09abe0..81cd3a8 100644 --- a/src/libvm/src/state.rs +++ b/src/libvm/src/state.rs @@ -1,4 +1,5 @@ -use crate::{addr::*, error::*, flags::*, inst::*, mem::*, obj::obj::*, reg::*}; +use crate::{addr::*, error::*, flags::*, inst::*, interrupt::*, mem::*, obj::obj::*, reg::*}; +use std::mem; pub struct State { regs: [u64; NUM_REGS], @@ -47,6 +48,10 @@ impl State { Ok(()) } + //////////////////////////////////////////////////////////////////////////////// + // Memory + //////////////////////////////////////////////////////////////////////////////// + pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> { let mut cursor = MemCursor::new(self.mem.as_slice()); cursor.set_position(addr); @@ -131,6 +136,31 @@ impl State { self.set_reg_unchecked(FLAGS, flags.bits()); } + //////////////////////////////////////////////////////////////////////////////// + // Interrupts + //////////////////////////////////////////////////////////////////////////////// + pub fn ivt(&self) -> Result<&[Interrupt]> { + let ivt_addr = self.get_reg_unchecked(IVT); + if ivt_addr % 64 != 0 { + panic!("illegal IVT address {:#x}; must be divisible by 64", ivt_addr); + } + + let start = ivt_addr as usize; + let end = start + (IVT_LENGTH * mem::size_of::()); + + if end > self.mem.len() { + return Err(VmError::MemOutOfBounds { addr: Addr(ivt_addr) }); + } + + // This is safe because we check the bounds above + let slice_ptr = (&self.mem[start..]).as_ptr(); + let slice = unsafe { + std::slice::from_raw_parts(slice_ptr as *const Interrupt, IVT_LENGTH) + }; + + Ok(slice) + } + //////////////////////////////////////////////////////////////////////////////// // Execution ////////////////////////////////////////////////////////////////////////////////