Skip to content

Commit

Permalink
libuser: mem module
Browse files Browse the repository at this point in the history
  • Loading branch information
Orycterope committed Mar 9, 2019
1 parent 2bbebd7 commit 63f3be7
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 36 deletions.
33 changes: 2 additions & 31 deletions libuser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ extern crate bitfield;

#[macro_use]
extern crate kfs_libutils;
use kfs_libkern;
#[macro_use]
extern crate failure;

Expand All @@ -41,6 +40,7 @@ extern crate lazy_static;

pub mod caps;
pub mod syscalls;
pub mod mem;
pub mod types;
pub mod ipc;
pub mod sm;
Expand All @@ -54,8 +54,7 @@ mod log_impl;
pub use kfs_libutils::io;

use kfs_libutils as utils;
use crate::error::{Error, LibuserError};


// TODO: report #[cfg(not(test))] and #[global_allocator]
// BODY: `#[cfg(not(test))]` still compiles this item with cargo test,
// BODY: but `#[cfg(target_os = "none")] does not. I think this is a bug,
Expand All @@ -66,34 +65,6 @@ use crate::error::{Error, LibuserError};
#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator::new();

/// Finds a free memory zone of the given size and alignment in the current
/// process's virtual address space. Note that the address space is not reserved,
/// a call to map_memory to that address space might fail if another thread
/// maps to it first. It is recommended to use this function and the map syscall
/// in a loop.
///
/// # Panics
///
/// Panics on underflow when size = 0.
///
/// Panics on underflow when align = 0.
pub fn find_free_address(size: usize, align: usize) -> Result<usize, Error> {
let mut addr = 0;
// Go over the address space.
loop {
let (meminfo, _) = syscalls::query_memory(addr)?;
if meminfo.memtype == kfs_libkern::MemoryType::Unmapped {
let alignedbaseaddr = kfs_libutils::align_up_checked(meminfo.baseaddr, align).ok_or(LibuserError::AddressSpaceExhausted)?;

let alignment = alignedbaseaddr - meminfo.baseaddr;
if alignment.checked_add(size - 1).ok_or(LibuserError::AddressSpaceExhausted)? < meminfo.size {
return Ok(alignedbaseaddr)
}
}
addr = meminfo.baseaddr.checked_add(meminfo.size).ok_or(LibuserError::AddressSpaceExhausted)?;
}
}

// Runtime functions
//
// Functions beyond this lines are required by the rust compiler when building
Expand Down
76 changes: 76 additions & 0 deletions libuser/src/mem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//! Memory
//!
//! Low-level helpers to assist memory mapping, MMIOs and DMAs.
use kfs_libutils::{align_down, align_up};
use crate::syscalls;
use crate::error::{KernelError, LibuserError, Error};

/// The size of page. Used to interface with the kernel.
pub const PAGE_SIZE: usize = 4096;

/// Finds a free memory zone of the given size and alignment in the current
/// process's virtual address space. Note that the address space is not reserved,
/// a call to map_memory to that address space might fail if another thread
/// maps to it first. It is recommended to use this function and the map syscall
/// in a loop.
///
/// # Panics
///
/// Panics on underflow when size = 0.
///
/// Panics on underflow when align = 0.
pub fn find_free_address(size: usize, align: usize) -> Result<usize, Error> {
let mut addr = 0;
// Go over the address space.
loop {
let (meminfo, _) = syscalls::query_memory(addr)?;
if meminfo.memtype == kfs_libkern::MemoryType::Unmapped {
let alignedbaseaddr = kfs_libutils::align_up_checked(meminfo.baseaddr, align).ok_or(LibuserError::AddressSpaceExhausted)?;

let alignment = alignedbaseaddr - meminfo.baseaddr;
if alignment.checked_add(size - 1).ok_or(LibuserError::AddressSpaceExhausted)? < meminfo.size {
return Ok(alignedbaseaddr)
}
}
addr = meminfo.baseaddr.checked_add(meminfo.size).ok_or(LibuserError::AddressSpaceExhausted)?;
}
}

