Add memory and register checking when required in the VM
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
use crate::vm::vm::*;
|
use crate::vm::{vm::*, reg::Reg};
|
||||||
use snafu::Snafu;
|
use snafu::Snafu;
|
||||||
|
|
||||||
#[derive(Snafu, Debug, Clone)]
|
#[derive(Snafu, Debug, Clone)]
|
||||||
pub enum VmError {
|
pub enum VmError {
|
||||||
|
#[snafu(display("illegal register: 0x{:02x}", reg))]
|
||||||
|
IllegalReg { reg: Reg },
|
||||||
|
#[snafu(display("memory address out of bounds: 0x{:016x}", addr))]
|
||||||
MemOutOfBounds { addr: Addr },
|
MemOutOfBounds { addr: Addr },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ impl<'a> Assemble<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.symbols.globals_mut().extend(exports);
|
self.symbols.globals_mut().extend(exports);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +150,8 @@ impl<'a> Assemble<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO : make sure we aren't trying to export anything that doesn't exist
|
||||||
|
|
||||||
// only return exports if specified
|
// only return exports if specified
|
||||||
if export {
|
if export {
|
||||||
labels.retain(|k, _| exports.contains(k));
|
labels.retain(|k, _| exports.contains(k));
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ impl Vm {
|
|||||||
($mapping:expr) => {{
|
($mapping:expr) => {{
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
let value = ($mapping)(self.get_reg(r1), self.get_reg(r2));
|
let value = ($mapping)(self.get_reg_checked(r1)?, self.get_reg_checked(r2)?);
|
||||||
self.set_reg(r1, value);
|
self.set_reg(r1, value);
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ impl Vm {
|
|||||||
INV => {
|
INV => {
|
||||||
let r1 = cursor.next_reg()?;
|
let r1 = cursor.next_reg()?;
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
let value = self.get_reg(r1);
|
let value = self.get_reg_checked(r1)?;
|
||||||
self.set_reg(r1, !value);
|
self.set_reg(r1, !value);
|
||||||
}
|
}
|
||||||
NOT => {
|
NOT => {
|
||||||
@@ -80,8 +80,8 @@ impl Vm {
|
|||||||
LOAD => {
|
LOAD => {
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
let value = self.load(r2);
|
let value = self.load(r2)?;
|
||||||
self.set_reg(r1, value);
|
self.set_reg_checked(r1, value)?;
|
||||||
}
|
}
|
||||||
REGCOPY => math_inst!(|_: u64, w2: u64| w2),
|
REGCOPY => math_inst!(|_: u64, w2: u64| w2),
|
||||||
STOREIMM64 => {
|
STOREIMM64 => {
|
||||||
@@ -101,14 +101,14 @@ impl Vm {
|
|||||||
MEMCOPY => {
|
MEMCOPY => {
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
let value = self.load(r2);
|
let value = self.load(r2)?;
|
||||||
self.store(r1, value);
|
self.store(r1, value)?;
|
||||||
}
|
}
|
||||||
STORE => {
|
STORE => {
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
let value = self.get_reg(r1);
|
let value = self.get_reg(r1);
|
||||||
self.store(r2, value);
|
self.store(r2, value)?;
|
||||||
}
|
}
|
||||||
HALT => {
|
HALT => {
|
||||||
next_ip = cursor.position();
|
next_ip = cursor.position();
|
||||||
|
|||||||
93
src/vm/vm.rs
93
src/vm/vm.rs
@@ -1,5 +1,5 @@
|
|||||||
use crate::vm::{error::*, flags::*, mem::*, reg::*};
|
use crate::vm::{error::*, flags::*, mem::*, reg::*};
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
use byteorder::{WriteBytesExt, LE};
|
||||||
use std::{io::Cursor, mem};
|
use std::{io::Cursor, mem};
|
||||||
|
|
||||||
pub type Word = u64;
|
pub type Word = u64;
|
||||||
@@ -18,7 +18,6 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mem_cursor(&self, at: usize) -> MemCursor {
|
pub fn mem_cursor(&self, at: usize) -> MemCursor {
|
||||||
// TODO : MemCursor
|
|
||||||
MemCursor::new(&self.mem[at..])
|
MemCursor::new(&self.mem[at..])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,59 +36,62 @@ impl Vm {
|
|||||||
self.flags().contains(Flags::HALT)
|
self.flags().contains(Flags::HALT)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_word(&self, addr: Word) -> Word {
|
pub fn get_word(&self, addr: Addr) -> Result<Word> {
|
||||||
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
|
self.check_read(addr, 8)?;
|
||||||
reader
|
Ok(self.mem_cursor(addr as usize).next_u64().unwrap())
|
||||||
.read_u64::<LE>()
|
|
||||||
.expect("word outside of address range")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_halfword(&self, addr: Word) -> HalfWord {
|
pub fn get_halfword(&self, addr: Addr) -> Result<HalfWord> {
|
||||||
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
|
self.check_read(addr, 4)?;
|
||||||
reader
|
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
|
||||||
.read_u32::<LE>()
|
|
||||||
.expect("word outside of address range")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_byte(&self, addr: Word) -> u8 {
|
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
|
||||||
let mut reader = Cursor::new(&self.mem[(addr as usize)..]);
|
self.check_addr(addr)?;
|
||||||
reader.read_u8().expect("word outside of address range")
|
Ok(self.mem_cursor(addr as usize).next_u8().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_word(&mut self, addr: Word, value: Word) {
|
pub fn set_word(&mut self, addr: Addr, value: Word) -> Result<()> {
|
||||||
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
|
self.check_read(addr, 8)?;
|
||||||
writer
|
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
|
||||||
.write_u64::<LE>(value)
|
Ok(cursor.write_u64::<LE>(value).unwrap())
|
||||||
.expect("word outside of address range");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_halfword(&mut self, addr: Word, value: HalfWord) {
|
pub fn set_halfword(&mut self, addr: Addr, value: HalfWord) -> Result<()> {
|
||||||
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
|
self.check_read(addr, 4)?;
|
||||||
writer
|
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
|
||||||
.write_u32::<LE>(value)
|
Ok(cursor.write_u32::<LE>(value).unwrap())
|
||||||
.expect("word outside of address range");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_byte(&mut self, addr: Word, value: u8) {
|
pub fn set_byte(&mut self, addr: Addr, value: u8) -> Result<()> {
|
||||||
let mut writer = Cursor::new(&mut self.mem[(addr as usize)..]);
|
self.check_addr(addr)?;
|
||||||
writer
|
let mut cursor = Cursor::new(&mut self.mem[addr as usize..]);
|
||||||
.write_u8(value)
|
Ok(cursor.write_u8(value).unwrap())
|
||||||
.expect("word outside of address range");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(&self, reg: Reg) -> Word {
|
pub fn load(&self, reg: Reg) -> Result<Word> {
|
||||||
self.get_word(self.get_reg(reg))
|
self.get_word(self.get_reg_checked(reg)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(&mut self, reg: Reg, value: Word) {
|
pub fn store(&mut self, reg: Reg, value: Word) -> Result<()> {
|
||||||
let addr = self.get_reg(reg);
|
let addr = self.get_reg_checked(reg)?;
|
||||||
self.set_word(addr, value);
|
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 {
|
pub fn get_reg(&self, reg: Reg) -> Word {
|
||||||
self.registers[reg as usize]
|
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 {
|
pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word {
|
||||||
mem::replace(&mut self.registers[reg as usize], value)
|
mem::replace(&mut self.registers[reg as usize], value)
|
||||||
}
|
}
|
||||||
@@ -119,4 +121,25 @@ impl Vm {
|
|||||||
pub fn set_flags(&mut self, flags: Flags) {
|
pub fn set_flags(&mut self, flags: Flags) {
|
||||||
self.set_reg(FLAGS, flags.bits());
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user