summaryrefslogtreecommitdiff
path: root/src/mem.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem.rs')
-rw-r--r--src/mem.rs105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/mem.rs b/src/mem.rs
new file mode 100644
index 0000000..297c54c
--- /dev/null
+++ b/src/mem.rs
@@ -0,0 +1,105 @@
+const PAGE_SIZE: usize = 4 * 1024;
+const PAGE_MASK: usize = !(PAGE_SIZE - 1);
+
+struct Page {
+ virtual_addr: usize,
+ real_addr: usize,
+ permission: usize,
+ allocated: usize,
+}
+pub struct Memory {
+ memory: Box<[u8]>,
+ pages: Vec<Page>,
+}
+impl Memory {
+ pub fn new(size: usize) -> Memory {
+ let mut pages: Vec<Page> = Vec::with_capacity(size / PAGE_SIZE);
+ for i in 0..size / PAGE_SIZE {
+ pages[i] = Page {
+ virtual_addr: usize::MAX,
+ real_addr: i * PAGE_SIZE,
+ permission: 0,
+ allocated: 0
+ }
+ }
+ Memory {
+ memory: vec![0u8; size].into_boxed_slice(),
+ pages,
+ }
+ }
+
+ pub fn create_page(&mut self, virtual_addr: usize, permission: usize) -> Option<usize> {
+ // Find first page that isn't allocated and set it to allocated
+ for (i, page) in self.pages.iter_mut().enumerate() {
+ if page.allocated == 0 {
+ page.virtual_addr = virtual_addr;
+ page.permission = permission;
+ page.allocated = 1;
+ return Some(i);
+ }
+ }
+ None
+ }
+
+ pub fn lookup_page(&mut self, virtual_addr: usize, permission: usize) -> Option<usize> {
+ for (i, page) in self.pages.iter().enumerate() {
+ if page.virtual_addr == virtual_addr && permission >= page.permission && page.allocated == 1 {
+ return Some(i);
+ }
+ }
+ return self.create_page(virtual_addr, permission);
+ }
+
+ pub fn ro_lookup(&self, virtual_addr: usize, permission: usize) -> Option<usize> {
+ for (i, page) in self.pages.iter().enumerate() {
+ if page.virtual_addr == virtual_addr && page.permission == permission && page.allocated == 1 {
+ return Some(i);
+ }
+ }
+ None
+ }
+
+ pub fn write(&mut self, address: usize, permission: usize, value: u8) -> Result<(), ()> {
+ let page = address & PAGE_MASK;
+ let offset = address - page;
+
+ if let Some(page) = self.lookup_page(address, permission) {
+ self.memory[self.pages[page].real_addr + offset] = value;
+ Ok(())
+ } else {
+ Err(())
+ }
+ }
+
+ pub fn read(&self, address: usize, permission: usize) -> Result<u8, ()> {
+ let page = address & PAGE_MASK;
+ let offset = address - page;
+
+ if let Some(page) = self.ro_lookup(address, permission) {
+ Ok(self.memory[self.pages[page].real_addr + offset])
+ } else {
+ Err(())
+ }
+ }
+
+ pub fn read_multiple_bytes(&self, address: usize, size: usize, permission: usize) -> Result<Box<[u8]>, ()> {
+ let mut ret = [];
+ for addr in address..address+size {
+ if let Ok(byte) = self.read(addr, permission) {
+ ret[addr - address] = byte;
+ } else {
+ return Err(());
+ }
+ }
+ Ok(Box::new(ret))
+ }
+
+ pub fn write_multiple_bytes(&mut self, address: usize, bytes: &[u8], permission: usize) -> Result<(), ()> {
+ for addr in address..address + bytes.len() {
+ if let Err(_) = self.write(addr, permission, bytes[addr - address]) {
+ return Err(());
+ }
+ }
+ Ok(())
+ }
+} \ No newline at end of file