use crate::{
bindings,
error::{code::EINVAL, to_result, Result},
mm::MmWithUser,
page::Page,
types::Opaque,
};
use core::ops::Deref;
#[repr(transparent)]
pub struct VmaRef {
vma: Opaque<bindings::vm_area_struct>,
}
impl VmaRef {
#[inline]
pub unsafe fn from_raw<'a>(vma: *const bindings::vm_area_struct) -> &'a Self {
unsafe { &*vma.cast() }
}
#[inline]
pub fn as_ptr(&self) -> *mut bindings::vm_area_struct {
self.vma.get()
}
#[inline]
pub fn mm(&self) -> &MmWithUser {
unsafe { MmWithUser::from_raw((*self.as_ptr()).vm_mm) }
}
#[inline]
pub fn flags(&self) -> vm_flags_t {
unsafe { (*self.as_ptr()).__bindgen_anon_2.vm_flags }
}
#[inline]
pub fn start(&self) -> usize {
unsafe { (*self.as_ptr()).__bindgen_anon_1.__bindgen_anon_1.vm_start }
}
#[inline]
pub fn end(&self) -> usize {
unsafe { (*self.as_ptr()).__bindgen_anon_1.__bindgen_anon_1.vm_end }
}
#[inline]
pub fn zap_vma_range(&self, address: usize, size: usize) {
let (end, did_overflow) = address.overflowing_add(size);
if did_overflow || address < self.start() || self.end() < end {
return;
}
unsafe { bindings::zap_vma_range(self.as_ptr(), address, size) };
}
#[inline]
pub fn as_mixedmap_vma(&self) -> Option<&VmaMixedMap> {
if self.flags() & flags::MIXEDMAP != 0 {
Some(unsafe { VmaMixedMap::from_raw(self.as_ptr()) })
} else {
None
}
}
}
#[repr(transparent)]
pub struct VmaMixedMap {
vma: VmaRef,
}
impl Deref for VmaMixedMap {
type Target = VmaRef;
#[inline]
fn deref(&self) -> &VmaRef {
&self.vma
}
}
impl VmaMixedMap {
#[inline]
pub unsafe fn from_raw<'a>(vma: *const bindings::vm_area_struct) -> &'a Self {
unsafe { &*vma.cast() }
}
#[inline]
pub fn vm_insert_page(&self, address: usize, page: &Page) -> Result {
to_result(unsafe { bindings::vm_insert_page(self.as_ptr(), address, page.as_ptr()) })
}
}
#[repr(transparent)]
pub struct VmaNew {
vma: VmaRef,
}
impl Deref for VmaNew {
type Target = VmaRef;
#[inline]
fn deref(&self) -> &VmaRef {
&self.vma
}
}
impl VmaNew {
#[inline]
pub unsafe fn from_raw<'a>(vma: *mut bindings::vm_area_struct) -> &'a Self {
unsafe { &*vma.cast() }
}
#[inline]
unsafe fn update_flags(&self, set: vm_flags_t, unset: vm_flags_t) {
let mut flags = self.flags();
flags |= set;
flags &= !unset;
unsafe { (*self.as_ptr()).__bindgen_anon_2.vm_flags = flags };
}
#[inline]
pub fn set_mixedmap(&self) -> &VmaMixedMap {
unsafe { self.update_flags(flags::MIXEDMAP, 0) };
unsafe { VmaMixedMap::from_raw(self.vma.as_ptr()) }
}
#[inline]
pub fn set_io(&self) {
unsafe { self.update_flags(flags::IO, 0) };
}
#[inline]
pub fn set_dontexpand(&self) {
unsafe { self.update_flags(flags::DONTEXPAND, 0) };
}
#[inline]
pub fn set_dontcopy(&self) {
unsafe { self.update_flags(flags::DONTCOPY, 0) };
}
#[inline]
pub fn set_dontdump(&self) {
unsafe { self.update_flags(flags::DONTDUMP, 0) };
}
#[inline]
pub fn readable(&self) -> bool {
(self.flags() & flags::READ) != 0
}
#[inline]
pub fn try_clear_mayread(&self) -> Result {
if self.readable() {
return Err(EINVAL);
}
unsafe { self.update_flags(0, flags::MAYREAD) };
Ok(())
}
#[inline]
pub fn writable(&self) -> bool {
(self.flags() & flags::WRITE) != 0
}
#[inline]
pub fn try_clear_maywrite(&self) -> Result {
if self.writable() {
return Err(EINVAL);
}
unsafe { self.update_flags(0, flags::MAYWRITE) };
Ok(())
}
#[inline]
pub fn executable(&self) -> bool {
(self.flags() & flags::EXEC) != 0
}
#[inline]
pub fn try_clear_mayexec(&self) -> Result {
if self.executable() {
return Err(EINVAL);
}
unsafe { self.update_flags(0, flags::MAYEXEC) };
Ok(())
}
}
#[doc(inline)]
pub use bindings::vm_flags_t;
pub mod flags {
use super::vm_flags_t;
use crate::bindings;
pub const NONE: vm_flags_t = bindings::VM_NONE as vm_flags_t;
pub const READ: vm_flags_t = bindings::VM_READ as vm_flags_t;
pub const WRITE: vm_flags_t = bindings::VM_WRITE as vm_flags_t;
pub const EXEC: vm_flags_t = bindings::VM_EXEC as vm_flags_t;
pub const SHARED: vm_flags_t = bindings::VM_SHARED as vm_flags_t;
pub const MAYREAD: vm_flags_t = bindings::VM_MAYREAD as vm_flags_t;
pub const MAYWRITE: vm_flags_t = bindings::VM_MAYWRITE as vm_flags_t;
pub const MAYEXEC: vm_flags_t = bindings::VM_MAYEXEC as vm_flags_t;
pub const MAYSHARE: vm_flags_t = bindings::VM_MAYSHARE as vm_flags_t;
pub const PFNMAP: vm_flags_t = bindings::VM_PFNMAP as vm_flags_t;
pub const IO: vm_flags_t = bindings::VM_IO as vm_flags_t;
pub const DONTCOPY: vm_flags_t = bindings::VM_DONTCOPY as vm_flags_t;
pub const DONTEXPAND: vm_flags_t = bindings::VM_DONTEXPAND as vm_flags_t;
pub const LOCKONFAULT: vm_flags_t = bindings::VM_LOCKONFAULT as vm_flags_t;
pub const ACCOUNT: vm_flags_t = bindings::VM_ACCOUNT as vm_flags_t;
pub const NORESERVE: vm_flags_t = bindings::VM_NORESERVE as vm_flags_t;
pub const HUGETLB: vm_flags_t = bindings::VM_HUGETLB as vm_flags_t;
pub const SYNC: vm_flags_t = bindings::VM_SYNC as vm_flags_t;
pub const ARCH_1: vm_flags_t = bindings::VM_ARCH_1 as vm_flags_t;
pub const WIPEONFORK: vm_flags_t = bindings::VM_WIPEONFORK as vm_flags_t;
pub const DONTDUMP: vm_flags_t = bindings::VM_DONTDUMP as vm_flags_t;
pub const SOFTDIRTY: vm_flags_t = bindings::VM_SOFTDIRTY as vm_flags_t;
pub const MIXEDMAP: vm_flags_t = bindings::VM_MIXEDMAP as vm_flags_t;
pub const HUGEPAGE: vm_flags_t = bindings::VM_HUGEPAGE as vm_flags_t;
pub const NOHUGEPAGE: vm_flags_t = bindings::VM_NOHUGEPAGE as vm_flags_t;
pub const MERGEABLE: vm_flags_t = bindings::VM_MERGEABLE as vm_flags_t;
}