summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2018-11-03 01:49:40 +0100
committerAndreas Kling <awesomekling@gmail.com>2018-11-03 01:51:42 +0100
commit202bdb553c2dc073f06105b12fbf0b2a8045069b (patch)
tree159e2bf3ccb0ba84b51aa811aa3cdc0d2aa12c19 /Kernel
parentb59ce22fc5a3097544519eee7876e5f5d0656d4b (diff)
downloadserenity-202bdb553c2dc073f06105b12fbf0b2a8045069b.zip
Implemented sys$execve().
It's really crufty, but it basically works!
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/MemoryManager.cpp16
-rw-r--r--Kernel/MemoryManager.h4
-rw-r--r--Kernel/Process.cpp149
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
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();