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!
This commit is contained in:
4lDO2
2022-06-17 12:37:03 +02:00
parent 6e5015dcab
commit 563121596d
5 changed files with 20 additions and 21 deletions

View File

@@ -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;

View File

@@ -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::<BTreeMap<_, _>>(),
holes: core::iter::once((VirtualAddress::new(0), crate::USER_END_OFFSET)).collect::<BTreeMap<_, _>>(),
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

View File

@@ -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<Item = (usize, usize)> {
// 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);

View File

@@ -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));
}

View File

@@ -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::<usize>(); // 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);
}
}