Quellcode durchsuchen

Share code between spawn() and exec() implementations.

Okay, now there's only one ELF loading client in the process launch code.
Andreas Kling vor 6 Jahren
Ursprung
Commit
dd060d0fa8
7 geänderte Dateien mit 85 neuen und 127 gelöschten Zeilen
  1. 54 99
      Kernel/Process.cpp
  2. 2 2
      Kernel/Process.h
  3. 1 1
      Kernel/Syscall.cpp
  4. 19 17
      Kernel/TSS.h
  5. 5 5
      Kernel/init.cpp
  6. 2 2
      LibC/process.cpp
  7. 2 1
      LibC/process.h

+ 54 - 99
Kernel/Process.cpp

@@ -359,7 +359,8 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
     }
 
     InterruptDisabler disabler;
-    loadTaskRegister(s_kernelProcess->selector());
+    if (current == this)
+        loadTaskRegister(s_kernelProcess->selector());
 
     m_name = parts.takeLast();
 
@@ -392,8 +393,9 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
     kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), filename, m_tss.eip);
 #endif
 
-    yield();
-    ASSERT(false);
+    if (current == this)
+        yield();
+
     return 0;
 }
 
@@ -430,129 +432,82 @@ int Process::sys$execve(const char* filename, const char** argv, const char** en
         }
     }
 
-    return exec(path, move(arguments), move(environment));
+    int rc = exec(path, move(arguments), move(environment));
+    ASSERT(rc < 0);
+    return rc;
 }
 
