From 26a34c3eae661235b8cfeb79ffc977f8379b57c4 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Wed, 11 Sep 2019 11:29:24 -0400 Subject: [PATCH] A class which manages virtio device config area --- rust/src/virtio/device_config.rs | 97 ++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 rust/src/virtio/device_config.rs diff --git a/rust/src/virtio/device_config.rs b/rust/src/virtio/device_config.rs new file mode 100644 index 0000000..d2975fa --- /dev/null +++ b/rust/src/virtio/device_config.rs @@ -0,0 +1,97 @@ + +use byteorder::{ByteOrder,LittleEndian}; +use std::ops::Range; + +pub struct DeviceConfigArea { + buffer: Vec, + write_filter: DeviceConfigWriteFilter, +} + + +impl DeviceConfigArea { + pub fn new(size: usize) -> Self { + DeviceConfigArea{ + buffer: vec![0u8; size], + write_filter: DeviceConfigWriteFilter::new(size), + } + } + + pub fn read_config(&self, offset: usize, size: usize) -> u64 { + if offset + size > self.buffer.len() { + return 0; + } + match size { + 1 => self.buffer[offset] as u64, + 2 => LittleEndian::read_u16(&self.buffer[offset..]) as u64, + 4 => LittleEndian::read_u32(&self.buffer[offset..]) as u64, + 8 => LittleEndian::read_u64(&self.buffer[offset..]), + _ => 0, + } + } + + pub fn write_config(&mut self, offset: usize, size: usize, val: u64) { + if self.write_filter.is_writeable(offset, size) { + match size { + 1 => self.write_u8(offset, val as u8), + 2 => self.write_u16(offset, val as u16), + 4 => self.write_u32(offset, val as u32), + 8 => self.write_u64(offset, val as u64), + _ => {}, + } + } + } + + pub fn set_writeable(&mut self, offset: usize, size: usize) { + self.write_filter.set_writable(offset, size) + } + + pub fn write_u8(&mut self, offset: usize, val: u8) { + assert!(offset + 1 <= self.buffer.len()); + self.buffer[offset] = val; + } + + pub fn write_u16(&mut self, offset: usize, val: u16) { + assert!(offset + 2 <= self.buffer.len()); + LittleEndian::write_u16(&mut self.buffer[offset..], val); + } + + pub fn write_u32(&mut self, offset: usize, val: u32) { + assert!(offset + 4 <= self.buffer.len()); + LittleEndian::write_u32(&mut self.buffer[offset..], val); + } + + pub fn write_u64(&mut self, offset: usize, val: u64) { + assert!(offset + 8 <= self.buffer.len()); + LittleEndian::write_u64(&mut self.buffer[offset..], val); + } + + pub fn write_bytes(&mut self, offset: usize, bytes: &[u8]) { + assert!(offset + bytes.len() <= self.buffer.len()); + self.buffer[offset..offset + bytes.len()].copy_from_slice(bytes); + } +} + +struct DeviceConfigWriteFilter { + size: usize, + ranges: Vec>, +} + +impl DeviceConfigWriteFilter { + fn new(size: usize) -> Self { + DeviceConfigWriteFilter { size, ranges: Vec::new() } + } + + fn set_writable(&mut self, offset: usize, size: usize) { + let end = offset + size; + self.ranges.push(offset..end); + } + + fn is_writeable(&self, offset: usize, size: usize) -> bool { + if offset + size > self.size { + false + } else { + let last = offset + size - 1; + self.ranges.iter().any(|r| r.contains(&offset) && r.contains(&last)) + } + } +} \ No newline at end of file