Parcourir la source

Implemented sys$execve().

It's really crufty, but it basically works!
Andreas Kling il y a 6 ans
Parent
commit
202bdb553c
9 fichiers modifiés avec 215 ajouts et 21 suppressions
  1. 8 8
      Kernel/MemoryManager.cpp
  2. 2 2
      Kernel/MemoryManager.h
  3. 146 3
      Kernel/Process.cpp
  4. 1 0
      Kernel/Process.h
  5. 2 0
      Kernel/Syscall.cpp
  6. 1 0
      Kernel/Syscall.h
  7. 20 7
      LibC/unistd.cpp
  8. 1 0
      LibC/unistd.h
  9. 34 1
      Userland/sh.cpp

+ 8 - 8
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
 }
 

+ 2 - 2
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*);

+ 146 - 3
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
 

+ 1 - 0
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();
 

+ 2 - 0
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;

+ 1 - 0
Kernel/Syscall.h

@@ -48,6 +48,7 @@ enum Function {
     PosixTcsetpgrp = 0x2016,
     PosixTcgetpgrp = 0x2017,
     PosixFork = 0x2018,
+    PosixExecve = 0x2019,
 };
 
 void initialize();

+ 20 - 7
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)

+ 1 - 0
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);

+ 34 - 1
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;