-int Process::sys$spawn(const char* path, const char** args)
+pid_t Process::sys$spawn(const char* filename, const char** argv, const char** envp)
 {
-    if (args) {
-        for (size_t i = 0; args[i]; ++i) {
-            VALIDATE_USER_READ(args[i], strlen(args[i]));
+    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('/');
+
+    Vector<String> arguments;
+    if (argv) {
+        for (size_t i = 0; argv[i]; ++i) {
+            arguments.append(argv[i]);
+        }
+    } else {
+        arguments.append(parts.last());
+    }
+
+    Vector<String> environment;
+    if (envp) {
+        for (size_t i = 0; envp[i]; ++i) {
+            environment.append(envp[i]);
         }
     }
 
-    int error = 0;
-    auto* child = Process::createUserProcess(path, m_uid, m_gid, m_pid, error, args, m_tty);
+    int error;
+    auto* child = create_user_process(path, m_uid, m_gid, m_pid, error, move(arguments), move(environment), m_tty);
     if (child)
         return child->pid();
     return error;
 }
 
-Process* Process::createUserProcess(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args, TTY* tty)
+Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, pid_t parent_pid, int& error, Vector<String>&& arguments, Vector<String>&& environment, TTY* tty)
 {
+    // FIXME: Don't split() the path twice (sys$spawn also does it...)
     auto parts = path.split('/');
-    if (parts.isEmpty()) {
-        error = -ENOENT;
-        return nullptr;
+    if (arguments.isEmpty()) {
+        arguments.append(parts.last());
     }
-
     RetainPtr<VirtualFileSystem::Node> cwd;
     {
         InterruptDisabler disabler;
-        if (auto* parentProcess = Process::fromPID(parentPID))
-            cwd = parentProcess->m_cwd.copyRef();
-        if (!cwd)
-            cwd = VirtualFileSystem::the().root();
+        if (auto* parent = Process::fromPID(parent_pid))
+            cwd = parent->m_cwd.copyRef();
     }
+    if (!cwd)
+        cwd = VirtualFileSystem::the().root();
 
-    auto handle = VirtualFileSystem::the().open(path, error, 0, cwd ? cwd->inode : InodeIdentifier());
-    if (!handle)
-        return nullptr;
+    auto* process = new Process(parts.takeLast(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
 
-    if (!handle->metadata().mayExecute(uid, gid)) {
-        error = -EACCES;
+    error = process->exec(path, move(arguments), move(environment));
+    if (error != 0)
         return nullptr;
-    }
 
-    auto elfData = handle->readEntireFile();
-    if (!elfData) {
-        error = -EIO; // FIXME: Get a more detailed error from VFS.
-        return nullptr;
-    }
+    ProcFileSystem::the().addProcess(*process);
 
-    Vector<String> processArguments;
-    if (args) {
-        for (size_t i = 0; args[i]; ++i) {
-            processArguments.append(args[i]);
-        }
-    } else {
-        processArguments.append(parts.last());
-    }
-
-    Vector<String> processEnvironment;
-    processEnvironment.append("PATH=/bin");
-    processEnvironment.append("SHELL=/bin/sh");
-    processEnvironment.append("TERM=console");
-    processEnvironment.append("HOME=/");
-
-    auto* t = new Process(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty);
-
-    t->m_arguments = move(processArguments);
-    t->m_initialEnvironment = move(processEnvironment);
-
-    ExecSpace space;
-    Region* region = nullptr;
-
-    ProcessPagingScope pagingScope(*t);
-    space.hookableAlloc = [&] (const String& name, size_t size) {
-        if (!size)
-            return (void*)nullptr;
-        size = ((size / 4096) + 1) * 4096; // FIXME: Use ceil_div?
-        region = t->allocateRegion(size, String(name));
-        return (void*)region->linearAddress.get();
-    };
-    bool success = space.loadELF(move(elfData));
-    if (!success) {
-        delete t;
-        kprintf("Failure loading ELF %s\n", path.characters());
-        error = -ENOEXEC;
-        return nullptr;
-    }
-
-    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);
-        t->m_subregions.append(make<Subregion>(*region, roundedOffset, roundedSize, roundedLaddr, String(name)));
-#ifdef SUBREGION_DEBUG
-        kprintf("   req subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), offset, size, laddr.get());
-        kprintf("actual subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), roundedOffset, roundedSize, roundedLaddr.get());
-#endif
-        MM.mapSubregion(*t, *t->m_subregions.last());
-    });
-
-    t->m_tss.eip = (dword)space.symbolPtr("_start");
-    if (!t->m_tss.eip) {
-        // FIXME: This is ugly. If we need to do this, it should be at a different level.
-        delete t;
-        error = -ENOEXEC;
-        return nullptr;
-    }
-
-    ASSERT(region);
-
-    ProcFileSystem::the().addProcess(*t);
-
-    s_processes->prepend(t);
+    s_processes->prepend(process);
     system.nprocess++;
 #ifdef TASK_DEBUG
-    kprintf("Process %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
+    kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
 #endif
     error = 0;
-    return t;
+    return process;
 }
 
 int Process::sys$get_environment(char*** environ)

+ 2 - 2
Kernel/Process.h

@@ -19,7 +19,7 @@ class Process : public InlineLinkedListNode<Process> {
     friend class InlineLinkedListNode<Process>;
 public:
     static Process* createKernelProcess(void (*entry)(), String&& name);
-    static Process* createUserProcess(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr, TTY* = nullptr);
+    static Process* create_user_process(const String& path, uid_t, gid_t, pid_t parentPID, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
     ~Process();
 
     static Vector<Process*> allProcesses();
@@ -103,7 +103,7 @@ public:
     int sys$kill(pid_t pid, int sig);
     int sys$geterror() { return m_error; }
     void sys$exit(int status);
-    int sys$spawn(const char* path, const char** args);
+    pid_t sys$spawn(const char* path, const char** args, const char** envp);
     pid_t sys$waitpid(pid_t, int* wstatus, int options);
     void* sys$mmap(void*, size_t size);
     int sys$munmap(void*, size_t size);

+ 1 - 1
Kernel/Syscall.cpp

@@ -58,7 +58,7 @@ static DWORD handle(RegisterDump& regs, DWORD function, DWORD arg1, DWORD arg2,
     case Syscall::PosixGettimeofday:
         return current->sys$gettimeofday((timeval*)arg1);
     case Syscall::Spawn:
-        return current->sys$spawn((const char*)arg1, (const char**)arg2);
+        return current->sys$spawn((const char*)arg1, (const char**)arg2, (const char**)arg3);
     case Syscall::GetDirEntries:
         return current->sys$get_dir_entries((int)arg1, (void*)arg2, (size_t)arg3);
     case Syscall::PosixLstat:

+ 19 - 17
Kernel/TSS.h

@@ -1,21 +1,23 @@
 #pragma once
 
+#include <AK/Types.h>
+
 struct TSS32 {
-    unsigned short backlink, __blh;
-    unsigned long esp0;
-    unsigned short ss0, __ss0h;
-    unsigned long esp1;
-    unsigned short ss1, __ss1h;
-    unsigned long esp2;
-    unsigned short ss2, __ss2h;
-    unsigned long cr3, eip, eflags;
-    unsigned long eax,ecx,edx,ebx,esp,ebp,esi,edi;
-    unsigned short es, __esh;
-    unsigned short cs, __csh;
-    unsigned short ss, __ssh;
-    unsigned short ds, __dsh;
-    unsigned short fs, __fsh;
-    unsigned short gs, __gsh;
-    unsigned short ldt, __ldth;
-    unsigned short trace, iomapbase;
+    word backlink, __blh;
+    dword esp0;
+    word ss0, __ss0h;
+    dword esp1;
+    word ss1, __ss1h;
+    dword esp2;
+    word ss2, __ss2h;
+    dword cr3, eip, eflags;
+    dword eax,ecx,edx,ebx,esp,ebp,esi,edi;
+    word es, __esh;
+    word cs, __csh;
+    word ss, __ssh;
+    word ds, __dsh;
+    word fs, __fsh;
+    word gs, __gsh;
+    word ldt, __ldth;
+    word trace, iomapbase;
 } PACKED;

+ 5 - 5
Kernel/init.cpp

@@ -145,7 +145,7 @@ static void spawn_stress()
 
     for (unsigned i = 0; i < 10000; ++i) {
         int error;
-        Process::createUserProcess("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0);
+        Process::create_user_process("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
 //        kprintf("malloc stats: alloc:%u free:%u page_aligned:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_page_aligned, kmalloc_sum_eternal);
 //        kprintf("delta:%u\n", sum_alloc - lastAlloc);
         lastAlloc = sum_alloc;
@@ -230,11 +230,11 @@ static void init_stage2()
 #endif
 
     int error;
-    auto* sh0 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0);
+    auto* sh0 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
 #ifdef SPAWN_MULTIPLE_SHELLS
-    auto* sh1 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty1);
-    auto* sh2 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty2);
-    auto* sh3 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty3);
+    auto* sh1 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty1);
+    auto* sh2 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty2);
+    auto* sh3 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty3);
 #endif
 
 #ifdef STRESS_TEST_SPAWNING

+ 2 - 2
LibC/process.cpp

@@ -4,9 +4,9 @@
 
 extern "C" {
 
-int spawn(const char* path, const char** args)
+int spawn(const char* path, const char** args, const char** envp)
 {
-    int rc = Syscall::invoke(Syscall::Spawn, (dword)path, (dword)args);
+    int rc = Syscall::invoke(Syscall::Spawn, (dword)path, (dword)args, (dword)envp);
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 

+ 2 - 1
LibC/process.h

@@ -1,10 +1,11 @@
 #pragma once
 
 #include <sys/cdefs.h>
+#include <sys/types.h>
 
 __BEGIN_DECLS
 
-int spawn(const char* path, const char** args);
+pid_t spawn(const char* path, const char** args, const char** envp);
 
 __END_DECLS