2018-10-16 09:01:38 +00:00
|
|
|
#include "types.h"
|
2018-11-01 12:15:46 +00:00
|
|
|
#include "Process.h"
|
2018-10-16 09:01:38 +00:00
|
|
|
#include "kmalloc.h"
|
|
|
|
#include "VGA.h"
|
|
|
|
#include "StdLib.h"
|
|
|
|
#include "i386.h"
|
|
|
|
#include "system.h"
|
2018-10-18 08:28:09 +00:00
|
|
|
#include <VirtualFileSystem/FileHandle.h>
|
|
|
|
#include <VirtualFileSystem/VirtualFileSystem.h>
|
2018-10-22 13:42:39 +00:00
|
|
|
#include <ELFLoader/ExecSpace.h>
|
2018-10-17 21:13:55 +00:00
|
|
|
#include "MemoryManager.h"
|
2018-10-25 10:06:00 +00:00
|
|
|
#include "errno.h"
|
2018-10-25 11:53:49 +00:00
|
|
|
#include "i8253.h"
|
2018-10-25 15:29:49 +00:00
|
|
|
#include "RTC.h"
|
2018-10-26 15:42:12 +00:00
|
|
|
#include "ProcFileSystem.h"
|
2018-10-27 12:56:52 +00:00
|
|
|
#include <AK/StdLib.h>
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-23 08:12:50 +00:00
|
|
|
//#define DEBUG_IO
|
2018-10-23 22:20:34 +00:00
|
|
|
//#define TASK_DEBUG
|
2018-10-29 20:54:11 +00:00
|
|
|
//#define SCHEDULER_DEBUG
|
2018-10-23 22:20:34 +00:00
|
|
|
|
2018-11-01 11:45:51 +00:00
|
|
|
// FIXME: Only do a single validation for accesses that don't span multiple pages.
|
|
|
|
// FIXME: Some places pass strlen(arg1) as arg2. This doesn't seem entirely perfect..
|
|
|
|
#define VALIDATE_USER_READ(b, s) \
|
2018-10-28 08:57:22 +00:00
|
|
|
do { \
|
|
|
|
LinearAddress laddr((dword)(b)); \
|
2018-11-01 11:45:51 +00:00
|
|
|
if (!validate_user_read(laddr) || !validate_user_read(laddr.offset((s) - 1))) \
|
|
|
|
return -EFAULT; \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define VALIDATE_USER_WRITE(b, s) \
|
|
|
|
do { \
|
|
|
|
LinearAddress laddr((dword)(b)); \
|
|
|
|
if (!validate_user_write(laddr) || !validate_user_write(laddr.offset((s) - 1))) \
|
2018-10-28 08:57:22 +00:00
|
|
|
return -EFAULT; \
|
|
|
|
} while(0)
|
|
|
|
|
2018-10-23 22:20:34 +00:00
|
|
|
static const DWORD defaultStackSize = 16384;
|
2018-10-23 08:12:50 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Process* current;
|
|
|
|
Process* s_kernelProcess;
|
2018-10-16 09:01:38 +00:00
|
|
|
|
|
|
|
static pid_t next_pid;
|
2018-11-01 12:15:46 +00:00
|
|
|
static InlineLinkedList<Process>* s_processes;
|
|
|
|
static InlineLinkedList<Process>* s_deadProcesses;
|
2018-10-26 07:54:29 +00:00
|
|
|
static String* s_hostname;
|
|
|
|
|
2018-10-26 12:56:21 +00:00
|
|
|
static String& hostnameStorage(InterruptDisabler&)
|
2018-10-26 07:54:29 +00:00
|
|
|
{
|
|
|
|
ASSERT(s_hostname);
|
|
|
|
return *s_hostname;
|
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-26 12:56:21 +00:00
|
|
|
static String getHostname()
|
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
return hostnameStorage(disabler).isolatedCopy();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
static bool contextSwitch(Process*);
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
static void redoKernelProcessTSS()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
if (!s_kernelProcess->selector())
|
2018-11-01 15:23:12 +00:00
|
|
|
s_kernelProcess->setSelector(gdt_alloc_entry());
|
2018-10-16 09:06:35 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
auto& tssDescriptor = getGDTEntry(s_kernelProcess->selector());
|
2018-10-16 09:06:35 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
tssDescriptor.setBase(&s_kernelProcess->tss());
|
2018-10-16 09:06:35 +00:00
|
|
|
tssDescriptor.setLimit(0xffff);
|
|
|
|
tssDescriptor.dpl = 0;
|
|
|
|
tssDescriptor.segment_present = 1;
|
|
|
|
tssDescriptor.granularity = 1;
|
|
|
|
tssDescriptor.zero = 0;
|
|
|
|
tssDescriptor.operation_size = 1;
|
|
|
|
tssDescriptor.descriptor_type = 0;
|
|
|
|
tssDescriptor.type = 9;
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
flushGDT();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::prepForIRETToNewProcess()
|
2018-10-16 09:06:35 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
redoKernelProcessTSS();
|
|
|
|
s_kernelProcess->tss().backlink = current->selector();
|
|
|
|
loadTaskRegister(s_kernelProcess->selector());
|
2018-10-16 09:06:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 13:41:49 +00:00
|
|
|
static void hlt_loop()
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
asm volatile("hlt");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::initialize()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
current = nullptr;
|
|
|
|
next_pid = 0;
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes = new InlineLinkedList<Process>;
|
|
|
|
s_deadProcesses = new InlineLinkedList<Process>;
|
2018-11-01 13:41:49 +00:00
|
|
|
s_kernelProcess = Process::createKernelProcess(hlt_loop, "colonel");
|
2018-10-26 07:54:29 +00:00
|
|
|
s_hostname = new String("birx");
|
2018-11-01 12:15:46 +00:00
|
|
|
redoKernelProcessTSS();
|
|
|
|
loadTaskRegister(s_kernelProcess->selector());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 11:56:51 +00:00
|
|
|
template<typename Callback>
|
|
|
|
static void forEachProcess(Callback callback)
|
|
|
|
{
|
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
if (!callback(*process))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 13:06:48 +00:00
|
|
|
void Process::for_each_in_pgrp(pid_t pgid, Function<void(Process&)> callback)
|
|
|
|
{
|
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
if (process->pgid() == pgid)
|
|
|
|
callback(*process);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Vector<Process*> Process::allProcesses()
|
2018-10-23 10:44:46 +00:00
|
|
|
{
|
2018-10-25 08:33:10 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
Vector<Process*> processes;
|
|
|
|
processes.ensureCapacity(s_processes->sizeSlow());
|
|
|
|
for (auto* process = s_processes->head(); process; process = process->next())
|
|
|
|
processes.append(process);
|
|
|
|
return processes;
|
2018-10-23 10:44:46 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 10:28:23 +00:00
|
|
|
Region* Process::allocate_region(LinearAddress laddr, size_t size, String&& name, bool is_readable, bool is_writable)
|
2018-10-18 11:05:00 +00:00
|
|
|
{
|
2018-10-18 12:53:00 +00:00
|
|
|
// FIXME: This needs sanity checks. What if this overlaps existing regions?
|
2018-11-03 10:28:23 +00:00
|
|
|
if (laddr.is_null()) {
|
|
|
|
laddr = m_nextRegion;
|
|
|
|
m_nextRegion = m_nextRegion.offset(size).offset(PAGE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
laddr.mask(0xfffff000);
|
2018-10-18 12:53:00 +00:00
|
|
|
|
2018-10-27 12:56:52 +00:00
|
|
|
auto zone = MM.createZone(size);
|
2018-10-18 12:53:00 +00:00
|
|
|
ASSERT(zone);
|
2018-11-03 10:28:23 +00:00
|
|
|
|
2018-11-03 10:36:45 +00:00
|
|
|
m_regions.append(adopt(*new Region(laddr, size, move(zone), move(name), is_readable, is_writable)));
|
2018-11-03 10:28:23 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
MM.mapRegion(*this, *m_regions.last());
|
2018-10-18 12:53:00 +00:00
|
|
|
return m_regions.last().ptr();
|
2018-10-18 11:05:00 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 10:28:23 +00:00
|
|
|
bool Process::deallocate_region(Region& region)
|
2018-10-24 07:48:24 +00:00
|
|
|
{
|
2018-10-28 08:36:21 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-10-24 07:48:24 +00:00
|
|
|
for (size_t i = 0; i < m_regions.size(); ++i) {
|
|
|
|
if (m_regions[i].ptr() == ®ion) {
|
2018-10-27 12:56:52 +00:00
|
|
|
MM.unmapRegion(*this, region);
|
2018-10-24 07:48:24 +00:00
|
|
|
m_regions.remove(i);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:21:02 +00:00
|
|
|
Region* Process::regionFromRange(LinearAddress laddr, size_t size)
|
2018-10-24 07:48:24 +00:00
|
|
|
{
|
|
|
|
for (auto& region : m_regions) {
|
|
|
|
if (region->linearAddress == laddr && region->size == size)
|
|
|
|
return region.ptr();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$set_mmap_name(void* addr, size_t size, const char* name)
|
2018-10-28 08:57:22 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_READ(name, strlen(name));
|
2018-10-28 08:57:22 +00:00
|
|
|
auto* region = regionFromRange(LinearAddress((dword)addr), size);
|
|
|
|
if (!region)
|
|
|
|
return -EINVAL;
|
|
|
|
region->name = name;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void* Process::sys$mmap(void* addr, size_t size)
|
2018-10-24 07:48:24 +00:00
|
|
|
{
|
2018-10-31 16:50:43 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-10-24 07:48:24 +00:00
|
|
|
// FIXME: Implement mapping at a client-preferred address.
|
|
|
|
ASSERT(addr == nullptr);
|
2018-11-03 10:28:23 +00:00
|
|
|
auto* region = allocate_region(LinearAddress(), size, "mmap");
|
2018-10-24 07:48:24 +00:00
|
|
|
if (!region)
|
|
|
|
return (void*)-1;
|
2018-10-27 12:56:52 +00:00
|
|
|
MM.mapRegion(*this, *region);
|
2018-10-24 07:48:24 +00:00
|
|
|
return (void*)region->linearAddress.get();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$munmap(void* addr, size_t size)
|
2018-10-24 07:48:24 +00:00
|
|
|
{
|
2018-10-31 16:50:43 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-10-24 07:48:24 +00:00
|
|
|
auto* region = regionFromRange(LinearAddress((dword)addr), size);
|
|
|
|
if (!region)
|
|
|
|
return -1;
|
2018-11-03 10:28:23 +00:00
|
|
|
if (!deallocate_region(*region))
|
2018-10-24 07:48:24 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$gethostname(char* buffer, size_t size)
|
2018-10-26 07:54:29 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(buffer, size);
|
2018-10-26 12:56:21 +00:00
|
|
|
auto hostname = getHostname();
|
|
|
|
if (size < (hostname.length() + 1))
|
2018-10-26 07:54:29 +00:00
|
|
|
return -ENAMETOOLONG;
|
2018-10-26 12:56:21 +00:00
|
|
|
memcpy(buffer, hostname.characters(), size);
|
2018-10-26 09:16:56 +00:00
|
|
|
return 0;
|
2018-10-26 07:54:29 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
Process* Process::fork(RegisterDump& regs)
|
|
|
|
{
|
|
|
|
auto* child = new Process(String(m_name), m_uid, m_gid, m_pid, m_ring, m_cwd.copyRef(), m_executable.copyRef(), m_tty, this);
|
|
|
|
#ifdef FORK_DEBUG
|
|
|
|
dbgprintf("fork: child=%p\n", child);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// FIXME: An honest fork() would copy these. Needs a Vector copy ctor.
|
|
|
|
child->m_arguments = m_arguments;
|
|
|
|
child->m_initialEnvironment = m_initialEnvironment;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (auto& region : m_regions) {
|
|
|
|
#ifdef FORK_DEBUG
|
|
|
|
dbgprintf("fork: cloning Region{%p}\n", region.ptr());
|
|
|
|
#endif
|
|
|
|
auto cloned_region = region->clone();
|
|
|
|
child->m_regions.append(move(cloned_region));
|
|
|
|
MM.mapRegion(*child, *child->m_regions.last());
|
|
|
|
}
|
|
|
|
|
|
|
|
child->m_tss.eax = 0; // fork() returns 0 in the child :^)
|
|
|
|
child->m_tss.ebx = regs.ebx;
|
|
|
|
child->m_tss.ecx = regs.ecx;
|
|
|
|
child->m_tss.edx = regs.edx;
|
|
|
|
child->m_tss.ebp = regs.ebp;
|
|
|
|
child->m_tss.esp = regs.esp_if_crossRing;
|
|
|
|
child->m_tss.esi = regs.esi;
|
|
|
|
child->m_tss.edi = regs.edi;
|
|
|
|
child->m_tss.eflags = regs.eflags;
|
|
|
|
child->m_tss.eip = regs.eip;
|
|
|
|
child->m_tss.cs = regs.cs;
|
|
|
|
child->m_tss.ds = regs.ds;
|
|
|
|
child->m_tss.es = regs.es;
|
|
|
|
child->m_tss.fs = regs.fs;
|
|
|
|
child->m_tss.gs = regs.gs;
|
|
|
|
child->m_tss.ss = regs.ss_if_crossRing;
|
|
|
|
|
|
|
|
#ifdef FORK_DEBUG
|
|
|
|
dbgprintf("fork: child will begin executing at %w:%x with stack %w:%x\n", child->m_tss.cs, child->m_tss.eip, child->m_tss.ss, child->m_tss.esp);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ProcFileSystem::the().addProcess(*child);
|
|
|
|
|
|
|
|
s_processes->prepend(child);
|
|
|
|
system.nprocess++;
|
|
|
|
#ifdef TASK_DEBUG
|
|
|
|
kprintf("Process %u (%s) forked from %u @ %p\n", child->pid(), child->name().characters(), m_pid, child->m_tss.eip);
|
|
|
|
#endif
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t Process::sys$fork(RegisterDump& regs)
|
|
|
|
{
|
|
|
|
auto* child = fork(regs);
|
|
|
|
ASSERT(child);
|
|
|
|
return child->pid();
|
|
|
|
}
|
|
|
|
|
2018-11-03 09:20:23 +00:00
|
|
|
int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment)
|
2018-11-03 00:49:40 +00:00
|
|
|
{
|
|
|
|
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.
|
|
|
|
|
|
|
|
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);
|
|
|
|
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;
|
2018-11-03 01:04:36 +00:00
|
|
|
MM.enter_process_paging_scope(*this);
|
2018-11-03 10:28:23 +00:00
|
|
|
space.alloc_section_hook = [&] (LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable, const String& name) {
|
|
|
|
ASSERT(size);
|
2018-11-03 00:49:40 +00:00
|
|
|
size = ((size / 4096) + 1) * 4096; // FIXME: Use ceil_div?
|
2018-11-03 10:28:23 +00:00
|
|
|
region = allocate_region(laddr, size, String(name), is_readable, is_writable);
|
|
|
|
return laddr.asPtr();
|
2018-11-03 00:49:40 +00:00
|
|
|
};
|
|
|
|
bool success = space.loadELF(move(elfData));
|
|
|
|
if (!success) {
|
|
|
|
m_page_directory = old_page_directory;
|
2018-11-03 01:04:36 +00:00
|
|
|
MM.enter_process_paging_scope(*this);
|
|
|
|
MM.release_page_directory(*new_page_directory);
|
2018-11-03 00:49:40 +00:00
|
|
|
m_regions = move(old_regions);
|
2018-11-03 01:04:36 +00:00
|
|
|
kprintf("sys$execve: Failure loading %s\n", path.characters());
|
2018-11-03 00:49:40 +00:00
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry_eip = (dword)space.symbolPtr("_start");
|
|
|
|
if (!entry_eip) {
|
|
|
|
m_page_directory = old_page_directory;
|
2018-11-03 01:04:36 +00:00
|
|
|
MM.enter_process_paging_scope(*this);
|
|
|
|
MM.release_page_directory(*new_page_directory);
|
2018-11-03 00:49:40 +00:00
|
|
|
m_regions = move(old_regions);
|
|
|
|
return -ENOEXEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InterruptDisabler disabler;
|
2018-11-03 09:49:13 +00:00
|
|
|
if (current == this)
|
|
|
|
loadTaskRegister(s_kernelProcess->selector());
|
2018-11-03 00:49:40 +00:00
|
|
|
|
|
|
|
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;
|
2018-11-03 10:28:23 +00:00
|
|
|
auto* stack_region = allocate_region(LinearAddress(), defaultStackSize, "stack");
|
2018-11-03 00:49:40 +00:00
|
|
|
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();
|
2018-11-03 09:20:23 +00:00
|
|
|
m_arguments = move(arguments);
|
|
|
|
m_initialEnvironment = move(environment);
|
2018-11-03 00:49:40 +00:00
|
|
|
|
|
|
|
#ifdef TASK_DEBUG
|
2018-11-03 09:20:23 +00:00
|
|
|
kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), filename, m_tss.eip);
|
2018-11-03 00:49:40 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
if (current == this)
|
|
|
|
yield();
|
|
|
|
|
2018-11-03 00:49:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-03 09:20:23 +00:00
|
|
|
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('/');
|
|
|
|
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
int rc = exec(path, move(arguments), move(environment));
|
|
|
|
ASSERT(rc < 0);
|
|
|
|
return rc;
|
2018-11-03 09:20:23 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
pid_t Process::sys$spawn(const char* filename, const char** argv, const char** envp)
|
2018-10-23 08:12:50 +00:00
|
|
|
{
|
2018-11-03 09:49:13 +00:00
|
|
|
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]);
|
2018-10-31 16:50:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
int error;
|
|
|
|
auto* child = create_user_process(path, m_uid, m_gid, m_pid, error, move(arguments), move(environment), m_tty);
|
2018-10-23 08:12:50 +00:00
|
|
|
if (child)
|
|
|
|
return child->pid();
|
2018-10-25 10:06:00 +00:00
|
|
|
return error;
|
2018-10-23 08:12:50 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
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)
|
2018-10-22 13:42:39 +00:00
|
|
|
{
|
2018-11-03 09:49:13 +00:00
|
|
|
// FIXME: Don't split() the path twice (sys$spawn also does it...)
|
2018-10-22 13:42:39 +00:00
|
|
|
auto parts = path.split('/');
|
2018-11-03 09:49:13 +00:00
|
|
|
if (arguments.isEmpty()) {
|
|
|
|
arguments.append(parts.last());
|
2018-10-25 10:06:00 +00:00
|
|
|
}
|
2018-10-26 12:24:11 +00:00
|
|
|
RetainPtr<VirtualFileSystem::Node> cwd;
|
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
2018-11-03 09:49:13 +00:00
|
|
|
if (auto* parent = Process::fromPID(parent_pid))
|
|
|
|
cwd = parent->m_cwd.copyRef();
|
2018-10-27 14:43:03 +00:00
|
|
|
}
|
2018-11-03 09:49:13 +00:00
|
|
|
if (!cwd)
|
|
|
|
cwd = VirtualFileSystem::the().root();
|
2018-10-27 14:43:03 +00:00
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
auto* process = new Process(parts.takeLast(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
|
2018-10-26 09:16:56 +00:00
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
error = process->exec(path, move(arguments), move(environment));
|
|
|
|
if (error != 0)
|
2018-10-22 13:42:39 +00:00
|
|
|
return nullptr;
|
2018-11-01 10:30:48 +00:00
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
ProcFileSystem::the().addProcess(*process);
|
2018-11-01 13:41:49 +00:00
|
|
|
|
2018-11-03 09:49:13 +00:00
|
|
|
s_processes->prepend(process);
|
2018-10-22 13:42:39 +00:00
|
|
|
system.nprocess++;
|
2018-10-23 22:20:34 +00:00
|
|
|
#ifdef TASK_DEBUG
|
2018-11-03 09:49:13 +00:00
|
|
|
kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
|
2018-10-23 22:20:34 +00:00
|
|
|
#endif
|
2018-10-25 10:06:00 +00:00
|
|
|
error = 0;
|
2018-11-03 09:49:13 +00:00
|
|
|
return process;
|
2018-10-22 13:42:39 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$get_environment(char*** environ)
|
2018-10-31 16:50:43 +00:00
|
|
|
{
|
2018-11-03 10:28:23 +00:00
|
|
|
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "environ");
|
2018-10-31 16:50:43 +00:00
|
|
|
if (!region)
|
|
|
|
return -ENOMEM;
|
|
|
|
MM.mapRegion(*this, *region);
|
|
|
|
char* envpage = (char*)region->linearAddress.get();
|
|
|
|
*environ = (char**)envpage;
|
|
|
|
char* bufptr = envpage + (sizeof(char*) * (m_initialEnvironment.size() + 1));
|
|
|
|
for (size_t i = 0; i < m_initialEnvironment.size(); ++i) {
|
|
|
|
(*environ)[i] = bufptr;
|
|
|
|
memcpy(bufptr, m_initialEnvironment[i].characters(), m_initialEnvironment[i].length());
|
|
|
|
bufptr += m_initialEnvironment[i].length();
|
|
|
|
*(bufptr++) = '\0';
|
|
|
|
}
|
|
|
|
(*environ)[m_initialEnvironment.size()] = nullptr;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$get_arguments(int* argc, char*** argv)
|
2018-10-26 09:16:56 +00:00
|
|
|
{
|
2018-11-03 10:28:23 +00:00
|
|
|
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "argv");
|
2018-10-26 09:16:56 +00:00
|
|
|
if (!region)
|
|
|
|
return -ENOMEM;
|
2018-10-27 12:56:52 +00:00
|
|
|
MM.mapRegion(*this, *region);
|
2018-10-26 09:16:56 +00:00
|
|
|
char* argpage = (char*)region->linearAddress.get();
|
|
|
|
*argc = m_arguments.size();
|
|
|
|
*argv = (char**)argpage;
|
|
|
|
char* bufptr = argpage + (sizeof(char*) * m_arguments.size());
|
|
|
|
for (size_t i = 0; i < m_arguments.size(); ++i) {
|
|
|
|
(*argv)[i] = bufptr;
|
|
|
|
memcpy(bufptr, m_arguments[i].characters(), m_arguments[i].length());
|
|
|
|
bufptr += m_arguments[i].length();
|
|
|
|
*(bufptr++) = '\0';
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Process* Process::createKernelProcess(void (*e)(), String&& name)
|
2018-10-25 09:15:17 +00:00
|
|
|
{
|
2018-11-01 13:41:49 +00:00
|
|
|
auto* process = new Process(move(name), (uid_t)0, (gid_t)0, (pid_t)0, Ring0);
|
2018-11-01 12:15:46 +00:00
|
|
|
process->m_tss.eip = (dword)e;
|
2018-10-25 09:15:17 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (process->pid() != 0) {
|
2018-10-25 09:15:17 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes->prepend(process);
|
2018-10-25 09:15:17 +00:00
|
|
|
system.nprocess++;
|
2018-11-01 13:41:49 +00:00
|
|
|
ProcFileSystem::the().addProcess(*process);
|
2018-10-25 09:15:17 +00:00
|
|
|
#ifdef TASK_DEBUG
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
|
2018-10-25 09:15:17 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
return process;
|
2018-10-25 09:15:17 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
Process::Process(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring, RetainPtr<VirtualFileSystem::Node>&& cwd, RetainPtr<VirtualFileSystem::Node>&& executable, TTY* tty, Process* fork_parent)
|
2018-10-22 13:42:39 +00:00
|
|
|
: m_name(move(name))
|
2018-11-02 19:41:58 +00:00
|
|
|
, m_pid(next_pid++) // FIXME: RACE: This variable looks racy!
|
2018-10-22 13:42:39 +00:00
|
|
|
, m_uid(uid)
|
|
|
|
, m_gid(gid)
|
|
|
|
, m_state(Runnable)
|
2018-10-25 09:15:17 +00:00
|
|
|
, m_ring(ring)
|
2018-10-29 23:06:31 +00:00
|
|
|
, m_cwd(move(cwd))
|
2018-10-28 13:11:51 +00:00
|
|
|
, m_executable(move(executable))
|
2018-10-30 12:59:29 +00:00
|
|
|
, m_tty(tty)
|
2018-10-30 14:33:37 +00:00
|
|
|
, m_parentPID(parentPID)
|
2018-10-22 13:42:39 +00:00
|
|
|
{
|
2018-11-02 19:41:58 +00:00
|
|
|
if (fork_parent) {
|
|
|
|
m_sid = fork_parent->m_sid;
|
|
|
|
m_pgid = fork_parent->m_pgid;
|
|
|
|
} else {
|
2018-11-02 11:56:51 +00:00
|
|
|
// FIXME: Use a ProcessHandle? Presumably we're executing *IN* the parent right now though..
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
if (auto* parent = Process::fromPID(m_parentPID)) {
|
|
|
|
m_sid = parent->m_sid;
|
|
|
|
m_pgid = parent->m_pgid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 22:04:34 +00:00
|
|
|
m_page_directory = (PageDirectory*)kmalloc_page_aligned(sizeof(PageDirectory));
|
2018-11-03 00:49:40 +00:00
|
|
|
MM.populate_page_directory(*m_page_directory);
|
2018-11-01 08:01:51 +00:00
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
if (fork_parent) {
|
|
|
|
m_file_descriptors.resize(fork_parent->m_file_descriptors.size());
|
|
|
|
for (size_t i = 0; i < fork_parent->m_file_descriptors.size(); ++i) {
|
|
|
|
if (!fork_parent->m_file_descriptors[i])
|
|
|
|
continue;
|
|
|
|
#ifdef FORK_DEBUG
|
|
|
|
dbgprintf("fork: cloning fd %u... (%p) istty? %um\n", i, fork_parent->m_file_descriptors[i].ptr(), fork_parent->m_file_descriptors[i]->isTTY());
|
|
|
|
#endif
|
|
|
|
m_file_descriptors[i] = fork_parent->m_file_descriptors[i]->clone();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_file_descriptors.resize(m_max_open_file_descriptors);
|
|
|
|
if (tty) {
|
|
|
|
m_file_descriptors[0] = tty->open(O_RDONLY);
|
|
|
|
m_file_descriptors[1] = tty->open(O_WRONLY);
|
|
|
|
m_file_descriptors[2] = tty->open(O_WRONLY);
|
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
if (fork_parent)
|
|
|
|
m_nextRegion = fork_parent->m_nextRegion;
|
|
|
|
else
|
|
|
|
m_nextRegion = LinearAddress(0x10000000);
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
if (fork_parent) {
|
|
|
|
memcpy(&m_tss, &fork_parent->m_tss, sizeof(m_tss));
|
2018-10-16 09:01:38 +00:00
|
|
|
} else {
|
2018-11-02 19:41:58 +00:00
|
|
|
memset(&m_tss, 0, sizeof(m_tss));
|
|
|
|
|
|
|
|
// Only IF is set when a process boots.
|
|
|
|
m_tss.eflags = 0x0202;
|
|
|
|
word cs, ds, ss;
|
|
|
|
|
|
|
|
if (isRing0()) {
|
|
|
|
cs = 0x08;
|
|
|
|
ds = 0x10;
|
|
|
|
ss = 0x10;
|
|
|
|
} else {
|
|
|
|
cs = 0x1b;
|
|
|
|
ds = 0x23;
|
|
|
|
ss = 0x23;
|
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-11-02 19:41:58 +00:00
|
|
|
m_tss.ds = ds;
|
|
|
|
m_tss.es = ds;
|
|
|
|
m_tss.fs = ds;
|
|
|
|
m_tss.gs = ds;
|
|
|
|
m_tss.ss = ss;
|
|
|
|
m_tss.cs = cs;
|
|
|
|
}
|
2018-10-22 09:15:16 +00:00
|
|
|
|
2018-11-01 22:04:34 +00:00
|
|
|
m_tss.cr3 = (dword)m_page_directory;
|
2018-10-17 21:13:55 +00:00
|
|
|
|
2018-10-18 12:53:00 +00:00
|
|
|
if (isRing0()) {
|
|
|
|
// FIXME: This memory is leaked.
|
2018-11-01 12:15:46 +00:00
|
|
|
// But uh, there's also no kernel process termination, so I guess it's not technically leaked...
|
2018-10-31 22:19:15 +00:00
|
|
|
dword stackBottom = (dword)kmalloc_eternal(defaultStackSize);
|
2018-10-26 20:32:35 +00:00
|
|
|
m_stackTop0 = (stackBottom + defaultStackSize) & 0xffffff8;
|
|
|
|
m_tss.esp = m_stackTop0;
|
2018-10-18 12:53:00 +00:00
|
|
|
} else {
|
2018-11-02 19:41:58 +00:00
|
|
|
if (fork_parent) {
|
|
|
|
m_stackTop3 = fork_parent->m_stackTop3;
|
|
|
|
} else {
|
2018-11-03 10:28:23 +00:00
|
|
|
auto* region = allocate_region(LinearAddress(), defaultStackSize, "stack");
|
2018-11-02 19:41:58 +00:00
|
|
|
ASSERT(region);
|
|
|
|
m_stackTop3 = region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8;
|
|
|
|
m_tss.esp = m_stackTop3;
|
|
|
|
}
|
2018-10-18 12:53:00 +00:00
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-25 09:15:17 +00:00
|
|
|
if (isRing3()) {
|
2018-11-01 12:15:46 +00:00
|
|
|
// Ring3 processes need a separate stack for Ring0.
|
2018-10-18 12:53:00 +00:00
|
|
|
m_kernelStack = kmalloc(defaultStackSize);
|
2018-10-26 20:32:35 +00:00
|
|
|
m_stackTop0 = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
|
2018-10-16 09:01:38 +00:00
|
|
|
m_tss.ss0 = 0x10;
|
2018-10-26 20:32:35 +00:00
|
|
|
m_tss.esp0 = m_stackTop0;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HACK: Ring2 SS in the TSS is the current PID.
|
|
|
|
m_tss.ss2 = m_pid;
|
2018-10-25 09:15:17 +00:00
|
|
|
m_farPtr.offset = 0x98765432;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Process::~Process()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-25 09:15:17 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-10-26 15:42:12 +00:00
|
|
|
ProcFileSystem::the().removeProcess(*this);
|
2018-10-17 22:26:30 +00:00
|
|
|
system.nprocess--;
|
2018-11-01 15:23:12 +00:00
|
|
|
|
|
|
|
gdt_free_entry(selector());
|
2018-10-18 12:53:00 +00:00
|
|
|
|
|
|
|
if (m_kernelStack) {
|
|
|
|
kfree(m_kernelStack);
|
|
|
|
m_kernelStack = nullptr;
|
|
|
|
}
|
2018-11-01 22:04:34 +00:00
|
|
|
|
2018-11-03 00:49:40 +00:00
|
|
|
MM.release_page_directory(*m_page_directory);
|
2018-10-18 12:53:00 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::dumpRegions()
|
2018-10-18 12:53:00 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process %s(%u) regions:\n", name().characters(), pid());
|
2018-10-18 12:53:00 +00:00
|
|
|
kprintf("BEGIN END SIZE NAME\n");
|
|
|
|
for (auto& region : m_regions) {
|
|
|
|
kprintf("%x -- %x %x %s\n",
|
|
|
|
region->linearAddress.get(),
|
|
|
|
region->linearAddress.offset(region->size - 1).get(),
|
|
|
|
region->size,
|
|
|
|
region->name.characters());
|
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::notify_waiters(pid_t waitee, int exit_status, int signal)
|
2018-11-01 00:04:02 +00:00
|
|
|
{
|
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
2018-11-01 12:15:46 +00:00
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
if (process->waitee() == waitee)
|
|
|
|
process->m_waiteeStatus = (exit_status << 8) | (signal);
|
2018-11-01 00:04:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::sys$exit(int status)
|
2018-10-22 09:43:55 +00:00
|
|
|
{
|
|
|
|
cli();
|
2018-10-23 22:20:34 +00:00
|
|
|
#ifdef TASK_DEBUG
|
2018-10-22 09:43:55 +00:00
|
|
|
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
2018-10-23 22:20:34 +00:00
|
|
|
#endif
|
2018-10-22 09:43:55 +00:00
|
|
|
|
2018-11-01 13:21:02 +00:00
|
|
|
set_state(Exiting);
|
2018-10-22 09:43:55 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes->remove(this);
|
2018-10-22 09:43:55 +00:00
|
|
|
|
2018-11-01 00:04:02 +00:00
|
|
|
notify_waiters(m_pid, status, 0);
|
2018-10-26 23:24:22 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (!scheduleNewProcess()) {
|
|
|
|
kprintf("Process::sys$exit: Failed to schedule a new process :(\n");
|
2018-10-22 09:43:55 +00:00
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
s_deadProcesses->append(this);
|
2018-10-22 09:43:55 +00:00
|
|
|
|
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
2018-11-02 13:06:48 +00:00
|
|
|
void Process::send_signal(int signal, Process* sender)
|
2018-10-31 00:06:57 +00:00
|
|
|
{
|
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
2018-11-02 13:06:48 +00:00
|
|
|
bool wasCurrent = current == sender;
|
2018-11-01 13:21:02 +00:00
|
|
|
set_state(Exiting);
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes->remove(this);
|
2018-11-01 00:04:02 +00:00
|
|
|
|
|
|
|
notify_waiters(m_pid, 0, signal);
|
|
|
|
|
2018-10-31 00:06:57 +00:00
|
|
|
if (wasCurrent) {
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Current process committing suicide!\n");
|
|
|
|
if (!scheduleNewProcess()) {
|
2018-11-02 13:06:48 +00:00
|
|
|
kprintf("Process::send_signal: Failed to schedule a new process :(\n");
|
2018-10-31 00:06:57 +00:00
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
}
|
2018-11-01 12:15:46 +00:00
|
|
|
s_deadProcesses->append(this);
|
2018-10-31 00:06:57 +00:00
|
|
|
if (wasCurrent)
|
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::processDidCrash(Process* crashedProcess)
|
2018-10-17 22:26:30 +00:00
|
|
|
{
|
2018-10-25 08:33:10 +00:00
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (crashedProcess->state() == Crashing) {
|
2018-10-29 23:12:08 +00:00
|
|
|
kprintf("Double crash :(\n");
|
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
2018-11-01 13:21:02 +00:00
|
|
|
crashedProcess->set_state(Crashing);
|
2018-11-01 12:15:46 +00:00
|
|
|
crashedProcess->dumpRegions();
|
2018-10-18 12:53:00 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes->remove(crashedProcess);
|
2018-10-17 22:26:30 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
notify_waiters(crashedProcess->m_pid, 0, SIGSEGV);
|
2018-11-01 00:04:02 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (!scheduleNewProcess()) {
|
|
|
|
kprintf("Process::processDidCrash: Failed to schedule a new process :(\n");
|
2018-10-17 22:26:30 +00:00
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
s_deadProcesses->append(crashedProcess);
|
2018-10-17 22:26:30 +00:00
|
|
|
|
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::doHouseKeeping()
|
2018-10-23 13:41:55 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
if (s_deadProcesses->isEmpty())
|
2018-10-25 09:15:17 +00:00
|
|
|
return;
|
2018-11-01 22:04:34 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
Process* next = nullptr;
|
|
|
|
for (auto* deadProcess = s_deadProcesses->head(); deadProcess; deadProcess = next) {
|
|
|
|
next = deadProcess->next();
|
|
|
|
delete deadProcess;
|
2018-10-23 13:41:55 +00:00
|
|
|
}
|
2018-11-01 12:15:46 +00:00
|
|
|
s_deadProcesses->clear();
|
2018-10-23 13:41:55 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
void yield()
|
|
|
|
{
|
|
|
|
if (!current) {
|
|
|
|
kprintf( "PANIC: yield() with !current" );
|
|
|
|
HANG;
|
|
|
|
}
|
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
//kprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
|
|
|
|
2018-10-24 09:07:53 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
if (!scheduleNewProcess())
|
2018-10-16 09:06:35 +00:00
|
|
|
return;
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
//kprintf("yield() jumping to new process: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
2018-10-17 21:49:32 +00:00
|
|
|
switchNow();
|
|
|
|
}
|
|
|
|
|
|
|
|
void switchNow()
|
|
|
|
{
|
2018-10-16 09:06:35 +00:00
|
|
|
Descriptor& descriptor = getGDTEntry(current->selector());
|
|
|
|
descriptor.type = 9;
|
|
|
|
flushGDT();
|
2018-10-19 09:28:43 +00:00
|
|
|
asm("sti\n"
|
2018-10-16 09:06:35 +00:00
|
|
|
"ljmp *(%%eax)\n"
|
|
|
|
::"a"(¤t->farPtr())
|
|
|
|
);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
bool scheduleNewProcess()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-25 08:33:10 +00:00
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
if (!current) {
|
2018-11-01 12:15:46 +00:00
|
|
|
// XXX: The first ever context_switch() goes to the idle process.
|
2018-10-16 09:01:38 +00:00
|
|
|
// This to setup a reliable place we can return to.
|
2018-11-01 12:15:46 +00:00
|
|
|
return contextSwitch(Process::kernelProcess());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
// Check and unblock processes whose wait conditions have been met.
|
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
if (process->state() == Process::BlockedSleep) {
|
|
|
|
if (process->wakeupTime() <= system.uptime) {
|
|
|
|
process->unblock();
|
2018-10-16 09:01:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-10-23 22:20:34 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (process->state() == Process::BlockedWait) {
|
|
|
|
if (!Process::fromPID(process->waitee())) {
|
|
|
|
process->unblock();
|
2018-10-23 22:20:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-10-25 11:07:59 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (process->state() == Process::BlockedRead) {
|
|
|
|
ASSERT(process->m_fdBlockedOnRead != -1);
|
2018-11-01 12:39:28 +00:00
|
|
|
if (process->m_file_descriptors[process->m_fdBlockedOnRead]->hasDataAvailableForRead()) {
|
2018-11-01 12:15:46 +00:00
|
|
|
process->unblock();
|
2018-10-25 11:07:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 20:54:11 +00:00
|
|
|
#ifdef SCHEDULER_DEBUG
|
|
|
|
dbgprintf("Scheduler choices:\n");
|
2018-11-01 12:15:46 +00:00
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
//if (process->state() == Process::BlockedWait || process->state() == Process::BlockedSleep)
|
2018-10-29 20:54:11 +00:00
|
|
|
// continue;
|
2018-11-03 00:49:40 +00:00
|
|
|
dbgprintf("%w %s(%u) @ %w:%x\n", process->state(), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
|
2018-10-25 10:45:29 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
auto* prevHead = s_processes->head();
|
2018-10-16 09:01:38 +00:00
|
|
|
for (;;) {
|
|
|
|
// Move head to tail.
|
2018-11-01 12:15:46 +00:00
|
|
|
s_processes->append(s_processes->removeHead());
|
|
|
|
auto* process = s_processes->head();
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (process->state() == Process::Runnable || process->state() == Process::Running) {
|
2018-10-29 20:54:11 +00:00
|
|
|
#ifdef SCHEDULER_DEBUG
|
2018-11-01 12:15:46 +00:00
|
|
|
dbgprintf("switch to %s(%u) (%p vs %p)\n", process->name().characters(), process->pid(), process, current);
|
2018-10-29 20:54:11 +00:00
|
|
|
#endif
|
2018-11-01 12:15:46 +00:00
|
|
|
return contextSwitch(process);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
if (process == prevHead) {
|
|
|
|
// Back at process_head, nothing wants to run.
|
2018-10-23 23:02:55 +00:00
|
|
|
kprintf("Nothing wants to run!\n");
|
|
|
|
kprintf("PID OWNER STATE NSCHED NAME\n");
|
2018-11-01 12:15:46 +00:00
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
2018-10-23 23:02:55 +00:00
|
|
|
kprintf("%w %w:%w %b %w %s\n",
|
2018-11-01 12:15:46 +00:00
|
|
|
process->pid(),
|
|
|
|
process->uid(),
|
|
|
|
process->gid(),
|
|
|
|
process->state(),
|
|
|
|
process->timesScheduled(),
|
|
|
|
process->name().characters());
|
2018-10-23 23:02:55 +00:00
|
|
|
}
|
2018-11-01 13:41:49 +00:00
|
|
|
kprintf("Switch to kernel process @ %w:%x\n", s_kernelProcess->tss().cs, s_kernelProcess->tss().eip);
|
2018-11-01 12:15:46 +00:00
|
|
|
return contextSwitch(Process::kernelProcess());
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
static bool contextSwitch(Process* t)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
t->setTicksLeft(5);
|
2018-10-25 10:45:29 +00:00
|
|
|
t->didSchedule();
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-10-16 09:06:35 +00:00
|
|
|
if (current == t)
|
|
|
|
return false;
|
|
|
|
|
2018-11-01 10:57:36 +00:00
|
|
|
#ifdef SCHEDULER_DEBUG
|
2018-10-22 09:15:16 +00:00
|
|
|
// Some sanity checking to force a crash earlier.
|
|
|
|
auto csRPL = t->tss().cs & 3;
|
|
|
|
auto ssRPL = t->tss().ss & 3;
|
2018-10-23 08:12:50 +00:00
|
|
|
|
|
|
|
if (csRPL != ssRPL) {
|
|
|
|
kprintf("Fuckup! Switching from %s(%u) to %s(%u) has RPL mismatch\n",
|
|
|
|
current->name().characters(), current->pid(),
|
|
|
|
t->name().characters(), t->pid()
|
|
|
|
);
|
|
|
|
kprintf("code: %w:%x\n", t->tss().cs, t->tss().eip);
|
|
|
|
kprintf(" stk: %w:%x\n", t->tss().ss, t->tss().esp);
|
|
|
|
ASSERT(csRPL == ssRPL);
|
|
|
|
}
|
2018-11-01 10:57:36 +00:00
|
|
|
#endif
|
2018-10-22 09:15:16 +00:00
|
|
|
|
2018-10-21 19:57:43 +00:00
|
|
|
if (current) {
|
2018-11-01 12:15:46 +00:00
|
|
|
// If the last process hasn't blocked (still marked as running),
|
2018-10-21 19:57:43 +00:00
|
|
|
// mark it as runnable for the next round.
|
2018-11-01 12:15:46 +00:00
|
|
|
if (current->state() == Process::Running)
|
2018-11-01 13:21:02 +00:00
|
|
|
current->set_state(Process::Runnable);
|
2018-10-21 19:57:43 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 09:01:38 +00:00
|
|
|
current = t;
|
2018-11-01 13:21:02 +00:00
|
|
|
t->set_state(Process::Running);
|
2018-10-16 09:01:38 +00:00
|
|
|
|
2018-11-01 10:57:36 +00:00
|
|
|
if (!t->selector()) {
|
2018-11-01 15:23:12 +00:00
|
|
|
t->setSelector(gdt_alloc_entry());
|
2018-11-01 10:57:36 +00:00
|
|
|
auto& descriptor = getGDTEntry(t->selector());
|
|
|
|
descriptor.setBase(&t->tss());
|
|
|
|
descriptor.setLimit(0xffff);
|
|
|
|
descriptor.dpl = 0;
|
|
|
|
descriptor.segment_present = 1;
|
|
|
|
descriptor.granularity = 1;
|
|
|
|
descriptor.zero = 0;
|
|
|
|
descriptor.operation_size = 1;
|
|
|
|
descriptor.descriptor_type = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& descriptor = getGDTEntry(t->selector());
|
|
|
|
descriptor.type = 11; // Busy TSS
|
2018-10-16 09:06:35 +00:00
|
|
|
flushGDT();
|
|
|
|
return true;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Process* Process::fromPID(pid_t pid)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-26 13:11:29 +00:00
|
|
|
ASSERT_INTERRUPTS_DISABLED();
|
2018-11-01 12:15:46 +00:00
|
|
|
for (auto* process = s_processes->head(); process; process = process->next()) {
|
|
|
|
if (process->pid() == pid)
|
|
|
|
return process;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
FileHandle* Process::fileHandleIfExists(int fd)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
if (fd < 0)
|
|
|
|
return nullptr;
|
2018-11-01 12:39:28 +00:00
|
|
|
if ((unsigned)fd < m_file_descriptors.size())
|
|
|
|
return m_file_descriptors[fd].ptr();
|
2018-10-16 09:01:38 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
ssize_t Process::sys$get_dir_entries(int fd, void* buffer, size_t size)
|
2018-10-24 10:43:52 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(buffer, size);
|
2018-10-24 10:43:52 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
|
|
|
if (!handle)
|
2018-10-30 21:03:02 +00:00
|
|
|
return -EBADF;
|
2018-10-24 10:43:52 +00:00
|
|
|
return handle->get_dir_entries((byte*)buffer, size);
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$lseek(int fd, off_t offset, int whence)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-16 09:01:38 +00:00
|
|
|
if (!handle)
|
2018-10-31 16:50:43 +00:00
|
|
|
return -EBADF;
|
|
|
|
return handle->seek(offset, whence);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$ttyname_r(int fd, char* buffer, size_t size)
|
2018-10-30 21:03:02 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(buffer, size);
|
2018-10-30 21:03:02 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
|
|
|
if (!handle)
|
|
|
|
return -EBADF;
|
|
|
|
if (!handle->isTTY())
|
|
|
|
return -ENOTTY;
|
|
|
|
auto ttyName = handle->tty()->ttyName();
|
|
|
|
if (size < ttyName.length() + 1)
|
|
|
|
return -ERANGE;
|
|
|
|
strcpy(buffer, ttyName.characters());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
ssize_t Process::sys$write(int fd, const void* data, size_t size)
|
2018-10-30 14:33:37 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_READ(data, size);
|
2018-10-30 14:33:37 +00:00
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$write: called(%d, %p, %u)\n", fd, data, size);
|
2018-10-30 14:33:37 +00:00
|
|
|
#endif
|
|
|
|
auto* handle = fileHandleIfExists(fd);
|
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$write: handle=%p\n", handle);
|
2018-10-30 14:33:37 +00:00
|
|
|
#endif
|
|
|
|
if (!handle)
|
|
|
|
return -EBADF;
|
|
|
|
auto nwritten = handle->write((const byte*)data, size);
|
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$write: nwritten=%u\n", nwritten);
|
2018-10-30 14:33:37 +00:00
|
|
|
#endif
|
|
|
|
return nwritten;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
ssize_t Process::sys$read(int fd, void* outbuf, size_t nread)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(outbuf, nread);
|
2018-10-23 08:12:50 +00:00
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread);
|
2018-10-23 08:12:50 +00:00
|
|
|
#endif
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-23 08:12:50 +00:00
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$read: handle=%p\n", handle);
|
2018-10-23 08:12:50 +00:00
|
|
|
#endif
|
2018-10-30 14:33:37 +00:00
|
|
|
if (!handle)
|
|
|
|
return -EBADF;
|
2018-10-25 11:07:59 +00:00
|
|
|
if (handle->isBlocking()) {
|
|
|
|
if (!handle->hasDataAvailableForRead()) {
|
|
|
|
m_fdBlockedOnRead = fd;
|
|
|
|
block(BlockedRead);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
}
|
2018-10-18 08:28:09 +00:00
|
|
|
nread = handle->read((byte*)outbuf, nread);
|
2018-10-23 08:12:50 +00:00
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$read: nread=%u\n", nread);
|
2018-10-23 08:12:50 +00:00
|
|
|
#endif
|
2018-10-16 09:01:38 +00:00
|
|
|
return nread;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$close(int fd)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-18 08:28:09 +00:00
|
|
|
auto* handle = fileHandleIfExists(fd);
|
2018-10-16 09:01:38 +00:00
|
|
|
if (!handle)
|
2018-10-30 21:03:02 +00:00
|
|
|
return -EBADF;
|
2018-11-01 13:00:28 +00:00
|
|
|
int rc = handle->close();
|
|
|
|
m_file_descriptors[fd] = nullptr;
|
|
|
|
return rc;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$lstat(const char* path, Unix::stat* statbuf)
|
2018-10-24 11:19:36 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(statbuf, sizeof(Unix::stat));
|
2018-10-28 13:25:51 +00:00
|
|
|
int error;
|
|
|
|
auto handle = VirtualFileSystem::the().open(move(path), error, O_NOFOLLOW_NOERROR, cwdInode());
|
2018-10-24 11:19:36 +00:00
|
|
|
if (!handle)
|
2018-10-28 13:25:51 +00:00
|
|
|
return error;
|
2018-10-26 22:29:31 +00:00
|
|
|
handle->stat(statbuf);
|
2018-10-24 11:19:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$stat(const char* path, Unix::stat* statbuf)
|
2018-10-31 09:14:56 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(statbuf, sizeof(Unix::stat));
|
2018-10-31 09:14:56 +00:00
|
|
|
int error;
|
|
|
|
auto handle = VirtualFileSystem::the().open(move(path), error, 0, cwdInode());
|
|
|
|
if (!handle)
|
|
|
|
return error;
|
|
|
|
handle->stat(statbuf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$readlink(const char* path, char* buffer, size_t size)
|
2018-10-28 13:11:51 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_READ(path, strlen(path));
|
|
|
|
VALIDATE_USER_WRITE(buffer, size);
|
2018-10-28 13:11:51 +00:00
|
|
|
|
2018-10-28 13:25:51 +00:00
|
|
|
int error;
|
|
|
|
auto handle = VirtualFileSystem::the().open(path, error, O_RDONLY | O_NOFOLLOW_NOERROR, cwdInode());
|
2018-10-28 13:11:51 +00:00
|
|
|
if (!handle)
|
2018-10-28 13:25:51 +00:00
|
|
|
return error;
|
2018-10-28 13:11:51 +00:00
|
|
|
|
|
|
|
if (!handle->metadata().isSymbolicLink())
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
auto contents = handle->readEntireFile();
|
|
|
|
if (!contents)
|
|
|
|
return -EIO; // FIXME: Get a more detailed error from VFS.
|
|
|
|
|
|
|
|
memcpy(buffer, contents.pointer(), min(size, contents.size()));
|
|
|
|
if (contents.size() + 1 < size)
|
|
|
|
buffer[contents.size()] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$chdir(const char* path)
|
2018-10-24 12:28:22 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_READ(path, strlen(path));
|
2018-10-28 13:25:51 +00:00
|
|
|
int error;
|
|
|
|
auto handle = VirtualFileSystem::the().open(path, error, 0, cwdInode());
|
2018-10-26 12:24:11 +00:00
|
|
|
if (!handle)
|
2018-10-28 13:25:51 +00:00
|
|
|
return error;
|
2018-10-26 12:24:11 +00:00
|
|
|
if (!handle->isDirectory())
|
|
|
|
return -ENOTDIR;
|
|
|
|
m_cwd = handle->vnode();
|
2018-10-24 12:28:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$getcwd(char* buffer, size_t size)
|
2018-10-26 12:24:11 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(buffer, size);
|
2018-10-29 23:06:31 +00:00
|
|
|
auto path = VirtualFileSystem::the().absolutePath(cwdInode());
|
|
|
|
if (path.isNull())
|
|
|
|
return -EINVAL;
|
|
|
|
if (size < path.length() + 1)
|
|
|
|
return -ERANGE;
|
|
|
|
strcpy(buffer, path.characters());
|
2018-10-26 12:24:11 +00:00
|
|
|
return -ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:39:28 +00:00
|
|
|
size_t Process::number_of_open_file_descriptors() const
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
for (auto& handle : m_file_descriptors) {
|
|
|
|
if (handle)
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$open(const char* path, int options)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-10-23 08:12:50 +00:00
|
|
|
#ifdef DEBUG_IO
|
2018-11-01 12:15:46 +00:00
|
|
|
kprintf("Process::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength);
|
2018-10-23 08:12:50 +00:00
|
|
|
#endif
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_READ(path, strlen(path));
|
2018-11-01 12:39:28 +00:00
|
|
|
if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
|
2018-10-26 12:30:13 +00:00
|
|
|
return -EMFILE;
|
2018-10-28 13:25:51 +00:00
|
|
|
int error;
|
2018-10-29 20:54:11 +00:00
|
|
|
auto handle = VirtualFileSystem::the().open(path, error, options, cwdInode());
|
2018-10-26 12:30:13 +00:00
|
|
|
if (!handle)
|
2018-10-28 13:25:51 +00:00
|
|
|
return error;
|
2018-10-28 13:11:51 +00:00
|
|
|
if (options & O_DIRECTORY && !handle->isDirectory())
|
|
|
|
return -ENOTDIR; // FIXME: This should be handled by VFS::open.
|
|
|
|
|
2018-11-01 13:00:28 +00:00
|
|
|
int fd = 0;
|
|
|
|
for (; fd < m_max_open_file_descriptors; ++fd) {
|
|
|
|
if (!m_file_descriptors[fd])
|
|
|
|
break;
|
|
|
|
}
|
2018-10-26 12:30:13 +00:00
|
|
|
handle->setFD(fd);
|
2018-11-01 13:00:28 +00:00
|
|
|
m_file_descriptors[fd] = move(handle);
|
2018-10-26 12:30:13 +00:00
|
|
|
return fd;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$uname(utsname* buf)
|
2018-10-26 12:56:21 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(buf, sizeof(utsname));
|
2018-10-26 12:56:21 +00:00
|
|
|
strcpy(buf->sysname, "Serenity");
|
|
|
|
strcpy(buf->release, "1.0-dev");
|
|
|
|
strcpy(buf->version, "FIXME");
|
|
|
|
strcpy(buf->machine, "i386");
|
|
|
|
strcpy(buf->nodename, getHostname().characters());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-02 13:06:48 +00:00
|
|
|
int Process::sys$kill(pid_t pid, int signal)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
if (pid == 0) {
|
|
|
|
// FIXME: Send to same-group processes.
|
|
|
|
ASSERT(pid != 0);
|
|
|
|
}
|
|
|
|
if (pid == -1) {
|
|
|
|
// FIXME: Send to all processes.
|
|
|
|
ASSERT(pid != -1);
|
|
|
|
}
|
2018-10-31 00:06:57 +00:00
|
|
|
ASSERT(pid != current->pid()); // FIXME: Support this scenario.
|
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
auto* peer = Process::fromPID(pid);
|
2018-10-31 00:06:57 +00:00
|
|
|
if (!peer)
|
|
|
|
return -ESRCH;
|
2018-11-02 13:06:48 +00:00
|
|
|
peer->send_signal(signal, this);
|
|
|
|
return 0;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$sleep(unsigned seconds)
|
2018-10-25 11:53:49 +00:00
|
|
|
{
|
|
|
|
if (!seconds)
|
|
|
|
return 0;
|
|
|
|
sleep(seconds * TICKS_PER_SECOND);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
int Process::sys$gettimeofday(timeval* tv)
|
2018-10-25 15:29:49 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(tv, sizeof(tv));
|
2018-10-25 15:29:49 +00:00
|
|
|
InterruptDisabler disabler;
|
|
|
|
auto now = RTC::now();
|
|
|
|
tv->tv_sec = now;
|
|
|
|
tv->tv_usec = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
uid_t Process::sys$getuid()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
return m_uid;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
gid_t Process::sys$getgid()
|
2018-10-22 11:55:11 +00:00
|
|
|
{
|
|
|
|
return m_gid;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
pid_t Process::sys$getpid()
|
2018-10-22 11:55:11 +00:00
|
|
|
{
|
|
|
|
return m_pid;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
2018-10-23 22:20:34 +00:00
|
|
|
{
|
2018-10-26 23:24:22 +00:00
|
|
|
if (wstatus)
|
2018-11-01 11:45:51 +00:00
|
|
|
VALIDATE_USER_WRITE(wstatus, sizeof(int));
|
2018-10-26 23:24:22 +00:00
|
|
|
|
2018-10-25 08:33:10 +00:00
|
|
|
InterruptDisabler disabler;
|
2018-11-01 12:15:46 +00:00
|
|
|
if (!Process::fromPID(waitee))
|
2018-10-23 22:20:34 +00:00
|
|
|
return -1;
|
|
|
|
m_waitee = waitee;
|
2018-10-26 23:24:22 +00:00
|
|
|
m_waiteeStatus = 0;
|
2018-10-23 22:20:34 +00:00
|
|
|
block(BlockedWait);
|
|
|
|
yield();
|
2018-10-26 23:24:22 +00:00
|
|
|
if (wstatus)
|
|
|
|
*wstatus = m_waiteeStatus;
|
2018-10-23 22:20:34 +00:00
|
|
|
return m_waitee;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::unblock()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
ASSERT(m_state != Process::Runnable && m_state != Process::Running);
|
2018-10-16 09:01:38 +00:00
|
|
|
system.nblocked--;
|
2018-11-01 12:15:46 +00:00
|
|
|
m_state = Process::Runnable;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void Process::block(Process::State state)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
ASSERT(current->state() == Process::Running);
|
2018-10-16 09:01:38 +00:00
|
|
|
system.nblocked++;
|
2018-11-01 13:21:02 +00:00
|
|
|
current->set_state(state);
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
void block(Process::State state)
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
|
|
|
current->block(state);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
void sleep(DWORD ticks)
|
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
ASSERT(current->state() == Process::Running);
|
2018-10-16 09:01:38 +00:00
|
|
|
current->setWakeupTime(system.uptime + ticks);
|
2018-11-01 12:15:46 +00:00
|
|
|
current->block(Process::BlockedSleep);
|
2018-10-16 09:01:38 +00:00
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
Process* Process::kernelProcess()
|
2018-10-16 09:01:38 +00:00
|
|
|
{
|
2018-11-01 12:15:46 +00:00
|
|
|
ASSERT(s_kernelProcess);
|
|
|
|
return s_kernelProcess;
|
2018-10-16 09:01:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-03 10:36:45 +00:00
|
|
|
Region::Region(LinearAddress a, size_t s, RetainPtr<Zone>&& z, String&& n, bool r, bool w)
|
2018-10-18 12:53:00 +00:00
|
|
|
: linearAddress(a)
|
|
|
|
, size(s)
|
|
|
|
, zone(move(z))
|
|
|
|
, name(move(n))
|
2018-11-03 10:36:45 +00:00
|
|
|
, is_readable(r)
|
|
|
|
, is_writable(w)
|
2018-10-18 12:53:00 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:21:02 +00:00
|
|
|
Region::~Region()
|
2018-10-18 12:53:00 +00:00
|
|
|
{
|
|
|
|
}
|
2018-10-26 22:14:24 +00:00
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
bool Process::isValidAddressForKernel(LinearAddress laddr) const
|
2018-10-26 22:14:24 +00:00
|
|
|
{
|
2018-11-01 11:45:51 +00:00
|
|
|
// We check extra carefully here since the first 4MB of the address space is identity-mapped.
|
|
|
|
// This code allows access outside of the known used address ranges to get caught.
|
|
|
|
|
2018-10-26 22:14:24 +00:00
|
|
|
InterruptDisabler disabler;
|
|
|
|
if (laddr.get() >= ksyms().first().address && laddr.get() <= ksyms().last().address)
|
|
|
|
return true;
|
|
|
|
if (is_kmalloc_address((void*)laddr.get()))
|
|
|
|
return true;
|
2018-11-01 11:45:51 +00:00
|
|
|
return validate_user_read(laddr);
|
2018-10-26 22:14:24 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
bool Process::validate_user_read(LinearAddress laddr) const
|
2018-10-26 22:14:24 +00:00
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
2018-11-01 11:45:51 +00:00
|
|
|
return MM.validate_user_read(*this, laddr);
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:15:46 +00:00
|
|
|
bool Process::validate_user_write(LinearAddress laddr) const
|
2018-11-01 11:45:51 +00:00
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
return MM.validate_user_write(*this, laddr);
|
2018-10-26 22:14:24 +00:00
|
|
|
}
|
2018-11-02 11:56:51 +00:00
|
|
|
|
|
|
|
pid_t Process::sys$getsid(pid_t pid)
|
|
|
|
{
|
|
|
|
if (pid == 0)
|
|
|
|
return m_sid;
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
auto* process = Process::fromPID(pid);
|
|
|
|
if (!process)
|
|
|
|
return -ESRCH;
|
|
|
|
if (m_sid != process->m_sid)
|
|
|
|
return -EPERM;
|
|
|
|
return process->m_sid;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t Process::sys$setsid()
|
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
bool found_process_with_same_pgid_as_my_pid = false;
|
|
|
|
forEachProcess([&] (auto& process) {
|
|
|
|
if (process.pgid() == pid()) {
|
|
|
|
found_process_with_same_pgid_as_my_pid = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (found_process_with_same_pgid_as_my_pid)
|
|
|
|
return -EPERM;
|
|
|
|
m_sid = m_pid;
|
|
|
|
m_pgid = m_pid;
|
|
|
|
return m_sid;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t Process::sys$getpgid(pid_t pid)
|
|
|
|
{
|
|
|
|
if (pid == 0)
|
|
|
|
return m_pgid;
|
|
|
|
InterruptDisabler disabler; // FIXME: Use a ProcessHandle
|
|
|
|
auto* process = Process::fromPID(pid);
|
|
|
|
if (!process)
|
|
|
|
return -ESRCH;
|
|
|
|
return process->m_pgid;
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t Process::sys$getpgrp()
|
|
|
|
{
|
|
|
|
return m_pgid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pid_t get_sid_from_pgid(pid_t pgid)
|
|
|
|
{
|
|
|
|
InterruptDisabler disabler;
|
|
|
|
auto* group_leader = Process::fromPID(pgid);
|
|
|
|
if (!group_leader)
|
|
|
|
return -1;
|
|
|
|
return group_leader->sid();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
|
|
|
{
|
|
|
|
InterruptDisabler disabler; // FIXME: Use a ProcessHandle
|
|
|
|
pid_t pid = specified_pid ? specified_pid : m_pid;
|
|
|
|
if (specified_pgid < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
auto* process = Process::fromPID(pid);
|
|
|
|
if (!process)
|
|
|
|
return -ESRCH;
|
|
|
|
pid_t new_pgid = specified_pgid ? specified_pgid : process->m_pid;
|
|
|
|
pid_t current_sid = get_sid_from_pgid(process->m_pgid);
|
|
|
|
pid_t new_sid = get_sid_from_pgid(new_pgid);
|
|
|
|
if (current_sid != new_sid) {
|
|
|
|
// Can't move a process between sessions.
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
// FIXME: There are more EPERM conditions to check for here..
|
|
|
|
process->m_pgid = new_pgid;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-02 12:14:25 +00:00
|
|
|
|
|
|
|
pid_t Process::sys$tcgetpgrp(int fd)
|
|
|
|
{
|
|
|
|
auto* handle = fileHandleIfExists(fd);
|
|
|
|
if (!handle)
|
|
|
|
return -EBADF;
|
|
|
|
if (!handle->isTTY())
|
|
|
|
return -ENOTTY;
|
|
|
|
auto& tty = *handle->tty();
|
|
|
|
if (&tty != m_tty)
|
|
|
|
return -ENOTTY;
|
|
|
|
return tty.pgid();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Process::sys$tcsetpgrp(int fd, pid_t pgid)
|
|
|
|
{
|
|
|
|
if (pgid < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (get_sid_from_pgid(pgid) != m_sid)
|
|
|
|
return -EINVAL;
|
|
|
|
auto* handle = fileHandleIfExists(fd);
|
|
|
|
if (!handle)
|
|
|
|
return -EBADF;
|
|
|
|
if (!handle->isTTY())
|
|
|
|
return -ENOTTY;
|
|
|
|
auto& tty = *handle->tty();
|
|
|
|
if (&tty != m_tty)
|
|
|
|
return -ENOTTY;
|
|
|
|
tty.set_pgid(pgid);
|
|
|
|
return 0;
|
|
|
|
}
|