From 793b84747ee2e8221392a24dd8e9e4832c71931e Mon Sep 17 00:00:00 2001 From: Zachary Barbanell Date: Mon, 6 Mar 2023 11:55:48 -0800 Subject: [PATCH 1/2] add_mapping and add_mapping_at impls --- Cargo.toml | 3 ++ src/address_space.rs | 113 +++++++++++++++++++++++++++++++++++++------ src/lib.rs | 3 +- 3 files changed, 104 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6bd5d94..2b08086 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[toolchain] +channel = "nightly" + [dependencies] diff --git a/src/address_space.rs b/src/address_space.rs index 8bbf908..13ebb5a 100644 --- a/src/address_space.rs +++ b/src/address_space.rs @@ -3,11 +3,21 @@ use std::sync::Arc; use crate::data_source::DataSource; +const SPACE: usize = 2usize.pow(27) - 1; + +const PAGE: usize = 4096; + type VirtualAddress = usize; -struct MapEntry { +#[derive(Clone)] +struct DataView { source: Arc, offset: usize, +} + +#[derive(Clone)] +struct MapEntry { + content: Option, span: usize, addr: usize, } @@ -32,37 +42,113 @@ pub struct AddressSpace { impl AddressSpace { #[must_use] pub fn new(name: &str) -> Self { - Self { + let mut s = Self { name: name.to_string(), mappings: LinkedList::new(), - } + }; + s.mappings.push_back(MapEntry { + content: None, + span: (SPACE / PAGE - 2) * PAGE, + addr: PAGE, + }); + s } /// Add a mapping from a `DataSource` into this `AddressSpace`. /// /// # Errors /// If the desired mapping is invalid. - pub fn add_mapping( - &self, - source: &D, + pub fn add_mapping( + &mut self, + source: D, offset: usize, span: usize, ) -> Result { - todo!() + let fullspan = PAGE * ((span - 1) / PAGE + 1); + let mut c = self.mappings.cursor_front_mut(); + loop { + let node = c.current().cloned(); + match node { + Some(entry) => { + if entry.content.is_none() && entry.span >= fullspan { + let leftover = entry.span - fullspan; + c.insert_before(MapEntry { + content: Some(DataView { + source: Arc::new(source), + offset, + }), + span: fullspan, + addr: entry.addr, + }); + if leftover >= PAGE { + c.insert_before(MapEntry { + content: None, + span: leftover - PAGE, + addr: entry.addr + fullspan + PAGE, + }) + } + c.remove_current(); + return Ok(entry.addr); + } else { + c.move_next(); + } + } + None => return Err("no available mappings of that size."), + } + } } /// Add a mapping from `DataSource` into this `AddressSpace` starting at a specific address. /// /// # Errors /// If there is insufficient room subsequent to `start`. - pub fn add_mapping_at( - &self, - source: &D, + pub fn add_mapping_at( + &mut self, + source: D, offset: usize, span: usize, start: VirtualAddress, ) -> Result<(), &str> { - todo!() + let fullspan = PAGE * ((span - 1) / PAGE + 1); + let mut c = self.mappings.cursor_front_mut(); + loop { + let node = c.current().cloned(); + match node { + Some(entry) => { + if entry.content.is_none() && start >= entry.addr && entry.addr + entry.span - start >= fullspan { + let before = start - entry.span; + let leftover = entry.addr + entry.span - start - fullspan; + if before >= PAGE { + c.insert_before(MapEntry { + content: None, + span: before - PAGE, + addr: entry.addr, + }) + } + c.insert_before(MapEntry { + content: Some(DataView { + source: Arc::new(source), + offset, + }), + span: fullspan, + addr: start, + }); + if leftover >= PAGE { + c.insert_before(MapEntry { + content: None, + span: leftover - PAGE, + addr: start + fullspan + PAGE, + }) + } + c.remove_current(); + return Ok(()); + } else { + c.move_next(); + } + } + None => return Err("no available mapping at that address."), + } + } } /// Remove the mapping to `DataSource` that starts at the given address. @@ -79,14 +165,14 @@ impl AddressSpace { /// Look up the DataSource and offset within that DataSource for a /// VirtualAddress / AccessType in this AddressSpace - /// + /// /// # Errors /// If this VirtualAddress does not have a valid mapping in &self, /// or if this AccessType is not permitted by the mapping pub fn get_source_for_addr( &self, addr: VirtualAddress, - access_type: FlagBuilder + access_type: FlagBuilder, ) -> Result<(&D, usize), &str> { todo!(); } @@ -218,4 +304,3 @@ impl FlagBuilder { } } } - diff --git a/src/lib.rs b/src/lib.rs index 2e974a4..653fde5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![allow(dead_code, unused_variables)] +#![feature(linked_list_cursors)] mod address_space; mod cacher; @@ -28,7 +29,7 @@ mod tests { let offset: usize = 0; let length: usize = 1; - let addr = addr_space.add_mapping(&data_source, offset, length).unwrap(); + let addr = addr_space.add_mapping(data_source, offset, length).unwrap(); assert!(addr != 0); // we should move these tests into addr_space, since they access non-public internals of the structure: From 1aa430bb804e4a8a1c808807a518dc8bf417ad0c Mon Sep 17 00:00:00 2001 From: 00gogo00 Date: Sun, 19 Mar 2023 01:13:29 -0600 Subject: [PATCH 2/2] assignment --- src/address_space.rs | 57 ++++++++++++++++++++++++++++++++++++++------ src/lib.rs | 2 +- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/address_space.rs b/src/address_space.rs index 13ebb5a..c3ab1dd 100644 --- a/src/address_space.rs +++ b/src/address_space.rs @@ -155,12 +155,40 @@ impl AddressSpace { /// /// # Errors /// If the mapping could not be removed. - pub fn remove_mapping( - &self, - source: &D, + pub fn remove_mapping( + &mut self, start: VirtualAddress, ) -> Result<(), &str> { - todo!() + let mut c = self.mappings.cursor_front_mut(); + loop { + let node = c.current(); + match node { + Some(entry) => { + if entry.addr == start && entry.content.is_some() { + let mut begin = entry.addr; + let mut end = entry.addr + entry.span; + c.move_prev(); + if let Some(e) = c.current() { + begin = e.addr; + c.remove_current(); + } else { + c.move_next(); + } + c.move_next(); + if let Some(e) = c.current() { + end = e.addr + e.span; + c.remove_current(); + } + c.move_prev(); + c.remove_current(); + c.insert_before(MapEntry { content: None, span: end - begin, addr: begin }) + } else { + c.move_next() + } + }, + None => return Err("no mapping at that address."), + } + } } /// Look up the DataSource and offset within that DataSource for a @@ -169,12 +197,27 @@ impl AddressSpace { /// # Errors /// If this VirtualAddress does not have a valid mapping in &self, /// or if this AccessType is not permitted by the mapping - pub fn get_source_for_addr( + pub fn get_source_for_addr( &self, addr: VirtualAddress, access_type: FlagBuilder, - ) -> Result<(&D, usize), &str> { - todo!(); + ) -> Result<(&dyn DataSource, usize), &str> { + let mut c = self.mappings.cursor_front(); + loop { + let node = c.current(); + match node { + Some(entry) => { + if entry.addr <= addr && addr <= entry.addr + entry.span { + if let Some(&MapEntry { content: Some(DataView { ref source, offset }), span, addr }) = c.current().clone() { + return Ok((source.as_ref(), offset + addr - entry.addr)); + } + } else { + c.move_next() + } + }, + None => return Err("no mapping at that address."), + } + } } } diff --git a/src/lib.rs b/src/lib.rs index 653fde5..768863b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ mod tests { // test if mapping has been added #[test] fn test_add_mapping() { - let addr_space = AddressSpace::new("Test address space"); + let mut addr_space = AddressSpace::new("Test address space"); let data_source: FileDataSource = FileDataSource::new("Cargo.toml").unwrap(); let offset: usize = 0; let length: usize = 1;