diff options
author | Andreas Kling <awesomekling@gmail.com> | 2018-11-03 01:49:40 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2018-11-03 01:51:42 +0100 |
commit | 202bdb553c2dc073f06105b12fbf0b2a8045069b (patch) | |
tree | 159e2bf3ccb0ba84b51aa811aa3cdc0d2aa12c19 /Kernel | |
parent | b59ce22fc5a3097544519eee7876e5f5d0656d4b (diff) | |
download | serenity-202bdb553c2dc073f06105b12fbf0b2a8045069b.zip |
Implemented sys$execve().
It's really crufty, but it basically works!
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/MemoryManager.cpp | 16 | ||||
-rw-r--r-- | Kernel/MemoryManager.h | 4 | ||||
-rw-r--r-- | Kernel/Process.cpp | 149 | ||||
-rw-r--r-- | Kernel/Process.h | 1 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 |
6 files changed, 160 insertions, 13 deletions
diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 97d5b32831..500f57bfb1 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -31,21 +31,21 @@ MemoryManager::~MemoryManager() { } -void MemoryManager::populate_page_directory(Process& process) +void MemoryManager::populate_page_directory(PageDirectory& page_directory) { - memset(process.m_page_directory, 0, sizeof(PageDirectory)); - process.m_page_directory->entries[0] = m_kernel_page_directory->entries[0]; - process.m_page_directory->entries[1] = m_kernel_page_directory->entries[1]; + memset(&page_directory, 0, sizeof(PageDirectory)); + page_directory.entries[0] = m_kernel_page_directory->entries[0]; + page_directory.entries[1] = m_kernel_page_directory->entries[1]; } -void MemoryManager::release_page_directory(Process& process) +void MemoryManager::release_page_directory(PageDirectory& page_directory) { ASSERT_INTERRUPTS_DISABLED(); #ifdef MM_DEBUG - dbgprintf("MM: release_page_directory for pid %d, PD K%x\n", process.pid(), process.m_page_directory); + dbgprintf("MM: release_page_directory for PD K%x\n", &page_directory); #endif for (size_t i = 0; i < 1024; ++i) { - auto page_table = process.m_page_directory->physical_addresses[i]; + auto page_table = page_directory.physical_addresses[i]; if (!page_table.is_null()) { #ifdef MM_DEBUG dbgprintf("MM: deallocating process page table [%u] P%x @ %p\n", i, page_table.get(), &process.m_page_directory->physical_addresses[i]); @@ -54,7 +54,7 @@ void MemoryManager::release_page_directory(Process& process) } } #ifdef SCRUB_DEALLOCATED_PAGE_TABLES - memset(process.m_page_directory, 0xc9, sizeof(PageDirectory)); + memset(&page_directory, 0xc9, sizeof(PageDirectory)); #endif } diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index 2a72841318..4a1c77b140 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -84,8 +84,8 @@ public: void registerZone(Zone&); void unregisterZone(Zone&); - void populate_page_directory(Process&); - void release_page_directory(Process&); + void populate_page_directory(PageDirectory&); + void release_page_directory(PageDirectory&); byte* create_kernel_alias_for_region(Region&); void remove_kernel_alias_for_region(Region&, byte*); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 1c634f3820..c4ef53777f 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -282,6 +282,149 @@ pid_t Process::sys$fork(RegisterDump& regs) return child->pid(); } +int Process::sys$execve(const char* filename, const char** argv, const char** envp) +{ + VALIDATE_USER_READ(filename, strlen(filename)); + if (argv) { + for (size_t i = 0; argv[i]; ++i) { + VALIDATE_USER_READ(argv[i], strlen(argv[i])); + } + } + if (envp) { + for (size_t i = 0; envp[i]; ++i) { + VALIDATE_USER_READ(envp[i], strlen(envp[i])); + } + } + + String path(filename); + auto parts = path.split('/'); + if (parts.isEmpty()) + return -ENOENT; + + int error; + auto handle = VirtualFileSystem::the().open(path, error, 0, m_cwd ? m_cwd->inode : InodeIdentifier()); + if (!handle) { + ASSERT(error != 0); + return error; + } + + if (!handle->metadata().mayExecute(m_uid, m_gid)) + return -EACCES; + + auto elfData = handle->readEntireFile(); + if (!elfData) + return -EIO; // FIXME: Get a more detailed error from VFS. + + Vector<String> processArguments; + if (argv) { + for (size_t i = 0; argv[i]; ++i) { + processArguments.append(argv[i]); + } + } else { + processArguments.append(parts.last()); + } + + Vector<String> processEnvironment; + if (envp) { + for (size_t i = 0; envp[i]; ++i) { + processEnvironment.append(envp[i]); + } + } + + dword entry_eip = 0; + PageDirectory* old_page_directory; + PageDirectory* new_page_directory; + { + ExecSpace space; + Region* region = nullptr; + + InterruptDisabler disabler; + // Okay, here comes the sleight of hand, pay close attention.. + auto old_regions = move(m_regions); + auto old_subregions = move(m_subregions); + old_page_directory = m_page_directory; + new_page_directory = reinterpret_cast<PageDirectory*>(kmalloc_page_aligned(sizeof(PageDirectory))); + MM.populate_page_directory(*new_page_directory); + m_page_directory = new_page_directory; + + ProcessPagingScope pagingScope(*this); + space.hookableAlloc = [&] (const String& name, size_t size) { + if (!size) + return (void*)nullptr; + size = ((size / 4096) + 1) * 4096; // FIXME: Use ceil_div? + region = allocateRegion(size, String(name)); + return (void*)region->linearAddress.get(); + }; + bool success = space.loadELF(move(elfData)); + if (!success) { + MM.release_page_directory(*new_page_directory); + m_page_directory = old_page_directory; + m_regions = move(old_regions); + m_subregions = move(old_subregions); + kprintf("Failure loading ELF %s\n", path.characters()); + return -ENOEXEC; + } + + space.forEachArea([&] (const String& name, dword offset, size_t size, LinearAddress laddr) { + if (laddr.isNull()) + return; + dword roundedOffset = offset & 0xfffff000; + size_t roundedSize = 4096 * ceilDiv((offset - roundedOffset) + size, 4096u); + LinearAddress roundedLaddr = laddr; + roundedLaddr.mask(0xfffff000); + m_subregions.append(make<Subregion>(*region, roundedOffset, roundedSize, roundedLaddr, String(name))); + MM.mapSubregion(*this, *m_subregions.last()); + }); + + entry_eip = (dword)space.symbolPtr("_start"); + if (!entry_eip) { + MM.release_page_directory(*new_page_directory); + m_page_directory = old_page_directory; + m_regions = move(old_regions); + m_subregions = move(old_subregions); + return -ENOEXEC; + } + } + + InterruptDisabler disabler; + loadTaskRegister(s_kernelProcess->selector()); + + m_name = parts.takeLast(); + + dword old_esp0 = m_tss.esp0; + + memset(&m_tss, 0, sizeof(m_tss)); + m_tss.eflags = 0x0202; + m_tss.eip = entry_eip; + m_tss.cs = 0x1b; + m_tss.ds = 0x23; + m_tss.es = 0x23; + m_tss.fs = 0x23; + m_tss.ss = 0x23; + m_tss.cr3 = (dword)m_page_directory; + auto* stack_region = allocateRegion(defaultStackSize, "stack"); + ASSERT(stack_region); + m_stackTop3 = stack_region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8; + m_tss.esp = m_stackTop3; + m_tss.ss0 = 0x10; + m_tss.esp0 = old_esp0; + m_tss.ss2 = m_pid; + + MM.release_page_directory(*old_page_directory); + + m_executable = handle->vnode(); + m_arguments = move(processArguments); + m_initialEnvironment = move(processEnvironment); + +#ifdef TASK_DEBUG + kprintf("Process %u (%s) execve'd %s @ %p\n", pid(), name().characters(), filename, m_tss.eip); +#endif + + yield(); + ASSERT(false); + return 0; +} + int Process::sys$spawn(const char* path, const char** args) { if (args) { @@ -485,7 +628,7 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel } m_page_directory = (PageDirectory*)kmalloc_page_aligned(sizeof(PageDirectory)); - MM.populate_page_directory(*this); + MM.populate_page_directory(*m_page_directory); if (fork_parent) { m_file_descriptors.resize(fork_parent->m_file_descriptors.size()); @@ -583,7 +726,7 @@ Process::~Process() m_kernelStack = nullptr; } - MM.release_page_directory(*this); + MM.release_page_directory(*m_page_directory); } void Process::dumpRegions() @@ -771,7 +914,7 @@ bool scheduleNewProcess() for (auto* process = s_processes->head(); process; process = process->next()) { //if (process->state() == Process::BlockedWait || process->state() == Process::BlockedSleep) // continue; - dbgprintf("%w %s(%u)\n", process->state(), process->name().characters(), process->pid()); + dbgprintf("%w %s(%u) @ %w:%x\n", process->state(), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip); } #endif diff --git a/Kernel/Process.h b/Kernel/Process.h index 2ee01dd07a..3f51132d58 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -120,6 +120,7 @@ public: int sys$readlink(const char*, char*, size_t); int sys$ttyname_r(int fd, char*, size_t); pid_t sys$fork(RegisterDump&); + int sys$execve(const char* filename, const char** argv, const char** envp); static void initialize(); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 353dcbf1a9..dd2ca9aeee 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -130,6 +130,8 @@ static DWORD handle(RegisterDump& regs, DWORD function, DWORD arg1, DWORD arg2, return current->sys$tcsetpgrp((int)arg1, (pid_t)arg2); case Syscall::PosixFork: return current->sys$fork(regs); + case Syscall::PosixExecve: + return current->sys$execve((const char*)arg1, (const char**)arg2, (const char**)arg3); default: kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 8b4208f81e..3576c637cf 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -48,6 +48,7 @@ enum Function { PosixTcsetpgrp = 0x2016, PosixTcgetpgrp = 0x2017, PosixFork = 0x2018, + PosixExecve = 0x2019, }; void initialize(); |