redox/kernel/context/memory.rs

346 lines
10 KiB
Rust
Raw Normal View History

2016-09-17 01:51:27 +02:00
use alloc::arc::{Arc, Weak};
use collections::VecDeque;
2016-11-14 18:50:00 +01:00
use core::intrinsics;
2016-09-17 01:51:27 +02:00
use spin::Mutex;
use arch::memory::Frame;
use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, PhysicalAddress, VirtualAddress};
use arch::paging::entry::{self, EntryFlags};
2016-09-15 06:21:52 +02:00
use arch::paging::temporary_page::TemporaryPage;
2016-09-12 05:04:34 +02:00
#[derive(Debug)]
pub struct Grant {
2016-09-12 05:04:34 +02:00
start: VirtualAddress,
size: usize,
flags: EntryFlags
}
impl Grant {
2016-09-21 06:14:08 +02:00
pub fn physmap(from: PhysicalAddress, to: VirtualAddress, size: usize, flags: EntryFlags) -> Grant {
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
let start_page = Page::containing_address(to);
let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - to.get() + from.get()));
active_table.map_to(page, frame, flags);
flush_all = true;
}
if flush_all {
active_table.flush_all();
}
Grant {
start: to,
size: size,
flags: flags
}
}
pub fn map_inactive(from: VirtualAddress, to: VirtualAddress, size: usize, flags: EntryFlags, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) -> Grant {
let mut active_table = unsafe { ActivePageTable::new() };
let mut frames = VecDeque::new();
let start_page = Page::containing_address(from);
let end_page = Page::containing_address(VirtualAddress::new(from.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = active_table.translate_page(page).expect("grant references unmapped memory");
frames.push_back(frame);
}
active_table.with(new_table, temporary_page, |mapper| {
let start_page = Page::containing_address(to);
let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = frames.pop_front().expect("grant did not find enough frames");
mapper.map_to(page, frame, flags);
}
});
Grant {
start: to,
size: size,
flags: flags
}
}
2016-09-21 06:14:08 +02:00
pub fn start_address(&self) -> VirtualAddress {
self.start
}
2016-09-21 06:14:08 +02:00
pub fn size(&self) -> usize {
self.size
}
2016-09-21 06:14:08 +02:00
pub fn flags(&self) -> EntryFlags {
self.flags
}
2016-09-21 06:14:08 +02:00
pub fn unmap(self) {
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
let start_page = Page::containing_address(self.start);
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
for page in Page::range_inclusive(start_page, end_page) {
active_table.unmap_return(page);
flush_all = true;
}
if flush_all {
active_table.flush_all();
}
}
2016-09-21 06:14:08 +02:00
pub fn unmap_inactive(self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) {
let mut active_table = unsafe { ActivePageTable::new() };
2016-09-21 06:14:08 +02:00
active_table.with(new_table, temporary_page, |mapper| {
let start_page = Page::containing_address(self.start);
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
for page in Page::range_inclusive(start_page, end_page) {
mapper.unmap_return(page);
}
});
}
}
#[derive(Clone, Debug)]
2016-09-17 01:51:27 +02:00
pub enum SharedMemory {
Owned(Arc<Mutex<Memory>>),
Borrowed(Weak<Mutex<Memory>>)
}
impl SharedMemory {
pub fn with<F, T>(&self, f: F) -> T where F: FnOnce(&mut Memory) -> T {
match *self {
SharedMemory::Owned(ref memory_lock) => {
let mut memory = memory_lock.lock();
f(&mut *memory)
},
SharedMemory::Borrowed(ref memory_weak) => {
let memory_lock = memory_weak.upgrade().expect("SharedMemory::Borrowed no longer valid");
let mut memory = memory_lock.lock();
f(&mut *memory)
}
}
}
pub fn borrow(&self) -> SharedMemory {
match *self {
SharedMemory::Owned(ref memory_lock) => SharedMemory::Borrowed(Arc::downgrade(memory_lock)),
SharedMemory::Borrowed(ref memory_lock) => SharedMemory::Borrowed(memory_lock.clone())
}
}
}
#[derive(Debug)]
pub struct Memory {
start: VirtualAddress,
size: usize,
flags: EntryFlags
}
2016-09-12 05:04:34 +02:00
impl Memory {
2016-09-12 05:47:44 +02:00
pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self {
2016-09-12 05:04:34 +02:00
let mut memory = Memory {
start: start,
size: size,
flags: flags
};
2016-09-12 05:47:44 +02:00
memory.map(flush, clear);
2016-09-12 05:04:34 +02:00
memory
}
2016-09-17 01:51:27 +02:00
pub fn to_shared(self) -> SharedMemory {
SharedMemory::Owned(Arc::new(Mutex::new(self)))
}
2016-09-12 05:18:18 +02:00
pub fn start_address(&self) -> VirtualAddress {
self.start
}
pub fn size(&self) -> usize {
self.size
}
pub fn flags(&self) -> EntryFlags {
self.flags
}
2016-09-12 05:04:34 +02:00
pub fn pages(&self) -> PageIter {
let start_page = Page::containing_address(self.start);
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
Page::range_inclusive(start_page, end_page)
}
2016-09-15 06:21:52 +02:00
fn map(&mut self, flush: bool, clear: bool) {
2016-09-12 05:04:34 +02:00
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
2016-09-12 05:35:02 +02:00
//TODO: Clear pages?
2016-09-12 05:04:34 +02:00
for page in self.pages() {
active_table.map(page, self.flags);
2016-09-12 05:04:34 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
2016-09-12 05:04:34 +02:00
}
}
2016-09-12 05:47:44 +02:00
if flush_all {
active_table.flush_all();
}
2016-09-12 05:47:44 +02:00
if clear {
assert!(flush && self.flags.contains(entry::WRITABLE));
2016-11-14 18:50:00 +01:00
unsafe {
intrinsics::write_bytes(self.start_address().get() as *mut u8, 0, self.size);
}
2016-09-12 05:47:44 +02:00
}
2016-09-12 05:04:34 +02:00
}
2016-09-15 06:21:52 +02:00
fn unmap(&mut self, flush: bool) {
2016-09-12 05:04:34 +02:00
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
2016-09-12 05:04:34 +02:00
for page in self.pages() {
active_table.unmap(page);
2016-09-12 05:04:34 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
2016-09-12 05:04:34 +02:00
}
}
if flush_all {
active_table.flush_all();
}
2016-09-12 05:04:34 +02:00
}
2016-09-15 06:21:52 +02:00
/// A complicated operation to move a piece of memory to a new page table
/// It also allows for changing the address at the same time
pub fn move_to(&mut self, new_start: VirtualAddress, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage, flush: bool) {
2016-09-12 05:04:34 +02:00
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
2016-09-12 05:04:34 +02:00
for page in self.pages() {
2016-09-15 06:21:52 +02:00
let frame = active_table.unmap_return(page);
active_table.with(new_table, temporary_page, |mapper| {
let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get()));
mapper.map_to(new_page, frame, self.flags);
});
2016-09-12 05:04:34 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
2016-09-12 05:04:34 +02:00
}
}
2016-09-12 05:18:18 +02:00
if flush_all {
active_table.flush_all();
}
2016-09-15 06:21:52 +02:00
self.start = new_start;
2016-09-12 05:18:18 +02:00
}
2016-09-15 06:21:52 +02:00
pub fn remap(&mut self, new_flags: EntryFlags, flush: bool) {
2016-09-14 05:27:27 +02:00
let mut active_table = unsafe { ActivePageTable::new() };
let mut flush_all = false;
for page in self.pages() {
2016-09-15 06:21:52 +02:00
active_table.remap(page, new_flags);
2016-09-14 05:27:27 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
}
}
if flush_all {
active_table.flush_all();
}
2016-09-15 06:21:52 +02:00
self.flags = new_flags;
2016-09-14 05:27:27 +02:00
}
2016-09-12 05:47:44 +02:00
pub fn resize(&mut self, new_size: usize, flush: bool, clear: bool) {
2016-09-12 05:18:18 +02:00
let mut active_table = unsafe { ActivePageTable::new() };
2016-09-12 05:35:02 +02:00
//TODO: Calculate page changes to minimize operations
2016-09-12 05:18:18 +02:00
if new_size > self.size {
let mut flush_all = false;
2016-09-12 05:18:18 +02:00
let start_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size));
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + new_size - 1));
for page in Page::range_inclusive(start_page, end_page) {
if active_table.translate_page(page).is_none() {
active_table.map(page, self.flags);
2016-09-12 05:18:18 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
2016-09-12 05:18:18 +02:00
}
}
}
2016-09-12 05:47:44 +02:00
if flush_all {
active_table.flush_all();
}
2016-09-12 05:47:44 +02:00
if clear {
assert!(flush);
2016-11-14 18:50:00 +01:00
unsafe {
intrinsics::write_bytes((self.start.get() + self.size) as *mut u8, 0, new_size - self.size);
}
2016-09-12 05:47:44 +02:00
}
2016-09-12 05:18:18 +02:00
} else if new_size < self.size {
let mut flush_all = false;
2016-09-12 05:18:18 +02:00
let start_page = Page::containing_address(VirtualAddress::new(self.start.get() + new_size));
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
for page in Page::range_inclusive(start_page, end_page) {
if active_table.translate_page(page).is_some() {
active_table.unmap(page);
2016-09-12 05:18:18 +02:00
if flush {
//active_table.flush(page);
flush_all = true;
2016-09-12 05:18:18 +02:00
}
}
}
if flush_all {
active_table.flush_all();
}
2016-09-12 05:18:18 +02:00
}
self.size = new_size;
2016-09-12 05:04:34 +02:00
}
}
impl Drop for Memory {
fn drop(&mut self) {
self.unmap(true);
}
}
#[derive(Debug)]
pub struct Tls {
pub master: VirtualAddress,
pub file_size: usize,
pub mem: Memory
}