Add memory and register checking when required in the VM

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-02-09 14:10:02 -05:00
parent f1ed41f98b
commit 00027c4542
4 changed files with 71 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
use crate::vm::{error::*, flags::*, mem::*, reg::*};
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use byteorder::{WriteBytesExt, LE};
use std::{io::Cursor, mem};
pub type Word = u64;
@@ -18,7 +18,6 @@ impl Vm {
}
pub fn mem_cursor(&self, at: usize) -> MemCursor {
// TODO : MemCursor
MemCursor::new(&self.mem[at..])
}
@@ -37,59 +36,62 @@ impl Vm {
self.flags().contains(Flags::HALT)
}
pub fn get_word(&self, addr: Word) -> Word {
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
reader
.read_u64::<LE>()
.expect("word outside of address range")
pub fn get_word(&self, addr: Addr) -> Result<Word> {
self.check_read(addr, 8)?;
Ok(self.mem_cursor(addr as usize).next_u64().unwrap())
}
pub fn get_halfword(&self, addr: Word) -> HalfWord {
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
reader
.read_u32::<LE>()
.expect("word outside of address range")
pub fn get_halfword(&self, addr: Addr) -> Result<HalfWord> {
self.check_read(addr, 4)?;
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
}
pub fn get_byte(&self, addr: Word) -> u8 {
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
reader.read_u8().expect("word outside of address range")
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
self.check_addr(addr)?;
Ok(self.mem_cursor(addr as usize).next_u8().unwrap())
}
pub fn set_word(&mut self, addr: Word, value: Word) {
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
writer
.write_u64::<LE>(value)
.expect("word outside of address range");
pub fn set_word(&mut self, addr: Addr, value: Word) -> Result<()> {
self.check_read(addr, 8)?;
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
Ok(cursor.write_u64::<LE>(value).unwrap())
}
pub fn set_halfword(&mut self, addr: Word, value: HalfWord) {
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
writer
.write_u32::<LE>(value)
.expect("word outside of address range");
pub fn set_halfword(&mut self, addr: Addr, value: HalfWord) -> Result<()> {
self.check_read(addr, 4)?;
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
Ok(cursor.write_u32::<LE>(value).unwrap())
}
pub fn set_byte(&mut self, addr: Word, value: u8) {
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
writer
.write_u8(value)
.expect("word outside of address range");
pub fn set_byte(&mut self, addr: Addr, value: u8) -> Result<()> {
self.check_addr(addr)?;
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
Ok(cursor.write_u8(value).unwrap())
}
pub fn load(&self, reg: Reg) -> Word {
self.get_word(self.get_reg(reg))
pub fn load(&self, reg: Reg) -> Result<Word> {
self.get_word(self.get_reg_checked(reg)?)
}
pub fn store(&mut self, reg: Reg, value: Word) {
let addr = self.get_reg(reg);
self.set_word(addr, value);
pub fn store(&mut self, reg: Reg, value: Word) -> Result<()> {
let addr = self.get_reg_checked(reg)?;
self.set_word(addr, value)
}
pub fn get_reg_checked(&self, reg: Reg) -> Result<Word> {
self.check_reg(reg)?;
Ok(self.get_reg(reg))
}
pub fn get_reg(&self, reg: Reg) -> Word {
self.registers[reg as usize]
}
pub fn set_reg_checked(&mut self, reg: Reg, value: Word) -> Result<Word> {
self.check_reg(reg)?;
Ok(self.set_reg(reg, value))
}
pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word {
mem::replace(&mut self.registers[reg as usize], value)
}
@@ -119,4 +121,25 @@ impl Vm {
pub fn set_flags(&mut self, flags: Flags) {
self.set_reg(FLAGS, flags.bits());
}
fn check_addr(&self, addr: Addr) -> Result<()> {
if addr >= (self.mem.len() as u64) {
Err(VmError::MemOutOfBounds { addr })
} else {
Ok(())
}
}
fn check_read(&self, addr: Addr, len: Word) -> Result<()> {
self.check_addr(addr)
.and_then(|_| self.check_addr(addr + len - 1))
}
fn check_reg(&self, reg: Reg) -> Result<()> {
if reg > LAST_REG {
Err(VmError::IllegalReg { reg })
} else {
Ok(())
}
}
}