/// Maps a Mmio struct in the virtual memory of this process.
///
/// This function preserves the offset relative to `PAGE_SIZE`.
///
/// # Example
///
/// ```
/// /// Found at physical address 0xabc00030
/// #[repr(packed)]
/// struct DeviceFoo {
/// header: Mmio<u32>,
/// version: Mmio<u32>,
/// field_a: Mmio<u16>
/// field_b: Mmio<u16>
/// }
///
/// let mapped_data: *mut DeviceFoo = map_mmio::<DeviceFoo>(0xabc00030); // = virtual address 0x7030
/// assert_eq!(mapped_data.version.read(), 0x010200);
/// ```
pub fn map_mmio<T>(physical_address: usize) -> Result<*mut T, KernelError> {
let aligned_phys_addr = align_down(physical_address, PAGE_SIZE);
let full_size = align_up(aligned_phys_addr + ::core::mem::size_of::<T>(), PAGE_SIZE) - aligned_phys_addr;
let virt_addr = find_free_address(full_size as _, 1).unwrap();
syscalls::map_mmio_region(aligned_phys_addr as _, full_size as _, virt_addr, true)?;
Ok((virt_addr + (physical_address % PAGE_SIZE)) as *mut T)
}

/// Gets the physical address of a structure from its virtual address, preserving offset in the page.
///
/// # Panics
///
/// * query_physical_address failed.
pub fn virt_to_phys<T>(virtual_address: *const T) -> usize {
let (phys_region_start, _, _, phys_region_offset) = syscalls::query_physical_address(virtual_address as usize)
.expect("syscall query_physical_memory failed");
phys_region_start + phys_region_offset
}
7 changes: 4 additions & 3 deletions libuser/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::types::{SharedMemory, MappedSharedMemory};
use crate::vi::{ViInterface, IBuffer};
use crate::syscalls::MemoryPermissions;
use crate::mem::{find_free_address, PAGE_SIZE};
use kfs_libutils::align_up;
use crate::error::Error;
use core::slice;
Expand Down Expand Up @@ -55,9 +56,9 @@ impl Window {
let bpp = 32;
let size = height * width * bpp / 8;

let sharedmem = SharedMemory::new(align_up(size, 0x1000) as _, MemoryPermissions::READABLE | MemoryPermissions::WRITABLE, MemoryPermissions::READABLE)?;
let addr = crate::find_free_address(size as _, 0x1000)?;
let buf = sharedmem.map(addr, align_up(size as _, 0x1000), MemoryPermissions::READABLE | MemoryPermissions::WRITABLE)?;
let sharedmem = SharedMemory::new(align_up(size, PAGE_SIZE as _) as _, MemoryPermissions::READABLE | MemoryPermissions::WRITABLE, MemoryPermissions::READABLE)?;
let addr = find_free_address(size as _, PAGE_SIZE)?;
let buf = sharedmem.map(addr, align_up(size as _, PAGE_SIZE), MemoryPermissions::READABLE | MemoryPermissions::WRITABLE)?;
let handle = vi.create_buffer(buf.as_shared_mem(), top, left, width, height)?;

let mut fb = Window {
Expand Down
5 changes: 3 additions & 2 deletions vi/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use spin::Mutex;
use crate::libuser::error::Error;
use crate::libuser::syscalls::MemoryPermissions;
use kfs_libutils::align_up;
use libuser::mem::{find_free_address, PAGE_SIZE};

/// Entry point interface.
#[derive(Default, Debug)]
Expand All @@ -59,8 +60,8 @@ object! {
#[cmdid(0)]
fn create_buffer(&mut self, manager: &WaitableManager, handle: Handle<copy>, top: i32, left: i32, width: u32, height: u32,) -> Result<(Handle,), Error> {
let sharedmem = SharedMemory(handle);
let size = align_up(width * height * 4, 0x1000);
let addr = libuser::find_free_address(size as _, 0x1000)?;
let size = align_up(width * height * 4, PAGE_SIZE as _);
let addr = find_free_address(size as _, PAGE_SIZE)?;
let mapped = sharedmem.map(addr, size as _, MemoryPermissions::READABLE)?;
let buf = IBuffer {
buffer: Arc::new(Buffer {
Expand Down

0 comments on commit 63f3be7

Please sign in to comment.