From 563121596de8edd6fa589c5ab70c54638f2b7649 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 17 Jun 2022 12:37:03 +0200 Subject: [PATCH] Fix running on multi_core. Turns out the problem all along was that the ActivePageTable was never dropped in usermode_bootstrap. So as soon as any other hardware thread tried to do page table business, it deadlocked! --- src/arch/x86_64/consts.rs | 6 ++---- src/context/memory.rs | 4 ++-- src/ptrace.rs | 8 ++------ src/scheme/proc.rs | 2 +- src/syscall/process.rs | 21 +++++++++++++-------- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/arch/x86_64/consts.rs b/src/arch/x86_64/consts.rs index 33432e8..1656c8c 100644 --- a/src/arch/x86_64/consts.rs +++ b/src/arch/x86_64/consts.rs @@ -38,7 +38,5 @@ /// Offset to user image pub const USER_OFFSET: usize = 0; - /// Offset for usage in other temporary pages - // TODO: Currently used for ptrace but should be removed or replaced with a kernel address. - pub const USER_TMP_MISC_OFFSET: usize = USER_OFFSET + PML4_SIZE; - pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK)/PML4_SIZE; + /// End offset of the user image, i.e. kernel start + pub const USER_END_OFFSET: usize = 256 * PML4_SIZE; diff --git a/src/context/memory.rs b/src/context/memory.rs index 619e93e..7461da6 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -68,7 +68,7 @@ impl UserGrants { pub fn new() -> Self { Self { inner: BTreeSet::new(), - holes: core::iter::once((VirtualAddress::new(0), crate::PML4_SIZE * 256)).collect::>(), + holes: core::iter::once((VirtualAddress::new(0), crate::USER_END_OFFSET)).collect::>(), funmap: BTreeMap::new(), } } @@ -114,7 +114,7 @@ impl UserGrants { let mut requested = Region::new(address, size); if - requested.end_address().data() > crate::PML4_SIZE * 256 // There are 256 PML4 entries reserved for userspace + requested.end_address().data() > crate::USER_END_OFFSET || address.data() % PAGE_SIZE != 0 { // ... but it was invalid diff --git a/src/ptrace.rs b/src/ptrace.rs index 7327170..2234aa6 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -451,13 +451,9 @@ pub unsafe fn regs_for_mut(context: &mut Context) -> Option<&mut InterruptStack> // Returns an iterator which splits [start, start + len) into an iterator of possibly trimmed // pages. fn page_aligned_chunks(mut start: usize, mut len: usize) -> impl Iterator { - // TODO: Define this elsewhere! - #[cfg(target_arch = "x86_64")] - const KERNEL_SPLIT_START: usize = crate::PML4_SIZE * 256; - // Ensure no pages can overlap with kernel memory. - if start.saturating_add(len) > KERNEL_SPLIT_START { - len = KERNEL_SPLIT_START.saturating_sub(start); + if start.saturating_add(len) > crate::USER_END_OFFSET { + len = crate::USER_END_OFFSET.saturating_sub(start); } let first_len = core::cmp::min(len, PAGE_SIZE - start % PAGE_SIZE); diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 76bff3c..70bc077 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -645,7 +645,7 @@ impl Scheme for ProcScheme { let flags = chunks.next().and_then(|f| MapFlags::from_bits(f)).ok_or(Error::new(EINVAL))?; let region = Region::new(VirtualAddress::new(base), size); - if base % PAGE_SIZE != 0 || size % PAGE_SIZE != 0 || base.saturating_add(size) > crate::PML4_SIZE * 256 { + if base % PAGE_SIZE != 0 || size % PAGE_SIZE != 0 || base.saturating_add(size) > crate::USER_END_OFFSET { return Err(Error::new(EINVAL)); } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 51eecfe..dc85d70 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -87,6 +87,7 @@ pub fn clone(flags: CloneFlags, stack_base: usize, info: Option<&CloneInfo>) -> cpu_id_opt = context.cpu_id; } + // TODO: Fill with newest registers. arch = context.arch.clone(); if let Some(ref fx) = context.kfx { @@ -115,6 +116,9 @@ pub fn clone(flags: CloneFlags, stack_base: usize, info: Option<&CloneInfo>) -> // // (base pointer - start of stack) - one offset = stack_base - stack.as_ptr() as usize - mem::size_of::(); // Add clone ret + // FIXME: This is incredibly UB, making Rust think the current stack being + // copied is simply a regular immutable slice. This part should either be + // written in assembly or have clone moved to userspace. let mut new_stack = stack.clone(); unsafe { @@ -352,7 +356,7 @@ pub fn clone(flags: CloneFlags, stack_base: usize, info: Option<&CloneInfo>) -> }; let _ = scheme.kfmap(number, &map, &new_context_lock); } - new_context_lock.write().unblock(); + new_context_lock.write().status = context::Status::Runnable; } if ptrace::send_event(ptrace_event!(PTRACE_EVENT_CLONE, pid.into())).is_some() { @@ -997,12 +1001,14 @@ pub fn usermode_bootstrap(mut data: Box<[u8]>) -> ! { const LOAD_BASE: usize = 0; let grant = context::memory::Grant::map(VirtualAddress::new(LOAD_BASE), ((data.len()+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE, PageFlags::new().user(true).write(true).execute(true)); - let mut active_table = unsafe { ActivePageTable::new(TableKind::User) }; + { + let mut active_table = unsafe { ActivePageTable::new(TableKind::User) }; - for (index, page) in grant.pages().enumerate() { - let len = if data.len() - index * PAGE_SIZE < PAGE_SIZE { data.len() % PAGE_SIZE } else { PAGE_SIZE }; - let frame = active_table.translate_page(page).expect("expected mapped init memory to have a corresponding frame"); - unsafe { ((frame.start_address().data() + crate::PHYS_OFFSET) as *mut u8).copy_from_nonoverlapping(data.as_ptr().add(index * PAGE_SIZE), len); } + for (index, page) in grant.pages().enumerate() { + let len = if data.len() - index * PAGE_SIZE < PAGE_SIZE { data.len() % PAGE_SIZE } else { PAGE_SIZE }; + let frame = active_table.translate_page(page).expect("expected mapped init memory to have a corresponding frame"); + unsafe { ((frame.start_address().data() + crate::PHYS_OFFSET) as *mut u8).copy_from_nonoverlapping(data.as_ptr().add(index * PAGE_SIZE), len); } + } } context::contexts().current().expect("expected a context to exist when executing init").read().grants.write().insert(grant); @@ -1012,8 +1018,7 @@ pub fn usermode_bootstrap(mut data: Box<[u8]>) -> ! { #[cfg(target_arch = "x86_64")] unsafe { let start = ((LOAD_BASE + 0x18) as *mut usize).read(); - // Start with the (probably) ELF executable loaded, without any stack the ability to load - // sections to arbitrary addresses. + // Start with the (probably) ELF executable loaded, without any stack. usermode(start, 0, 0, 0); } }