summaryrefslogtreecommitdiff
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
parentb59ce22fc5a3097544519eee7876e5f5d0656d4b (diff)
downloadserenity-202bdb553c2dc073f06105b12fbf0b2a8045069b.zip
Implemented sys$execve().
It's really crufty, but it basically works!
-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
-rw-r--r--LibC/unistd.cpp27
-rw-r--r--LibC/unistd.h1
-rw-r--r--Userland/sh.cpp35
9 files changed, 215 insertions, 21 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();
diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp
index 9a3b2459b8..86c9ce237c 100644
--- a/LibC/unistd.cpp
+++ b/LibC/unistd.cpp
@@ -7,7 +7,14 @@ extern "C" {
pid_t fork()
{
- return Syscall::invoke(Syscall::PosixFork);
+ int rc = Syscall::invoke(Syscall::PosixFork);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
+int execve(const char* filename, const char** argv, const char** envp)
+{
+ int rc = Syscall::invoke(Syscall::PosixExecve, (dword)filename, (dword)argv, (dword)envp);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
uid_t getuid()
@@ -27,32 +34,38 @@ pid_t getpid()
pid_t setsid()
{
- return Syscall::invoke(Syscall::PosixSetsid);
+ int rc = Syscall::invoke(Syscall::PosixSetsid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
pid_t tcgetpgrp(int fd)
{
- return Syscall::invoke(Syscall::PosixTcgetpgrp, (dword)fd);
+ int rc = Syscall::invoke(Syscall::PosixTcgetpgrp, (dword)fd);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
int tcsetpgrp(int fd, pid_t pgid)
{
- return Syscall::invoke(Syscall::PosixTcsetpgrp, (dword)fd, (dword)pgid);
+ int rc = Syscall::invoke(Syscall::PosixTcsetpgrp, (dword)fd, (dword)pgid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
int setpgid(pid_t pid, pid_t pgid)
{
- return Syscall::invoke(Syscall::PosixSetpgid, (dword)pid, (dword)pgid);
+ int rc = Syscall::invoke(Syscall::PosixSetpgid, (dword)pid, (dword)pgid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
pid_t getpgid(pid_t pid)
{
- return Syscall::invoke(Syscall::PosixGetpgid, (dword)pid);
+ int rc = Syscall::invoke(Syscall::PosixGetpgid, (dword)pid);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
pid_t getpgrp()
{
- return Syscall::invoke(Syscall::PosixGetpgrp);
+ int rc = Syscall::invoke(Syscall::PosixGetpgrp);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
}
int open(const char* path, int options)
diff --git a/LibC/unistd.h b/LibC/unistd.h
index 205002dff8..abcf410aba 100644
--- a/LibC/unistd.h
+++ b/LibC/unistd.h
@@ -9,6 +9,7 @@ extern char** environ;
inline int getpagesize() { return 4096; }
pid_t fork();
+int execve(const char* filename, const char** argv, const char** envp);
pid_t getsid(pid_t);
pid_t setsid();
int setpgid(pid_t pid, pid_t pgid);
diff --git a/Userland/sh.cpp b/Userland/sh.cpp
index 6efa9ce4de..6c83c806e4 100644
--- a/Userland/sh.cpp
+++ b/Userland/sh.cpp
@@ -39,6 +39,32 @@ static int sh_fork(int, const char**)
return 0;
}
+static int sh_fe(int, const char**)
+{
+ pid_t pid = fork();
+ if (!pid) {
+ int rc = execve("/bin/ps", nullptr, nullptr);
+ if (rc < 0) {
+ perror("execve");
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+static int sh_fef(int, const char**)
+{
+ pid_t pid = fork();
+ if (!pid) {
+ int rc = execve("/bin/psx", nullptr, nullptr);
+ if (rc < 0) {
+ perror("execve");
+ exit(1);
+ }
+ }
+ return 0;
+}
+
static int sh_exit(int, const char**)
{
printf("Good-bye!\n");
@@ -101,7 +127,14 @@ static bool handle_builtin(int argc, const char** argv, int& retval)
retval = sh_exit(argc, argv);
return true;
}
-
+ if (!strcmp(argv[0], "fe")) {
+ retval = sh_fe(argc, argv);
+ return true;
+ }
+ if (!strcmp(argv[0], "fef")) {
+ retval = sh_fef(argc, argv);
+ return true;
+ }
if (!strcmp(argv[0], "fork")) {
retval = sh_fork(argc, argv);
return true;