Skip to content

Commit

Permalink
Merge pull request #161 from xxchan/vm-doc
Browse files Browse the repository at this point in the history
Add missing docs for `zircon_object::vm`
  • Loading branch information
wangrunji0408 committed Aug 21, 2020
2 parents 00a3ad1 + cd79eb5 commit b758322
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 9 deletions.
20 changes: 13 additions & 7 deletions zircon-object/src/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![deny(missing_docs)]
//! Objects for Virtual Memory Management.

mod stream;
Expand All @@ -21,42 +22,47 @@ pub type DevVAddr = usize;

/// Size of a page
pub const PAGE_SIZE: usize = 0x1000;

/// log2(PAGE_SIZE)
pub const PAGE_SIZE_LOG2: usize = 12;

/// Check whether `x` is a multiple of `PAGE_SIZE`.
pub fn page_aligned(x: usize) -> bool {
x % PAGE_SIZE == 0
check_aligned(x, PAGE_SIZE)
}

/// Check whether `x` is a multiple of `align`.
pub fn check_aligned(x: usize, align: usize) -> bool {
x % align == 0
}

/// How many pages the `size` needs.
/// To avoid overflow and pass more unit tests, use wrapping add
pub fn pages(size: usize) -> usize {
size.wrapping_add(PAGE_SIZE - 1) / PAGE_SIZE
ceil(size, PAGE_SIZE)
}

/// How many `align` the `x` needs.
pub fn ceil(x: usize, align: usize) -> usize {
x.wrapping_add(align - 1) / align
}

/// Round up `size` to a multiple of `PAGE_SIZE`.
pub fn roundup_pages(size: usize) -> usize {
if page_aligned(size) {
size
} else {
pages(size) * PAGE_SIZE
}
pages(size) * PAGE_SIZE
}

/// Round down `size` to a multiple of `PAGE_SIZE`.
pub fn round_down_pages(size: usize) -> usize {
size / PAGE_SIZE * PAGE_SIZE
}

lazy_static! {
/// Kernel address space.
pub static ref KERNEL_ASPACE: Arc<VmAddressRegion> = VmAddressRegion::new_kernel();
}

/// Allocate memory in kernel address space at given physical address.
pub fn kernel_allocate_physical(
size: usize,
paddr: PhysAddr,
Expand Down
5 changes: 5 additions & 0 deletions zircon-object/src/vm/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ impl_kobject!(Stream);
numeric_enum! {
#[repr(usize)]
#[derive(Debug)]
/// Enumeration of possible methods to modify the seek within an Stream.
pub enum SeekOrigin {
/// Set the seek offset relative to the start of the stream.
Start = 0,
/// Set the seek offset relative to the current seek offset of the stream.
Current = 1,
/// Set the seek offset relative to the end of the stream, as defined by the content size of the stream.
End = 2,
}
}
Expand Down Expand Up @@ -122,6 +126,7 @@ impl Stream {
}
}

