mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 20:07:34 +00:00
Implemented sys$execve().
It's really crufty, but it basically works!
This commit is contained in:
parent
b59ce22fc5
commit
202bdb553c
9 changed files with 215 additions and 21 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -48,6 +48,7 @@ enum Function {
|
|||
PosixTcsetpgrp = 0x2016,
|
||||
PosixTcgetpgrp = 0x2017,
|
||||
PosixFork = 0x2018,
|
||||
PosixExecve = 0x2019,
|
||||
};
|
||||
|
||||
void initialize();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue