Build the foundation for TLB shootdown.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! Global descriptor table
|
||||
|
||||
use core::{convert::TryInto, mem};
|
||||
use core::{convert::TryInto, mem, sync::atomic::AtomicUsize};
|
||||
|
||||
use crate::{
|
||||
cpu_set::LogicalCpuId,
|
||||
@@ -239,6 +239,7 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
pcr.percpu = PercpuBlock {
|
||||
cpu_id,
|
||||
switch_internals: Default::default(),
|
||||
nmi_flags_lock: AtomicUsize::new(0),
|
||||
|
||||
#[cfg(feature = "profiling")]
|
||||
profiling: None,
|
||||
|
||||
@@ -37,3 +37,18 @@ pub fn ipi(kind: IpiKind, target: IpiTarget) {
|
||||
let icr = (target as u64) << 18 | 1 << 14 | (kind as u64);
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
}
|
||||
#[cfg(feature = "multi_core")]
|
||||
#[inline(always)]
|
||||
pub fn ipi_single(kind: IpiKind, target: u32) {
|
||||
use crate::device::local_apic::LOCAL_APIC;
|
||||
|
||||
#[cfg(feature = "profiling")]
|
||||
if matches!(kind, IpiKind::Profile) {
|
||||
let icr = (target as u64) << 18 | 1 << 14 | 0b100 << 8;
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
return;
|
||||
}
|
||||
|
||||
let icr = u64::from(target) << 18 | 1 << 14 | (kind as u64);
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
}
|
||||
|
||||
+92
-52
@@ -98,22 +98,21 @@ pub struct AddrSpace {
|
||||
/// against null pointers, so fixed mmaps to address zero are still allowed.
|
||||
pub mmap_min: usize,
|
||||
}
|
||||
impl AddrSpace {
|
||||
pub fn current() -> Result<Arc<AddrSpaceWrapper>> {
|
||||
Ok(Arc::clone(super::current()?.read().addr_space()?))
|
||||
}
|
||||
|
||||
impl AddrSpaceWrapper {
|
||||
/// Attempt to clone an existing address space so that all mappings are copied (CoW).
|
||||
pub fn try_clone(&mut self) -> Result<Arc<AddrSpaceWrapper>> {
|
||||
pub fn try_clone(&self) -> Result<Arc<AddrSpaceWrapper>> {
|
||||
let mut guard = self.inner.write();
|
||||
let guard = &mut *guard;
|
||||
|
||||
let mut new_arc = AddrSpaceWrapper::new()?;
|
||||
|
||||
let new = Arc::get_mut(&mut new_arc)
|
||||
.expect("expected new address space Arc not to be aliased");
|
||||
|
||||
let this_mapper = &mut self.table.utable;
|
||||
let mut this_flusher = Flusher::with_cpu_set(&mut self.used_by);
|
||||
let this_mapper = &mut guard.table.utable;
|
||||
let mut this_flusher = Flusher::with_cpu_set(&mut guard.used_by, &self.tlb_ack);
|
||||
|
||||
for (grant_base, grant_info) in self.grants.iter() {
|
||||
for (grant_base, grant_info) in guard.grants.iter() {
|
||||
let new_grant = match grant_info.provider {
|
||||
// No, your temporary UserScheme mappings will not be kept across forks.
|
||||
Provider::External {
|
||||
@@ -191,23 +190,15 @@ impl AddrSpace {
|
||||
}
|
||||
Ok(new_arc)
|
||||
}
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
grants: UserGrants::new(),
|
||||
table: setup_new_utable()?,
|
||||
mmap_min: MMAP_MIN_DEFAULT,
|
||||
used_by: LogicalCpuSet::empty(),
|
||||
})
|
||||
}
|
||||
pub fn is_current(&self) -> bool {
|
||||
self.table.utable.is_current()
|
||||
}
|
||||
pub fn mprotect(&mut self, requested_span: PageSpan, flags: MapFlags) -> Result<()> {
|
||||
let mapper = &mut self.table.utable;
|
||||
let mut flusher = Flusher::with_cpu_set(&mut self.used_by);
|
||||
pub fn mprotect(&self, requested_span: PageSpan, flags: MapFlags) -> Result<()> {
|
||||
let mut guard = self.inner.write();
|
||||
let guard = &mut *guard;
|
||||
|
||||
let mapper = &mut guard.table.utable;
|
||||
let mut flusher = Flusher::with_cpu_set(&mut guard.used_by, &self.tlb_ack);
|
||||
|
||||
// TODO: Remove allocation (might require BTreeMap::set_key or interior mutability).
|
||||
let regions = self
|
||||
let regions = guard
|
||||
.grants
|
||||
.conflicts(requested_span)
|
||||
.map(|(base, info)| {
|
||||
@@ -222,7 +213,7 @@ impl AddrSpace {
|
||||
for grant_span_res in regions {
|
||||
let grant_span = grant_span_res?;
|
||||
|
||||
let grant = self
|
||||
let grant = guard
|
||||
.grants
|
||||
.remove(grant_span.base)
|
||||
.expect("grant cannot magically disappear while we hold the lock!");
|
||||
@@ -235,14 +226,14 @@ impl AddrSpace {
|
||||
//log::info!("Sliced into\n\n{:#?}\n\n{:#?}\n\n{:#?}", before, grant, after);
|
||||
|
||||
if let Some(before) = before {
|
||||
self.grants.insert(before);
|
||||
guard.grants.insert(before);
|
||||
}
|
||||
if let Some(after) = after {
|
||||
self.grants.insert(after);
|
||||
guard.grants.insert(after);
|
||||
}
|
||||
|
||||
if !grant.info.can_have_flags(flags) {
|
||||
self.grants.insert(grant);
|
||||
guard.grants.insert(grant);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
@@ -259,18 +250,38 @@ impl AddrSpace {
|
||||
|
||||
grant.remap(mapper, &mut flusher, new_flags);
|
||||
//log::info!("Mprotect grant became {:#?}", grant);
|
||||
self.grants.insert(grant);
|
||||
guard.grants.insert(grant);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[must_use = "needs to notify files"]
|
||||
pub fn munmap(
|
||||
&mut self,
|
||||
&self,
|
||||
mut requested_span: PageSpan,
|
||||
unpin: bool,
|
||||
) -> Result<Vec<UnmapResult>> {
|
||||
let mut flusher = Flusher::with_cpu_set(&mut self.used_by);
|
||||
Self::munmap_inner(&mut self.grants, &mut self.table.utable, &mut flusher, requested_span, unpin)
|
||||
let mut guard = self.inner.write();
|
||||
let guard = &mut *guard;
|
||||
|
||||
let mut flusher = Flusher::with_cpu_set(&mut guard.used_by, &self.tlb_ack);
|
||||
AddrSpace::munmap_inner(&mut guard.grants, &mut guard.table.utable, &mut flusher, requested_span, unpin)
|
||||
}
|
||||
}
|
||||
impl AddrSpace {
|
||||
pub fn current() -> Result<Arc<AddrSpaceWrapper>> {
|
||||
Ok(Arc::clone(super::current()?.read().addr_space()?))
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
grants: UserGrants::new(),
|
||||
table: setup_new_utable()?,
|
||||
mmap_min: MMAP_MIN_DEFAULT,
|
||||
used_by: LogicalCpuSet::empty(),
|
||||
})
|
||||
}
|
||||
pub fn is_current(&self) -> bool {
|
||||
self.table.utable.is_current()
|
||||
}
|
||||
fn munmap_inner(
|
||||
this_grants: &mut UserGrants,
|
||||
@@ -341,6 +352,7 @@ impl AddrSpace {
|
||||
}
|
||||
pub fn mmap_anywhere(
|
||||
&mut self,
|
||||
dst_lock: &AddrSpaceWrapper,
|
||||
page_count: NonZeroUsize,
|
||||
flags: MapFlags,
|
||||
map: impl FnOnce(
|
||||
@@ -350,10 +362,11 @@ impl AddrSpace {
|
||||
&mut Flusher,
|
||||
) -> Result<Grant>,
|
||||
) -> Result<Page> {
|
||||
self.mmap(None, page_count, flags, &mut Vec::new(), map)
|
||||
self.mmap(dst_lock, None, page_count, flags, &mut Vec::new(), map)
|
||||
}
|
||||
pub fn mmap(
|
||||
&mut self,
|
||||
dst_lock: &AddrSpaceWrapper,
|
||||
requested_base_opt: Option<Page>,
|
||||
page_count: NonZeroUsize,
|
||||
flags: MapFlags,
|
||||
@@ -378,7 +391,7 @@ impl AddrSpace {
|
||||
requested_span
|
||||
} else if flags.contains(MapFlags::MAP_FIXED) {
|
||||
let unpin = false;
|
||||
let mut notify_files = self.munmap(requested_span, unpin)?;
|
||||
let mut notify_files = Self::munmap_inner(&mut self.grants, &mut self.table.utable, &mut Flusher::with_cpu_set(&mut self.used_by, &dst_lock.tlb_ack), requested_span, unpin)?;
|
||||
notify_files_out.append(&mut notify_files);
|
||||
|
||||
requested_span
|
||||
@@ -403,24 +416,25 @@ impl AddrSpace {
|
||||
selected_span.base,
|
||||
page_flags(flags),
|
||||
&mut self.table.utable,
|
||||
&mut Flusher::with_cpu_set(&mut self.used_by),
|
||||
&mut Flusher::with_cpu_set(&mut self.used_by, &dst_lock.tlb_ack),
|
||||
)?;
|
||||
self.grants.insert(grant);
|
||||
|
||||
Ok(selected_span.base)
|
||||
}
|
||||
pub fn r#move(
|
||||
dst_lock: &AddrSpaceWrapper,
|
||||
dst: &mut AddrSpace,
|
||||
mut src_opt: Option<&mut AddrSpace>,
|
||||
mut src_opt: Option<(&AddrSpaceWrapper, &mut AddrSpace)>,
|
||||
src_span: PageSpan,
|
||||
requested_dst_base: Option<Page>,
|
||||
new_page_count: usize,
|
||||
new_flags: MapFlags,
|
||||
notify_files: &mut Vec<UnmapResult>,
|
||||
) -> Result<Page> {
|
||||
let mut src_owned_opt = src_opt.as_mut().map(|a| (&mut a.grants, &mut a.table.utable, Flusher::with_cpu_set(&mut a.used_by)));
|
||||
let mut src_owned_opt = src_opt.as_mut().map(|(aw, a)| (&mut a.grants, &mut a.table.utable, Flusher::with_cpu_set(&mut a.used_by, &aw.tlb_ack)));
|
||||
let mut src_opt = src_owned_opt.as_mut().map(|(g, m, f)| (&mut *g, &mut *m, &mut *f));
|
||||
let mut dst_flusher = Flusher::with_cpu_set(&mut dst.used_by);
|
||||
let mut dst_flusher = Flusher::with_cpu_set(&mut dst.used_by, &dst_lock.tlb_ack);
|
||||
|
||||
let dst_base = match requested_dst_base {
|
||||
Some(base) if new_flags.contains(MapFlags::MAP_FIXED_NOREPLACE) => {
|
||||
@@ -1155,13 +1169,14 @@ impl Grant {
|
||||
new_flags: PageFlags<RmmA>,
|
||||
file_ref: GrantFileRef,
|
||||
src: Option<BorrowedFmapSource<'_>>,
|
||||
lock: &AddrSpaceWrapper,
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: &mut Flusher,
|
||||
) -> Result<Self> {
|
||||
if let Some(src) = src {
|
||||
let mut guard = src.addr_space_guard;
|
||||
let mut src_addrspace = &mut *guard;
|
||||
let mut src_flusher_state = Flusher::with_cpu_set(&mut src_addrspace.used_by).detach();
|
||||
let mut src_flusher_state = Flusher::with_cpu_set(&mut src_addrspace.used_by, &lock.tlb_ack).detach();
|
||||
for dst_page in span.pages() {
|
||||
let src_page = src.src_base.next_by(dst_page.offset_from(span.base));
|
||||
|
||||
@@ -2463,37 +2478,62 @@ impl GenericFlusher for NopFlusher {
|
||||
core::mem::forget(flush);
|
||||
}
|
||||
}
|
||||
impl GenericFlusher for Flusher<'_> {
|
||||
impl GenericFlusher for Flusher<'_, '_> {
|
||||
fn consume(&mut self, flush: PageFlush<RmmA>) {
|
||||
self.state.dirty = true;
|
||||
|
||||
unsafe {
|
||||
flush.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
struct FlusherState {
|
||||
struct FlusherState<'addrsp> {
|
||||
// TODO: Track *which* pages shall be flushed, to avoid expensive cr3 reloads. Linux defaults
|
||||
// to approx. 32 INVLPGs before a CR3 reload is worth it.
|
||||
dirty: bool,
|
||||
ackword: &'addrsp AtomicU32,
|
||||
}
|
||||
|
||||
pub struct Flusher<'asp> {
|
||||
active_cpus: &'asp mut LogicalCpuSet,
|
||||
state: FlusherState,
|
||||
pub struct Flusher<'guard, 'addrsp> {
|
||||
active_cpus: &'guard mut LogicalCpuSet,
|
||||
state: FlusherState<'addrsp>,
|
||||
}
|
||||
impl<'asp> Flusher<'asp> {
|
||||
fn with_cpu_set(set: &'asp mut LogicalCpuSet) -> Self {
|
||||
impl<'guard, 'addrsp> Flusher<'guard, 'addrsp> {
|
||||
fn with_cpu_set(set: &'guard mut LogicalCpuSet, ackword: &'addrsp AtomicU32) -> Self {
|
||||
Self {
|
||||
active_cpus: set,
|
||||
state: FlusherState {
|
||||
dirty: false,
|
||||
ackword,
|
||||
},
|
||||
}
|
||||
}
|
||||
fn detach(mut self) -> FlusherState {
|
||||
let state = core::mem::replace(&mut self.state, FlusherState { dirty: false });
|
||||
fn detach(mut self) -> FlusherState<'addrsp> {
|
||||
static DUMMY: AtomicU32 = AtomicU32::new(0);
|
||||
let state = core::mem::replace(&mut self.state, FlusherState { dirty: false, ackword: &DUMMY });
|
||||
core::mem::forget(self);
|
||||
state
|
||||
}
|
||||
}
|
||||
impl Drop for Flusher<'_> {
|
||||
fn drop(&mut self) {
|
||||
todo!()
|
||||
// NOTE: Lock must be held, which must be guaranteed by the caller.
|
||||
fn flush(&mut self) {
|
||||
self.state.ackword.store(0, Ordering::Relaxed);
|
||||
|
||||
let mut affected_cpu_count = 0;
|
||||
|
||||
for cpu_id in self.active_cpus.iter_mut() {
|
||||
crate::percpu::shootdown_tlb_ipi(Some(cpu_id));
|
||||
affected_cpu_count += 1;
|
||||
}
|
||||
|
||||
while self.state.ackword.load(Ordering::Relaxed) < affected_cpu_count {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
self.state.dirty = false;
|
||||
}
|
||||
}
|
||||
impl Drop for Flusher<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
self.flush();
|
||||
}
|
||||
}
|
||||
|
||||
+11
-2
@@ -35,10 +35,10 @@ impl core::fmt::Display for LogicalCpuId {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const MAX_CPU_COUNT: u32 = 128;
|
||||
pub const MAX_CPU_COUNT: u32 = 128;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const MAX_CPU_COUNT: u32 = 32;
|
||||
pub const MAX_CPU_COUNT: u32 = 32;
|
||||
|
||||
const SET_WORDS: usize = (MAX_CPU_COUNT / usize::BITS) as usize;
|
||||
|
||||
@@ -86,6 +86,15 @@ impl LogicalCpuSet {
|
||||
pub fn to_raw(&self) -> RawMask {
|
||||
self.0.each_ref().map(|w| w.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = LogicalCpuId> + '_ {
|
||||
// TODO: Will this be optimized away?
|
||||
self.0.iter_mut().enumerate().flat_map(move |(i, w)| (0..usize::BITS).filter_map(move |b| if *w.get_mut() & 1 << b != 0 {
|
||||
Some(LogicalCpuId::new(i as u32 * usize::BITS + b))
|
||||
} else {
|
||||
None
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for LogicalCpuSet {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use core::sync::atomic::{AtomicUsize, AtomicPtr, Ordering};
|
||||
|
||||
use crate::cpu_set::MAX_CPU_COUNT;
|
||||
use crate::{context::switch::ContextSwitchPercpu, cpu_set::LogicalCpuId};
|
||||
|
||||
/// The percpu block, that stored all percpu variables.
|
||||
@@ -8,10 +11,56 @@ pub struct PercpuBlock {
|
||||
/// Context management
|
||||
pub switch_internals: ContextSwitchPercpu,
|
||||
|
||||
// TODO: This lock can probably be relaxed further, but verify correctness first.
|
||||
|
||||
// The NMI lock. Can be set by any CPU, but can only be cleared by the CPU this percpu block
|
||||
// refers to. Multiple flags can be set simultaneously, but NMI senders need to wait for the
|
||||
// flag to be cleared if it was already set.
|
||||
pub nmi_flags_lock: AtomicUsize,
|
||||
|
||||
// TODO: Put mailbox queues here, e.g. for TLB shootdown? Just be sure to 128-byte align it
|
||||
// first to avoid cache invalidation.
|
||||
#[cfg(feature = "profiling")]
|
||||
pub profiling: Option<&'static crate::profiling::RingBuffer>,
|
||||
}
|
||||
|
||||
const NULL: AtomicPtr<PercpuBlock> = AtomicPtr::new(core::ptr::null_mut());
|
||||
static ALL_PERCPU_BLOCKS: [AtomicPtr<PercpuBlock>; MAX_CPU_COUNT as usize] = [NULL; MAX_CPU_COUNT as usize];
|
||||
|
||||
// PercpuBlock::current() is implemented somewhere in the arch-specific modules
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct NmiReasons: usize {
|
||||
const TLB_SHOOTDOWN = 1;
|
||||
|
||||
// TODO: Profiling code wakes all CPUs up, so use a global and percpu ack counter for that.
|
||||
//
|
||||
//#[cfg(feature = "profiling")]
|
||||
//const PROFILING = 1 << 32;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "multi_core"))]
|
||||
pub fn shootdown_tlb_ipi(_target: Option<LogicalCpuId>) {}
|
||||
|
||||
#[cfg(feature = "multi_core")]
|
||||
pub fn shootdown_tlb_ipi(target: Option<LogicalCpuId>) {
|
||||
if let Some(target) = target {
|
||||
let Some(percpublock) = (unsafe { ALL_PERCPU_BLOCKS[target.get() as usize].load(Ordering::Acquire).as_ref() }) else {
|
||||
return;
|
||||
};
|
||||
let bit = NmiReasons::TLB_SHOOTDOWN.bits();
|
||||
|
||||
while percpublock.nmi_flags_lock.fetch_or(bit, Ordering::Release) & bit == bit {
|
||||
// Load is faster than CAS or on x86, LOCK BTS
|
||||
while percpublock.nmi_flags_lock.load(Ordering::Relaxed) & bit == bit {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for id in 0..crate::cpu_count() {
|
||||
// TODO: Optimize: use global counter and percpu ack counters.
|
||||
shootdown_tlb_ipi(Some(LogicalCpuId::new(id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ impl MemoryScheme {
|
||||
}
|
||||
|
||||
let page = addr_space.inner.write().mmap(
|
||||
&addr_space,
|
||||
(map.address != 0).then_some(span.base),
|
||||
page_count,
|
||||
map.flags,
|
||||
@@ -131,10 +132,12 @@ impl MemoryScheme {
|
||||
}
|
||||
let page_count = NonZeroUsize::new(size.div_ceil(PAGE_SIZE)).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
AddrSpace::current()?
|
||||
.inner
|
||||
let current_addrsp = AddrSpace::current()?;
|
||||
|
||||
let base_page = current_addrsp.inner
|
||||
.write()
|
||||
.mmap_anywhere(
|
||||
¤t_addrsp,
|
||||
page_count,
|
||||
flags,
|
||||
|dst_page, mut page_flags, dst_mapper, dst_flusher| {
|
||||
@@ -169,8 +172,8 @@ impl MemoryScheme {
|
||||
dst_flusher,
|
||||
)
|
||||
},
|
||||
)
|
||||
.map(|page| page.start_address().data())
|
||||
)?;
|
||||
Ok(base_page.start_address().data())
|
||||
}
|
||||
}
|
||||
impl KernelScheme for MemoryScheme {
|
||||
|
||||
+9
-11
@@ -718,7 +718,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
let requested_dst_base = (map.address != 0).then_some(requested_dst_page);
|
||||
|
||||
let mut src_addr_space = addrspace.inner.write();
|
||||
let mut dst_addr_space = dst_addr_space.inner.write();
|
||||
let mut dst_addrsp_guard = dst_addr_space.inner.write();
|
||||
|
||||
let src_page_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
@@ -727,8 +727,9 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
// TODO: Validate flags
|
||||
let result_base = if consume {
|
||||
AddrSpace::r#move(
|
||||
&mut *dst_addr_space,
|
||||
Some(&mut *src_addr_space),
|
||||
&*dst_addr_space,
|
||||
&mut *dst_addrsp_guard,
|
||||
Some((&addrspace, &mut *src_addr_space)),
|
||||
src_span,
|
||||
requested_dst_base,
|
||||
src_page_count.get(),
|
||||
@@ -736,7 +737,8 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
&mut notify_files,
|
||||
)?
|
||||
} else {
|
||||
dst_addr_space.mmap(
|
||||
dst_addrsp_guard.mmap(
|
||||
&dst_addr_space,
|
||||
requested_dst_base,
|
||||
src_page_count,
|
||||
map.flags,
|
||||
@@ -1052,18 +1054,14 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
crate::syscall::validate_region(next()??, next()??)?;
|
||||
|
||||
let unpin = false;
|
||||
addrspace
|
||||
.inner.write()
|
||||
.munmap(PageSpan::new(page, page_count), unpin)?;
|
||||
addrspace.munmap(PageSpan::new(page, page_count), unpin)?;
|
||||
}
|
||||
ADDRSPACE_OP_MPROTECT => {
|
||||
let (page, page_count) =
|
||||
crate::syscall::validate_region(next()??, next()??)?;
|
||||
let flags = MapFlags::from_bits(next()??).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
addrspace
|
||||
.inner.write()
|
||||
.mprotect(PageSpan::new(page, page_count), flags)?;
|
||||
addrspace.mprotect(PageSpan::new(page, page_count), flags)?;
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
}
|
||||
@@ -1444,7 +1442,7 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
addrspace: AddrSpaceWrapper::new()?,
|
||||
},
|
||||
b"exclusive" => Operation::AddrSpace {
|
||||
addrspace: addrspace.inner.write().try_clone()?,
|
||||
addrspace: addrspace.try_clone()?,
|
||||
},
|
||||
b"mmap-min-addr" => Operation::MmapMinAddr(Arc::clone(addrspace)),
|
||||
|
||||
|
||||
+10
-6
@@ -243,6 +243,7 @@ impl UserInner {
|
||||
|
||||
let is_pinned = true;
|
||||
let dst_page = dst_addr_space.inner.write().mmap_anywhere(
|
||||
&dst_addr_space,
|
||||
ONE,
|
||||
PROT_READ,
|
||||
|dst_page, flags, mapper, flusher| {
|
||||
@@ -375,6 +376,7 @@ impl UserInner {
|
||||
}
|
||||
|
||||
dst_space.mmap(
|
||||
&dst_space_lock,
|
||||
Some(free_span.base),
|
||||
ONE,
|
||||
map_flags | MAP_FIXED_NOREPLACE,
|
||||
@@ -413,7 +415,9 @@ impl UserInner {
|
||||
.expect("split must succeed");
|
||||
|
||||
if let Some(middle_page_count) = NonZeroUsize::new(middle_page_count) {
|
||||
let cur_space_lock_clone = Arc::clone(&cur_space_lock);
|
||||
dst_space.mmap(
|
||||
&cur_space_lock,
|
||||
Some(first_middle_dst_page),
|
||||
middle_page_count,
|
||||
map_flags | MAP_FIXED_NOREPLACE,
|
||||
@@ -433,8 +437,8 @@ impl UserInner {
|
||||
let is_pinned_userscheme_borrow = true;
|
||||
|
||||
Ok(Grant::borrow(
|
||||
Arc::clone(&cur_space_lock),
|
||||
&mut *cur_space_lock.inner.write(),
|
||||
Arc::clone(&cur_space_lock_clone),
|
||||
&mut *cur_space_lock_clone.inner.write(),
|
||||
first_middle_src_page,
|
||||
dst_page,
|
||||
middle_page_count.get(),
|
||||
@@ -473,6 +477,7 @@ impl UserInner {
|
||||
}
|
||||
|
||||
dst_space.mmap(
|
||||
&dst_space_lock,
|
||||
Some(tail_dst_page),
|
||||
ONE,
|
||||
map_flags | MAP_FIXED_NOREPLACE,
|
||||
@@ -851,6 +856,7 @@ impl UserInner {
|
||||
let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0");
|
||||
let mut notify_files = Vec::new();
|
||||
let dst_base = dst_addr_space.inner.write().mmap(
|
||||
&dst_addr_space,
|
||||
dst_base,
|
||||
page_count_nz,
|
||||
map.flags,
|
||||
@@ -861,6 +867,7 @@ impl UserInner {
|
||||
flags,
|
||||
file_ref,
|
||||
src,
|
||||
&dst_addr_space,
|
||||
mapper,
|
||||
flusher,
|
||||
)
|
||||
@@ -935,10 +942,7 @@ impl<const READ: bool, const WRITE: bool> CaptureGuard<READ, WRITE> {
|
||||
let (first_page, page_count, _offset) = page_range_containing(self.base, self.len);
|
||||
|
||||
let unpin = true;
|
||||
space
|
||||
.inner
|
||||
.write()
|
||||
.munmap(PageSpan::new(first_page, page_count), unpin)?;
|
||||
space.munmap(PageSpan::new(first_page, page_count), unpin)?;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
+2
-1
@@ -433,7 +433,7 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
|
||||
let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned)
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
let unpin = false;
|
||||
let notify = addr_space.inner.write().munmap(span, unpin)?;
|
||||
let notify = addr_space.munmap(span, unpin)?;
|
||||
|
||||
for map in notify {
|
||||
let _ = map.unmap();
|
||||
@@ -483,6 +483,7 @@ pub fn mremap(
|
||||
let mut guard = addr_space.inner.write();
|
||||
|
||||
let base = AddrSpace::r#move(
|
||||
&addr_space,
|
||||
&mut *guard,
|
||||
None,
|
||||
src_span,
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ pub fn syscall(
|
||||
SYS_GETGID => getgid(),
|
||||
SYS_GETNS => getns(),
|
||||
SYS_GETUID => getuid(),
|
||||
SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
|
||||
SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)).map(|()| 0),
|
||||
SYS_MKNS => mkns(UserSlice::ro(
|
||||
b,
|
||||
c.checked_mul(core::mem::size_of::<[usize; 2]>())
|
||||
|
||||
@@ -254,17 +254,13 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> {
|
||||
pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<()> {
|
||||
// println!("mprotect {:#X}, {}, {:#X}", address, size, flags);
|
||||
|
||||
let span = PageSpan::validate_nonempty(VirtualAddress::new(address), size)
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
|
||||
AddrSpace::current()?
|
||||
.inner
|
||||
.write()
|
||||
.mprotect(span, flags)
|
||||
.map(|()| 0)
|
||||
AddrSpace::current()?.mprotect(span, flags)
|
||||
}
|
||||
|
||||
pub fn setpgid(pid: ContextId, pgid: ContextId) -> Result<usize> {
|
||||
@@ -591,7 +587,7 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! {
|
||||
let page_count = NonZeroUsize::new(bootstrap.page_count)
|
||||
.expect("bootstrap contained no pages!");
|
||||
|
||||
let _base_page = addr_space.inner.write().mmap(Some(base), page_count, flags, &mut Vec::new(), |page, flags, mapper, flusher| {
|
||||
let _base_page = addr_space.inner.write().mmap(&addr_space, Some(base), page_count, flags, &mut Vec::new(), |page, flags, mapper, flusher| {
|
||||
let shared = false;
|
||||
Ok(Grant::zeroed(PageSpan::new(page, bootstrap.page_count), flags, mapper, flusher, shared)?)
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user