Skip to content
Draft
8 changes: 8 additions & 0 deletions kernel/src/cpu/idt/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,14 @@ extern "C" fn ex_handler_system_call(
ctxt.regs.rax = match input {
// Class 0 SysCalls.
SYS_EXIT => sys_exit(ctxt.regs.rdi as u32),
SYS_MMAP => sys_mmap(
ctxt.regs.rdi as u32,
ctxt.regs.rsi,
ctxt.regs.r8,
ctxt.regs.r9,
ctxt.regs.r10,
),
SYS_MUNMAP => sys_munmap(ctxt.regs.rdi, ctxt.regs.rsi),
SYS_EXEC => sys_exec(ctxt.regs.rdi, ctxt.regs.rsi, ctxt.regs.r8),
SYS_CLOSE => sys_close(ctxt.regs.rdi as u32),
// Class 1 SysCalls.
Expand Down
18 changes: 17 additions & 1 deletion kernel/src/fs/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};

#[derive(Debug)]
struct DirectoryHandle {
pub struct DirectoryHandle {
dir: Arc<dyn Directory>,
list: Vec<FileName>,
next: AtomicUsize,
Expand Down Expand Up @@ -42,6 +42,22 @@ pub struct FsObj {
}

impl FsObj {
pub fn file_handle(&self) -> Option<&FileHandle> {
if let FsObjEntry::File(fh) = &self.entry {
Some(fh)
} else {
None
}
}

pub fn directory_handle(&self) -> Option<&DirectoryHandle> {
if let FsObjEntry::Directory(dh) = &self.entry {
Some(dh)
} else {
None
}
}

pub fn new_dir(dir: &Arc<dyn Directory>) -> Self {
FsObj {
entry: FsObjEntry::Directory(DirectoryHandle::new(dir)),
Expand Down
20 changes: 20 additions & 0 deletions kernel/src/mm/vm/mapping/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ pub trait VirtualMapping: core::fmt::Debug + Send + Sync {
/// Mapping size. Will always be a multiple of `VirtualMapping::page_size()`
fn mapping_size(&self) -> usize;

/// Request to resize the mapping
///
/// # Arguments
///
/// * `size` - The requested new size of the mapping
///
/// # Returns
///
/// Returns Ok() with the new size of the mapping on success, Err() with
/// SvsmError value on failure.
fn resize(&mut self, _size: usize) -> Result<usize, SvsmError> {
Err(SvsmError::Mem)
}

/// Perform cleanup work after resizing the mapping
///
/// This is a call-back to release any memory that can only be freed after
/// a TLB flush.
fn flush(&mut self) {}

/// Indicates whether the mapping has any associated data.
///
/// # Returns
Expand Down
30 changes: 30 additions & 0 deletions kernel/src/mm/vm/mapping/file_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use crate::mm::{PAGE_SIZE, pagetable::PTEntryFlags};
use crate::types::PAGE_SHIFT;
use crate::utils::align_up;

use syscall::MMFlags;

bitflags! {
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct VMFileMappingFlags : u32 {
Expand All @@ -36,6 +38,34 @@ bitflags! {
}
}

impl From<MMFlags> for VMFileMappingFlags {
fn from(value: MMFlags) -> Self {
let mut vm_val = Self::empty();

if value.contains(MMFlags::MAP_READ) {
vm_val |= VMFileMappingFlags::Read;
}

if value.contains(MMFlags::MAP_WRITE) {
vm_val |= VMFileMappingFlags::Write;
}

if value.contains(MMFlags::MAP_EXEC) {
vm_val |= VMFileMappingFlags::Execute;
}

if value.contains(MMFlags::MAP_PRIVATE) {
vm_val |= VMFileMappingFlags::Private;
}

if value.contains(MMFlags::MAP_FIXED) {
vm_val |= VMFileMappingFlags::Fixed;
}

vm_val
}
}

/// Map view of a ramfs file into virtual memory
#[derive(Debug)]
pub struct VMFileMapping {
Expand Down
86 changes: 82 additions & 4 deletions kernel/src/mm/vm/mapping/rawalloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::error::SvsmError;
use crate::mm::alloc::PageRef;
use crate::types::{PAGE_SHIFT, PAGE_SIZE};
use crate::utils::align_up;
use core::cmp::Ordering;

extern crate alloc;
use alloc::vec::Vec;
Expand All @@ -24,6 +25,9 @@ pub struct RawAllocMapping {

/// Number of pages required in `pages`
count: usize,

/// Pages to flush
unmapped_pages: Vec<Option<PageRef>>,
}

impl RawAllocMapping {
Expand All @@ -39,7 +43,12 @@ impl RawAllocMapping {
pub fn new(size: usize) -> Self {
let count = align_up(size, PAGE_SIZE) >> PAGE_SHIFT;
let pages: Vec<Option<PageRef>> = iter::repeat_n(None, count).collect();
RawAllocMapping { pages, count }
let unmapped_pages: Vec<Option<PageRef>> = Vec::new();
RawAllocMapping {
pages,
count,
unmapped_pages,
}
}

/// Allocates a single backing page of type PageFile if the page has not already
Expand All @@ -61,18 +70,32 @@ impl RawAllocMapping {
Ok(())
}

/// Allocates a full set of backing pages of type PageFile
/// Allocates backing pages for the mapping starting at a give offset
///
/// # Arguments:
///
/// * `offset` - Byte offset into the mapping to start allocating from
///
/// # Returns
///
/// `Ok(())` when all pages could be allocated, `Err(SvsmError::Mem)` otherwise
pub fn alloc_pages(&mut self) -> Result<(), SvsmError> {
for index in 0..self.count {
fn alloc_pages_offset(&mut self, offset: usize) -> Result<(), SvsmError> {
let start = offset / PAGE_SIZE;
for index in start..self.count {
self.alloc_page(index * PAGE_SIZE)?;
}
Ok(())
}

/// Allocates a full set of backing pages of type PageFile
///
/// # Returns
///
/// `Ok(())` when all pages could be allocated, `Err(SvsmError::Mem)` otherwise
pub fn alloc_pages(&mut self) -> Result<(), SvsmError> {
self.alloc_pages_offset(0)
}

/// Returns a reference to a page at a given index. The page must already
/// been allocated.
///
Expand Down Expand Up @@ -101,6 +124,61 @@ impl RawAllocMapping {
self.count * PAGE_SIZE
}

/// Change the size of the mapping. Note that the backing pages are not yet
/// freed when the mapping is shrinked. To free the pages a separate call to
/// the `flush()` method is required.
///
/// # Arguments
///
/// * `size` - The new size of the mapping. This will be rounded up to the
/// next PAGE_SIZE boundary.
///
/// # Returns
///
/// Returns `OK(new_aligned_size)` on success, `Err(SvsmError)` on failure.
pub fn resize(&mut self, size: usize) -> Result<usize, SvsmError> {
let size = align_up(size, PAGE_SIZE);
let old_size = self.mapping_size();

match size.cmp(&old_size) {
Ordering::Equal => Ok(size),
Ordering::Greater => {
// Increase pages vector
let diff_count = (size - old_size) / PAGE_SIZE;
let new_total_count = size / PAGE_SIZE;
// Reserve memory in pages vector
self.pages
.try_reserve_exact(diff_count)
.map_err(|_| SvsmError::Mem)?;
// Increase pages vector
self.pages.resize_with(new_total_count, || None);
self.count += diff_count;
// Try to allocate the pages
if let Err(e) = self.alloc_pages_offset(old_size) {
// Shrink pages vector
self.count -= diff_count;
// Free any stale backing pages
self.pages.truncate(self.count);
Err(e)
} else {
Ok(size)
}
}
Ordering::Less => {
self.count = size / PAGE_SIZE;
let mut old_pages = self.pages.split_off(self.count);
self.unmapped_pages.append(&mut old_pages);
Ok(size)
}
}
}

/// Free unmapped pages. This needs to be called after the unmapped pages
/// have been flushed out of all TLBs.
pub fn flush(&mut self) {
self.unmapped_pages.clear();
}

/// Request physical address to map for a given offset
///
/// # Arguments
Expand Down
8 changes: 8 additions & 0 deletions kernel/src/mm/vm/mapping/vmalloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ impl VirtualMapping for VMalloc {
self.alloc.mapping_size()
}

fn resize(&mut self, size: usize) -> Result<usize, SvsmError> {
self.alloc.resize(size)
}

fn flush(&mut self) {
self.alloc.flush();
}

fn map(&self, offset: usize) -> Option<PhysAddr> {
self.alloc.map(offset)
}
Expand Down
Loading