Skip to content

Commit

Permalink
Merge pull request #145 from roy-hopkins/fs_view_main
Browse files Browse the repository at this point in the history
fs: Add VMFileMapping to map ramfs file contents to virtual memory
  • Loading branch information
joergroedel authored Nov 20, 2023
2 parents eecf4ce + a946a91 commit 79fcc93
Show file tree
Hide file tree
Showing 16 changed files with 874 additions and 22 deletions.
9 changes: 8 additions & 1 deletion src/cpu/idt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Author: Joerg Roedel <[email protected]>

use super::control_regs::read_cr2;
use super::percpu::this_cpu;
use super::tss::IST_DF;
use super::vc::handle_vc_exception;
use super::{X86GeneralRegs, X86InterruptFrame};
Expand Down Expand Up @@ -39,6 +40,8 @@ pub const _HV_VECTOR: usize = 28;
pub const VC_VECTOR: usize = 29;
pub const _SX_VECTOR: usize = 30;

pub const PF_ERROR_WRITE: usize = 2;

#[repr(C, packed)]
#[derive(Default, Debug, Clone, Copy)]
pub struct X86ExceptionContext {
Expand Down Expand Up @@ -198,7 +201,11 @@ fn generic_idt_handler(ctx: &mut X86ExceptionContext) {
let rip = ctx.frame.rip;
let err = ctx.error_code;

if !handle_exception_table(ctx) {
if this_cpu()
.handle_pf(VirtAddr::from(cr2), (err & PF_ERROR_WRITE) != 0)
.is_err()
&& !handle_exception_table(ctx)
{
panic!(
"Unhandled Page-Fault at RIP {:#018x} CR2: {:#018x} error code: {:#018x}",
rip, cr2, err
Expand Down
4 changes: 4 additions & 0 deletions src/cpu/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ impl PerCpu {
pub fn populate_page_table(&self, pt: &mut PageTableRef) {
self.vm_range.populate(pt);
}

pub fn handle_pf(&self, vaddr: VirtAddr, write: bool) -> Result<(), SvsmError> {
self.vm_range.handle_page_fault(vaddr, write)
}
}

unsafe impl Sync for PerCpu {}
Expand Down
2 changes: 2 additions & 0 deletions src/fs/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use alloc::vec::Vec;
use core::fmt::Debug;

use crate::error::SvsmError;
use crate::mm::PageRef;
use crate::string::FixedString;
use packit::PackItError;

Expand Down Expand Up @@ -64,6 +65,7 @@ pub trait File: Debug + Send + Sync {
fn write(&self, buf: &[u8], offset: usize) -> Result<usize, SvsmError>;
fn truncate(&self, size: usize) -> Result<usize, SvsmError>;
fn size(&self) -> usize;
fn mapping(&self, offset: usize) -> Option<PageRef>;
}

pub trait Directory: Debug + Send + Sync {
Expand Down
9 changes: 9 additions & 0 deletions src/fs/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use super::*;

use crate::error::SvsmError;
use crate::locking::SpinLock;
use crate::mm::PageRef;

use core::cmp::min;

Expand Down Expand Up @@ -57,6 +58,10 @@ impl RawFileHandle {
fn size(&self) -> usize {
self.file.size()
}

fn mapping(&self, offset: usize) -> Option<PageRef> {
self.file.mapping(offset)
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -97,6 +102,10 @@ impl FileHandle {
pub fn position(&self) -> usize {
self.handle.lock().current
}

pub fn mapping(&self, offset: usize) -> Option<PageRef> {
self.handle.lock().mapping(offset)
}
}

#[derive(Debug)]
Expand Down
90 changes: 89 additions & 1 deletion src/fs/ramfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::*;
use crate::error::SvsmError;
use crate::locking::RWLock;
use crate::mm::{allocate_file_page_ref, PageRef};
use crate::types::PAGE_SIZE;
use crate::types::{PAGE_SHIFT, PAGE_SIZE};
use crate::utils::{page_align_up, page_offset, zero_mem_region};

extern crate alloc;
Expand Down Expand Up @@ -164,6 +164,13 @@ impl RawRamFile {
fn size(&self) -> usize {
self.size
}

fn mapping(&self, offset: usize) -> Option<PageRef> {
if offset > self.size() {
return None;
}
self.pages.get(offset >> PAGE_SHIFT).cloned()
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -196,6 +203,10 @@ impl File for RamFile {
fn size(&self) -> usize {
self.rawfile.lock_read().size()
}

fn mapping(&self, offset: usize) -> Option<PageRef> {
self.rawfile.lock_read().mapping(offset)
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -392,4 +403,81 @@ mod tests {
let list = ram_dir.list();
assert_eq!(list, [f_name]);
}

#[test]
#[cfg_attr(test_in_svsm, ignore = "FIXME")]
fn test_ramfs_single_page_mapping() {
let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE);

let file = RamFile::new();
let buf = [0xffu8; 512];

file.write(&buf, 0).expect("Failed to write file data");

let res = file
.mapping(0)
.expect("Failed to get mapping for ramfs page");
assert_eq!(
res.phys_addr(),
file.rawfile.lock_read().pages[0].phys_addr()
);
drop(file);
}

#[test]
#[cfg_attr(test_in_svsm, ignore = "FIXME")]
fn test_ramfs_multi_page_mapping() {
let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE);

let file = RamFile::new();
let buf = [0xffu8; 4 * PAGE_SIZE];

file.write(&buf, 0).expect("Failed to write file data");

for i in 0..4 {
let res = file
.mapping(i * PAGE_SIZE)
.expect("Failed to get mapping for ramfs page");
assert_eq!(
res.phys_addr(),
file.rawfile.lock_read().pages[i].phys_addr()
);
}
drop(file);
}

#[test]
#[cfg_attr(test_in_svsm, ignore = "FIXME")]
fn test_ramfs_mapping_unaligned_offset() {
let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE);

let file = RamFile::new();
let buf = [0xffu8; 4 * PAGE_SIZE];

file.write(&buf, 0).expect("Failed to write file data");

let res = file
.mapping(PAGE_SIZE + 0x123)
.expect("Failed to get mapping for ramfs page");
assert_eq!(
res.phys_addr(),
file.rawfile.lock_read().pages[1].phys_addr()
);
drop(file);
}

#[test]
#[cfg_attr(test_in_svsm, ignore = "FIXME")]
fn test_ramfs_mapping_out_of_range() {
let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE);

let file = RamFile::new();
let buf = [0xffu8; 4 * PAGE_SIZE];

file.write(&buf, 0).expect("Failed to write file data");

let res = file.mapping(4 * PAGE_SIZE);
assert!(res.is_none());
drop(file);
}
}
55 changes: 52 additions & 3 deletions src/mm/vm/mapping/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
// Author: Joerg Roedel <[email protected]>

use crate::address::{PhysAddr, VirtAddr};
use crate::error::SvsmError;
use crate::locking::{RWLock, ReadLockGuard, WriteLockGuard};
use crate::mm::pagetable::PTEntryFlags;
use crate::mm::vm::VMR;
use crate::types::{PAGE_SHIFT, PAGE_SIZE};

use intrusive_collections::rbtree::Link;
Expand All @@ -18,6 +20,16 @@ extern crate alloc;
use alloc::boxed::Box;
use alloc::sync::Arc;

/// Information required to resolve a page fault within a virtual mapping
pub struct VMPageFaultResolution {
/// The physical address of a page that must be mapped to the page fault
/// virtual address to resolve the page fault.
pub paddr: PhysAddr,

/// The flags to use to map the virtual memory page.
pub flags: PTEntryFlags,
}

pub trait VirtualMapping: core::fmt::Debug {
/// Request the size of the virtual memory mapping
///
Expand Down Expand Up @@ -48,14 +60,23 @@ pub trait VirtualMapping: core::fmt::Debug {
// Provide default in case there is nothing to do
}

/// Request the PTEntryFlags used for this virtual memory mapping. This is
/// a combination of
/// Request the PTEntryFlags used for this virtual memory mapping.
///
/// # Arguments
///
/// * 'offset' -> The offset in bytes into the `VirtualMapping`. The flags
/// returned from this function relate to the page at the
/// given offset
///
/// # Returns
///
/// A combination of:
/// * PTEntryFlags::WRITABLE
/// * PTEntryFlags::NX,
/// * PTEntryFlags::ACCESSED
/// * PTEntryFlags::DIRTY
fn pt_flags(&self) -> PTEntryFlags;
fn pt_flags(&self, offset: usize) -> PTEntryFlags;

/// Request the page size used for mappings
///
Expand All @@ -78,6 +99,30 @@ pub trait VirtualMapping: core::fmt::Debug {
// Shared with the HV - defaults not No
false
}

/// Handle a page fault that occurred on a virtual memory address within
/// this mapping.
///
/// # Arguments
///
/// * 'vmr' - Virtual memory range that contains the mapping. This
/// [`VirtualMapping`] can use this to insert/remove regions
/// as necessary to handle the page fault.
///
/// * `offset` - Offset into the virtual mapping that was the subject of
/// the page fault.
///
/// * 'write' - `true` if the fault was due to a write to the memory
/// location, or 'false' if the fault was due to a read.
///
fn handle_page_fault(
&mut self,
_vmr: &VMR,
_offset: usize,
_write: bool,
) -> Result<VMPageFaultResolution, SvsmError> {
Err(SvsmError::Mem)
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -186,4 +231,8 @@ impl VMM {
pub fn get_mapping_mut(&self) -> WriteLockGuard<Box<dyn VirtualMapping>> {
self.mapping.get_mut()
}

pub fn get_mapping_clone(&self) -> Arc<Mapping> {
self.mapping.clone()
}
}
Loading

0 comments on commit 79fcc93

Please sign in to comment.