Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
170 changes: 149 additions & 21 deletions src/address_space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn DataSource>,
offset: usize,
}

#[derive(Clone)]
struct MapEntry {
content: Option<DataView>,
span: usize,
addr: usize,
}
Expand All @@ -32,63 +42,182 @@ 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<D: DataSource>(
&self,
source: &D,
pub fn add_mapping<D: DataSource + 'static>(
&mut self,
source: D,
offset: usize,
span: usize,
) -> Result<VirtualAddress, &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() && 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<D: DataSource>(
&self,
source: &D,
pub fn add_mapping_at<D: DataSource + 'static>(
&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.
///
/// # Errors
/// If the mapping could not be removed.
pub fn remove_mapping<D: DataSource>(
&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
/// 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<D: DataSource>(
pub fn get_source_for_addr(
&self,
addr: VirtualAddress,
access_type: FlagBuilder
) -> Result<(&D, usize), &str> {
todo!();
access_type: FlagBuilder,
) -> 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."),
}
}
}
}

Expand Down Expand Up @@ -218,4 +347,3 @@ impl FlagBuilder {
}
}
}

5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(dead_code, unused_variables)]
#![feature(linked_list_cursors)]

mod address_space;
mod cacher;
Expand All @@ -23,12 +24,12 @@ 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;

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:
Expand Down