/// Information of a Stream
#[repr(C)]
#[derive(Default)]
pub struct StreamInfo {
Expand Down
33 changes: 32 additions & 1 deletion zircon-object/src/vm/vmar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,34 @@ use {
};

bitflags! {
/// Creation flags for VmAddressRegion.
pub struct VmarFlags: u32 {
#[allow(clippy::identity_op)]
/// When randomly allocating subregions, reduce sprawl by placing allocations
/// near each other.
const COMPACT = 1 << 0;
/// Request that the new region be at the specified offset in its parent region.
const SPECIFIC = 1 << 1;
/// Like SPECIFIC, but permits overwriting existing mappings. This
/// flag will not overwrite through a subregion.
const SPECIFIC_OVERWRITE = 1 << 2;
/// Allow VmMappings to be created inside the new region with the SPECIFIC or
/// OFFSET_IS_UPPER_LIMIT flag.
const CAN_MAP_SPECIFIC = 1 << 3;
/// Allow VmMappings to be created inside the region with read permissions.
const CAN_MAP_READ = 1 << 4;
/// Allow VmMappings to be created inside the region with write permissions.
const CAN_MAP_WRITE = 1 << 5;
/// Allow VmMappings to be created inside the region with execute permissions.
const CAN_MAP_EXECUTE = 1 << 6;
/// Require that VMO backing the mapping is non-resizable.
const REQUIRE_NON_RESIZABLE = 1 << 7;
/// Treat the offset as an upper limit when allocating a VMO or child VMAR.
const ALLOW_FAULTS = 1 << 8;

/// Allow VmMappings to be created inside the region with read, write and execute permissions.
const CAN_MAP_RXW = Self::CAN_MAP_READ.bits | Self::CAN_MAP_EXECUTE.bits | Self::CAN_MAP_WRITE.bits;
/// Creation flags for root VmAddressRegion
const ROOT_FLAGS = Self::CAN_MAP_RXW.bits | Self::CAN_MAP_SPECIFIC.bits;
}
}
Expand Down Expand Up @@ -132,6 +148,7 @@ impl VmAddressRegion {
Ok(child)
}

/// Map the `vmo` into this VMAR at given `offset`.
pub fn map_at(
&self,
vmar_offset: usize,
Expand Down Expand Up @@ -166,6 +183,7 @@ impl VmAddressRegion {
)
}

/// Map the `vmo` into this VMAR.
pub fn map(
&self,
vmar_offset: Option<usize>,
Expand Down Expand Up @@ -265,6 +283,9 @@ impl VmAddressRegion {
Ok(())
}

/// Change protections on a subset of the region of memory in the containing
/// address space. If the requested range overlaps with a subregion,
/// protect() will fail.
pub fn protect(&self, addr: usize, len: usize, flags: MMUFlags) -> ZxResult {
let mut guard = self.inner.lock();
let inner = guard.as_mut().ok_or(ZxError::BAD_STATE)?;
Expand Down Expand Up @@ -349,10 +370,12 @@ impl VmAddressRegion {
self.addr
}

/// Whether this VMAR is dead.
pub fn is_dead(&self) -> bool {
self.inner.lock().is_none()
}

/// Whether this VMAR is alive.
pub fn is_alive(&self) -> bool {
!self.is_dead()
}
Expand Down Expand Up @@ -439,13 +462,15 @@ impl VmAddressRegion {
self.addr <= vaddr && vaddr < self.end_addr()
}

/// Get information of this VmAddressRegion
pub fn get_info(&self) -> VmarInfo {
VmarInfo {
base: self.addr(),
len: self.size,
}
}

/// Get VmarFlags of this VMAR.
pub fn get_flags(&self) -> VmarFlags {
self.flags
}
Expand All @@ -462,6 +487,7 @@ impl VmAddressRegion {
}
}

/// Get base address of vdso.
pub fn vdso_base_addr(&self) -> Option<usize> {
let guard = self.inner.lock();
let inner = guard.as_ref().unwrap();
Expand Down Expand Up @@ -514,6 +540,7 @@ impl VmAddressRegion {
inner.fork_from(src, &self.page_table)
}

/// Returns statistics about memory used by a task.
pub fn get_task_stats(&self) -> TaskStatsInfo {
let mut task_stats = TaskStatsInfo::default();
self.for_each_mapping(&mut |map| map.fill_in_task_status(&mut task_stats));
Expand Down Expand Up @@ -595,6 +622,7 @@ impl VmarInner {
}
}

/// Information of a VmAddressRegion.
#[repr(C)]
#[derive(Debug)]
pub struct VmarInfo {
Expand All @@ -617,6 +645,7 @@ struct VmMappingInner {
vmo_offset: usize,
}

/// Statistics about resources (e.g., memory) used by a task.
#[repr(C)]
#[derive(Default)]
pub struct TaskStatsInfo {
Expand Down Expand Up @@ -807,6 +836,7 @@ impl VmMapping {
self.inner.lock().end_addr()
}

/// Get MMUFlags of this VmMapping.
pub fn get_flags(&self) -> MMUFlags {
self.flags
}
Expand All @@ -831,7 +861,8 @@ impl VmMapping {
}
}

pub fn handle_page_fault(&self, vaddr: VirtAddr, flags: MMUFlags) -> ZxResult {
/// Handle page fault happened on this VmMapping.
pub(crate) fn handle_page_fault(&self, vaddr: VirtAddr, flags: MMUFlags) -> ZxResult {
if !self.flags.contains(flags) {
return Err(ZxError::ACCESS_DENIED);
}
Expand Down
54 changes: 53 additions & 1 deletion zircon-object/src/vm/vmo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod slice;
kcounter!(VMO_PAGE_ALLOC, "vmo.page_alloc");
kcounter!(VMO_PAGE_DEALLOC, "vmo.page_dealloc");

/// The amount of memory committed to VMOs.
pub fn vmo_page_bytes() -> usize {
(VMO_PAGE_ALLOC.get() - VMO_PAGE_DEALLOC.get()) * PAGE_SIZE
}
Expand Down Expand Up @@ -69,38 +70,58 @@ pub trait VMObjectTrait: Sync + Send {
user_id: KoID,
) -> ZxResult<Arc<dyn VMObjectTrait>>;

/// Append a mapping to the VMO's mapping list.
fn append_mapping(&self, mapping: Weak<VmMapping>);

/// Remove a mapping from the VMO's mapping list.
fn remove_mapping(&self, mapping: Weak<VmMapping>);

/// Complete the VmoInfo.
fn complete_info(&self, info: &mut VmoInfo);

/// Get the cache policy.
fn cache_policy(&self) -> CachePolicy;

/// Set the cache policy.
fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult;

/// Returns an estimate of the number of unique VmAspaces that this object
/// is mapped into.
fn share_count(&self) -> usize;

/// Count committed pages of the VMO.
fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize;

/// Pin the given range of the VMO.
fn pin(&self, _offset: usize, _len: usize) -> ZxResult {
Err(ZxError::NOT_SUPPORTED)
}

/// Unpin the given range of the VMO.
fn unpin(&self, _offset: usize, _len: usize) -> ZxResult {
Err(ZxError::NOT_SUPPORTED)
}

/// Returns true if the object is backed by a contiguous range of physical memory.
fn is_contiguous(&self) -> bool {
false
}

/// Returns true if the object is backed by RAM.
fn is_paged(&self) -> bool {
false
}

/// Resets the range of bytes in the VMO from `offset` to `offset+len` to 0.
fn zero(&self, offset: usize, len: usize) -> ZxResult;
}

/// Virtual memory containers
///
/// ## SYNOPSIS
///
/// A Virtual Memory Object (VMO) represents a contiguous region of virtual memory
/// that may be mapped into multiple address spaces.
pub struct VmObject {
base: KObjectBase,
parent: Mutex<Weak<VmObject>>, // Parent could be changed
Expand All @@ -119,6 +140,7 @@ impl VmObject {
Self::new_paged_with_resizable(false, pages)
}

/// Create a new VMO, which can be resizable, backing on physical memory allocated in pages.
pub fn new_paged_with_resizable(resizable: bool, pages: usize) -> Arc<Self> {
let base = KObjectBase::with_signal(Signal::VMO_ZERO_CHILDREN);
Arc::new(VmObject {
Expand All @@ -143,6 +165,7 @@ impl VmObject {
})
}

/// Create a VM object referring to a specific contiguous range of physical frame.
pub fn new_contiguous(p_size: usize, align_log2: usize) -> ZxResult<Arc<Self>> {
assert!(align_log2 < 8 * core::mem::size_of::<usize>());
let size = roundup_pages(p_size);
Expand Down Expand Up @@ -295,17 +318,20 @@ impl VmObject {
ret
}

/// Set the cache policy.
pub fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult {
if self.children.lock().len() != 0 {
return Err(ZxError::BAD_STATE);
}
self.inner.set_cache_policy(policy)
}

/// Returns true if the object size can be changed.
pub fn is_resizable(&self) -> bool {
self.resizable
}

/// Returns true if the object is backed by a contiguous range of physical memory.
pub fn is_contiguous(&self) -> bool {
self.inner.is_contiguous()
}
Expand Down Expand Up @@ -387,21 +413,47 @@ pub struct VmoInfo {

bitflags! {
#[derive(Default)]
/// Values used by ZX_INFO_PROCESS_VMOS.
pub struct VmoInfoFlags: u32 {
/// The VMO points to a physical address range, and does not consume memory.
/// Typically used to access memory-mapped hardware.
/// Mutually exclusive with TYPE_PAGED.
const TYPE_PHYSICAL = 0;

#[allow(clippy::identity_op)]
/// The VMO is backed by RAM, consuming memory.
/// Mutually exclusive with TYPE_PHYSICAL.
const TYPE_PAGED = 1 << 0;

/// The VMO is resizable.
const RESIZABLE = 1 << 1;

/// The VMO is a child, and is a copy-on-write clone.
const IS_COW_CLONE = 1 << 2;

/// When reading a list of VMOs pointed to by a process, indicates that the
/// process has a handle to the VMO, which isn't necessarily mapped.
const VIA_HANDLE = 1 << 3;

/// When reading a list of VMOs pointed to by a process, indicates that the
/// process maps the VMO into a VMAR, but doesn't necessarily have a handle to
/// the VMO.
const VIA_MAPPING = 1 << 4;

/// The VMO is a pager owned VMO created by zx_pager_create_vmo or is
/// a clone of a VMO with this flag set. Will only be set on VMOs with
/// the ZX_INFO_VMO_TYPE_PAGED flag set.
const PAGER_BACKED = 1 << 5;

/// The VMO is contiguous.
const CONTIGUOUS = 1 << 6;
}
}

/// Different operations that `range_change` can perform against any VmMappings that are found.
#[allow(dead_code)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum RangeChangeOp {
pub(super) enum RangeChangeOp {
Unmap,
RemoveWrite,
}
Expand Down

0 comments on commit b758322

Please sign in to comment.