diff --git a/libkernel/src/memory/proc_vm/memory_map/mod.rs b/libkernel/src/memory/proc_vm/memory_map/mod.rs index 95c35d1..fc45fc1 100644 --- a/libkernel/src/memory/proc_vm/memory_map/mod.rs +++ b/libkernel/src/memory/proc_vm/memory_map/mod.rs @@ -7,7 +7,7 @@ use crate::{ region::VirtMemoryRegion, }, }; -use alloc::{collections::BTreeMap, vec::Vec}; +use alloc::{collections::BTreeMap, string::String, vec::Vec}; const MMAP_BASE: usize = 0x4000_0000_0000; @@ -85,6 +85,7 @@ impl MemoryMap { mut len: usize, perms: VMAPermissions, kind: VMAreaKind, + name: String, ) -> Result { if len == 0 { return Err(KernelError::InvalidValue); @@ -133,7 +134,9 @@ impl MemoryMap { // At this point, `start_addr` points to a valid, free region. // We can now create and insert the new VMA, handling merges. - let new_vma = VMArea::new(region, kind, perms); + let mut new_vma = VMArea::new(region, kind, perms); + + new_vma.set_name(name); self.insert_and_merge(new_vma); @@ -502,6 +505,10 @@ impl MemoryMap { pub fn vma_count(&self) -> usize { self.vmas.len() } + + pub fn iter_vmas(&self) -> impl Iterator { + self.vmas.values() + } } #[cfg(test)] diff --git a/libkernel/src/memory/proc_vm/memory_map/tests.rs b/libkernel/src/memory/proc_vm/memory_map/tests.rs index fc2fa6c..f0158a6 100644 --- a/libkernel/src/memory/proc_vm/memory_map/tests.rs +++ b/libkernel/src/memory/proc_vm/memory_map/tests.rs @@ -194,6 +194,7 @@ fn test_mmap_any_empty() { size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -218,6 +219,7 @@ fn test_mmap_any_with_existing() { size, VMAPermissions::ro(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -231,6 +233,7 @@ fn test_mmap_any_with_existing() { size, VMAPermissions::ro(), // different permissions to prevent merge. VMAreaKind::Anon, + String::new(), ) .unwrap(); assert_eq!(bottom_addr.value(), existing_addr - size); @@ -254,6 +257,7 @@ fn test_mmap_hint_free() { size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -282,6 +286,7 @@ fn test_mmap_hint_taken() { size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -309,6 +314,7 @@ fn test_mmap_fixed_clobber_complete_overlap() { 3 * PAGE_SIZE, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -345,6 +351,7 @@ fn test_mmap_fixed_clobber_partial_end() { new_size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -378,6 +385,7 @@ fn test_mmap_fixed_clobber_partial_end_spill() { new_size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .unwrap(); @@ -413,6 +421,7 @@ fn test_mmap_fixed_no_clobber_fails() { new_size, VMAPermissions::rw(), VMAreaKind::Anon, + String::new(), ) .is_err() ); @@ -438,6 +447,7 @@ fn test_mmap_fixed_clobber_punch_hole() { new_size, VMAPermissions::ro(), VMAreaKind::Anon, + String::new(), ) .unwrap(); diff --git a/libkernel/src/memory/proc_vm/mod.rs b/libkernel/src/memory/proc_vm/mod.rs index ecfb5b2..b8613e8 100644 --- a/libkernel/src/memory/proc_vm/mod.rs +++ b/libkernel/src/memory/proc_vm/mod.rs @@ -4,6 +4,7 @@ use crate::{ UserAddressSpace, error::{KernelError, Result}, }; +use alloc::string::ToString; use memory_map::{AddressRequest, MemoryMap}; use vmarea::{AccessKind, FaultValidation, VMAPermissions, VMArea, VMAreaKind}; @@ -137,6 +138,7 @@ impl ProcessVM { growth_size, BRK_PERMISSIONS, VMAreaKind::Anon, + "[heap]".to_string(), )?; self.brk = new_brk_region; @@ -174,6 +176,7 @@ mod tests { region: VirtMemoryRegion::new(VA::from_value(0x1000), PAGE_SIZE), kind: VMAreaKind::Anon, // Simplification for test permissions: VMAPermissions::rx(), + name: String::new(), }; ProcessVM::from_vma(text_vma).unwrap() @@ -329,6 +332,7 @@ mod tests { region: VirtMemoryRegion::new(obstacle_addr, PAGE_SIZE), kind: VMAreaKind::Anon, permissions: VMAPermissions::ro(), + name: String::new(), }; vm.mm.insert_and_merge(obstacle_vma); assert_eq!(vm.mm.vma_count(), 2); diff --git a/libkernel/src/memory/proc_vm/vmarea.rs b/libkernel/src/memory/proc_vm/vmarea.rs index b9d3981..3d77412 100644 --- a/libkernel/src/memory/proc_vm/vmarea.rs +++ b/libkernel/src/memory/proc_vm/vmarea.rs @@ -12,9 +12,10 @@ use core::cmp; use crate::{ - fs::Inode, + fs::{Inode, InodeId}, memory::{PAGE_MASK, PAGE_SIZE, address::VA, region::VirtMemoryRegion}, }; +use alloc::string::{String, ToString}; use alloc::sync::Arc; use object::{ Endian, @@ -173,6 +174,7 @@ impl VMAreaKind { #[derive(Clone, PartialEq)] pub struct VMArea { pub region: VirtMemoryRegion, + pub(super) name: String, pub(super) kind: VMAreaKind, pub(super) permissions: VMAPermissions, } @@ -189,9 +191,14 @@ impl VMArea { region, kind, permissions, + name: String::new(), } } + pub fn set_name>(&mut self, s: S) { + self.name = s.as_ref().to_string(); + } + /// Creates a file-backed `VMArea` directly from an ELF program header. /// /// This is a convenience function used by the ELF loader. It parses the @@ -246,6 +253,7 @@ impl VMArea { len: hdr.p_filesz(endian) + mappable_region.offset() as u64, }), permissions, + name: String::new(), } } @@ -455,6 +463,24 @@ impl VMArea { pub fn region(&self) -> VirtMemoryRegion { self.region } + + pub fn file_offset(&self) -> Option { + match self.kind { + VMAreaKind::File(ref vmfile_mapping) => Some(vmfile_mapping.offset()), + VMAreaKind::Anon => None, + } + } + + pub fn inode_id(&self) -> Option { + match self.kind { + VMAreaKind::File(ref vmfile_mapping) => Some(vmfile_mapping.file().id()), + VMAreaKind::Anon => None, + } + } + + pub fn name(&self) -> &str { + &self.name + } } #[cfg(test)] diff --git a/src/drivers/fs/proc/task/mod.rs b/src/drivers/fs/proc/task/mod.rs index 3487bd6..61e8630 100644 --- a/src/drivers/fs/proc/task/mod.rs +++ b/src/drivers/fs/proc/task/mod.rs @@ -126,12 +126,18 @@ impl Inode for ProcTaskInode { FileType::Directory, 7, )); + entries.push(Dirent::new( + "maps".to_string(), + InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "maps"])), + FileType::File, + 8, + )); if self.desc.tid().value() == self.desc.tgid().value() && !self.is_task_dir { entries.push(Dirent::new( "task".to_string(), InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "task"])), FileType::Directory, - 8, + 9, )); } diff --git a/src/drivers/fs/proc/task/task_file.rs b/src/drivers/fs/proc/task/task_file.rs index 6209b9e..095904e 100644 --- a/src/drivers/fs/proc/task/task_file.rs +++ b/src/drivers/fs/proc/task/task_file.rs @@ -17,6 +17,7 @@ pub enum TaskFileType { Root, State, Stat, + Maps, } impl TryFrom<&str> for TaskFileType { @@ -30,6 +31,7 @@ impl TryFrom<&str> for TaskFileType { "stat" => Ok(TaskFileType::Stat), "cwd" => Ok(TaskFileType::Cwd), "root" => Ok(TaskFileType::Root), + "maps" => Ok(TaskFileType::Maps), _ => Err(()), } } @@ -52,6 +54,7 @@ impl ProcTaskFileInode { TaskFileType::Status | TaskFileType::Comm | TaskFileType::State + | TaskFileType::Maps | TaskFileType::Stat => FileType::File, TaskFileType::Cwd | TaskFileType::Root => FileType::Symlink, }, @@ -174,6 +177,26 @@ Threads:\t{tasks}\n", } TaskFileType::Cwd => task.cwd.lock_save_irq().clone().1.as_str().to_string(), TaskFileType::Root => task.root.lock_save_irq().1.as_str().to_string(), + TaskFileType::Maps => { + let mut output = String::new(); + let mut vm = task.vm.lock_save_irq(); + + for vma in vm.mm_mut().iter_vmas() { + output.push_str(&format!( + "{:x}-{:x} {}{}{}{} {:010x} {}\n", + vma.region().start_address().value(), + vma.region().end_address().value(), + if vma.permissions().read { "r" } else { "-" }, + if vma.permissions().write { "w" } else { "-" }, + if vma.permissions().execute { "x" } else { "-" }, + "p", // Don't suport shared mappings... yet! + vma.file_offset().unwrap_or_default(), + vma.name() + )); + } + + output + } } } else { "State:\tGone\n".to_string() diff --git a/src/memory/mmap.rs b/src/memory/mmap.rs index 6a87724..4a4cb94 100644 --- a/src/memory/mmap.rs +++ b/src/memory/mmap.rs @@ -1,6 +1,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::{process::fd_table::Fd, sched::current::current_task}; +use alloc::string::{String, ToString}; use libkernel::{ error::{KernelError, Result}, memory::{ @@ -85,8 +86,8 @@ pub async fn sys_mmap( let requested_len = len as usize; - let kind = if (flags & (MAP_ANON | MAP_ANONYMOUS)) != 0 { - VMAreaKind::Anon + let (kind, name) = if (flags & (MAP_ANON | MAP_ANONYMOUS)) != 0 { + (VMAreaKind::Anon, String::new()) } else { // File-backed mapping: require a valid fd and use the provided offset. let fd = current_task() @@ -96,8 +97,12 @@ pub async fn sys_mmap( .ok_or(KernelError::BadFd)?; let inode = fd.inode().ok_or(KernelError::BadFd)?; + let name = fd + .path() + .map(|x| x.as_str().to_string()) + .unwrap_or_default(); - VMAreaKind::new_file(inode, offset, len) + (VMAreaKind::new_file(inode, offset, len), name) }; let address_request = if addr.is_null() { @@ -125,6 +130,7 @@ pub async fn sys_mmap( requested_len, permissions, kind, + name, )?; Ok(new_mapping_addr.value()) diff --git a/src/process/exec.rs b/src/process/exec.rs index 7596bf4..8d2bb8d 100644 --- a/src/process/exec.rs +++ b/src/process/exec.rs @@ -59,13 +59,14 @@ fn process_prog_headers( vmas: &mut Vec, bias: Option, elf_file: Arc, + path: &Path, endian: E, ) -> Option { let mut hdr_addr = None; for hdr in hdrs { if hdr.p_type(endian) == PT_LOAD { - let vma = VMArea::from_pheader(elf_file.clone(), *hdr, endian, bias); + let mut vma = VMArea::from_pheader(elf_file.clone(), *hdr, endian, bias); // Find PHDR: Assumption segment with p_offset == 0 contains // headers. @@ -73,6 +74,8 @@ fn process_prog_headers( hdr_addr = Some(vma.region().start_address()); } + vma.set_name(path.as_str()); + vmas.push(vma); } } @@ -80,7 +83,12 @@ fn process_prog_headers( hdr_addr } -async fn exec_elf(inode: Arc, argv: Vec, envp: Vec) -> Result<()> { +async fn exec_elf( + inode: Arc, + path: &Path, + argv: Vec, + envp: Vec, +) -> Result<()> { // Read ELF header let mut buf = [0u8; core::mem::size_of::>()]; inode.read_at(0, &mut buf).await?; @@ -137,7 +145,8 @@ async fn exec_elf(inode: Arc, argv: Vec, envp: Vec) - let mut vmas = Vec::new(); // Process the binary program headers. - if let Some(hdr_addr) = process_prog_headers(hdrs, &mut vmas, main_bias, inode.clone(), endian) + if let Some(hdr_addr) = + process_prog_headers(hdrs, &mut vmas, main_bias, inode.clone(), path, endian) { auxv.push(AT_PHDR); auxv.push(hdr_addr.add_bytes(elf.e_phoff(endian) as _).value() as _); @@ -160,11 +169,15 @@ async fn exec_elf(inode: Arc, argv: Vec, envp: Vec) - main_entry }; - vmas.push(VMArea::new( + let mut stack_vma = VMArea::new( VirtMemoryRegion::new(VA::from_value(STACK_START), STACK_SZ), VMAreaKind::Anon, VMAPermissions::rw(), - )); + ); + + stack_vma.set_name("[stack]"); + + vmas.push(stack_vma); let mut mem_map = MemoryMap::from_vmas(vmas)?; let stack_ptr = setup_user_stack(&mut mem_map, &argv, &envp, auxv)?; @@ -231,12 +244,13 @@ async fn exec_script( new_argv.push(path.as_str().to_string()); new_argv.extend(argv.into_iter().skip(1)); // Skip original argv[0] // Resolve interpreter inode + let interp_path = Path::new(interp_path); let task = current_task_shared(); let interp_inode = VFS - .resolve_path(Path::new(interp_path), VFS.root_inode(), &task) + .resolve_path(interp_path, VFS.root_inode(), &task) .await?; // Execute interpreter - exec_elf(interp_inode, new_argv, envp).await?; + exec_elf(interp_inode, interp_path, new_argv, envp).await?; Ok(()) } @@ -249,7 +263,7 @@ pub async fn kernel_exec( let mut buf = [0u8; 4]; inode.read_at(0, &mut buf).await?; if buf == [0x7F, b'E', b'L', b'F'] { - exec_elf(inode, argv, envp).await + exec_elf(inode, path, argv, envp).await } else if buf.starts_with(b"#!") { exec_script(path, inode, argv, envp).await } else { @@ -394,7 +408,14 @@ async fn process_interp(interp_path: String, vmas: &mut Vec) -> Result