starina_api/
folio.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! A contiguous page-aliged memory block.
use starina_types::address::PAddr;
use starina_types::address::VAddr;
use starina_types::error::FtlError;
use starina_types::vmspace::PageProtect;
use starina_utils::alignment::align_down;
use starina_utils::alignment::align_up;

use crate::handle::OwnedHandle;
use crate::start::app_vmspace_handle;
use crate::syscall;

/// The ownership of a contiguous page-aliged memory region.
///
/// To summarize:
///
/// - The memory block address is page-aligned (typically 4KB).
/// - The memory block size is also page-aligned.
/// - The memory block is *physically* contiguous.
///
/// # When to use
///
/// Use folio when you need a *physically contiguous* memory region. The common
/// case is when you need to allocate a DMA buffer in a device driver (strictly
/// speaking, when IOMMU is not available).
///
/// # Prefer [`Box<T>`](crate::prelude::Box) over folio
///
/// Unless you need low-level control over memory allocation, use containers
/// like [`Vec<T>`](crate::prelude::Vec) or [`Box<T>`](crate::prelude::Box)
/// memory regions directly, such as DMA buffers, MMIO regions, and shared
/// instead of folio. Folio is intended for OS services that need to manage
/// memory between processes.
///
/// # You may want [`MappedFolio`] instead
///
/// If you want to access the memory region, use [`MappedFolio`] instead.
///
/// # Why "folio"?
///
/// Because it's *a sheet of paper (pages)*.
pub struct Folio {
    handle: OwnedHandle,
}

impl Folio {
    pub fn create(len: usize) -> Result<Folio, FtlError> {
        let handle = syscall::folio_create(len)?;
        Ok(Folio {
            handle: OwnedHandle::from_raw(handle),
        })
    }

    pub fn handle(&self) -> &OwnedHandle {
        &self.handle
    }

    pub fn paddr(&self) -> Result<PAddr, FtlError> {
        let paddr = syscall::folio_paddr(self.handle.id())?;
        let paddr = PAddr::new(paddr);
        Ok(paddr)
    }
}

/// A folio mapped to the current process's address space.
pub struct MappedFolio {
    _folio: Folio,
    paddr: PAddr,
    vaddr: VAddr,
}

impl MappedFolio {
    /// Allocates a folio at an arbitrary physical address, and maps it to the
    /// current process's address space.
    pub fn create(len: usize) -> Result<MappedFolio, FtlError> {
        let handle = syscall::folio_create(len)?;
        let vaddr = syscall::vmspace_map(
            app_vmspace_handle(),
            len,
            handle,
            PageProtect::READABLE | PageProtect::WRITABLE,
        )?;
        let paddr = syscall::folio_paddr(handle)?;
        Ok(MappedFolio {
            _folio: Folio {
                handle: OwnedHandle::from_raw(handle),
            },
            paddr: PAddr::new(paddr),
            vaddr,
        })
    }

    /// Allocates a folio at a specific physical address (`paddr`), and maps it to the
    /// current process's address space.
    pub fn create_pinned(paddr: PAddr, len: usize) -> Result<MappedFolio, FtlError> {
        let offset = paddr.as_usize() % 4096; // FIXME:
        let map_paddr = PAddr::new(align_down(paddr.as_usize(), 4096));
        let map_len = align_up(len, 4096);

        let handle = syscall::folio_create_fixed(map_paddr, map_len)?;
        let vaddr = syscall::vmspace_map(
            app_vmspace_handle(),
            map_len,
            handle,
            PageProtect::READABLE | PageProtect::WRITABLE,
        )?;

        Ok(MappedFolio {
            _folio: Folio {
                handle: OwnedHandle::from_raw(handle),
            },
            paddr,
            vaddr: vaddr.add(offset),
        })
    }

    /// Returns the start address of the folio in the current process's address space.
    pub fn vaddr(&self) -> VAddr {
        self.vaddr
    }

    /// Returns the start address of the folio in physical memory space.
    pub fn paddr(&self) -> PAddr {
        self.paddr
    }
}