mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-12 03:30:39 +01:00
[rpcsx-os] fork: implement vm and vfs fork
stub metadbg device implement notification device implement sys_pipe
This commit is contained in:
parent
39092c7f16
commit
525ef02e8a
|
|
@ -6,6 +6,7 @@ add_library(obj.orbis-utils-ipc OBJECT
|
|||
)
|
||||
add_library(obj.orbis-kernel OBJECT
|
||||
src/module.cpp
|
||||
src/pipe.cpp
|
||||
src/sysvec.cpp
|
||||
src/evf.cpp
|
||||
src/KernelContext.cpp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "evf.hpp"
|
||||
#include "ipmi.hpp"
|
||||
#include "orbis/utils/IdMap.hpp"
|
||||
#include "osem.hpp"
|
||||
#include "utils/LinkedNode.hpp"
|
||||
#include "utils/SharedCV.hpp"
|
||||
|
|
@ -54,6 +55,15 @@ public:
|
|||
void deleteProcess(Process *proc);
|
||||
Process *findProcessById(pid_t pid) const;
|
||||
|
||||
utils::LinkedNode<Process> *getProcessList() {
|
||||
return m_processes;
|
||||
}
|
||||
|
||||
long allocatePid() {
|
||||
std::lock_guard lock(m_thread_id_mtx);
|
||||
return m_thread_id_map.emplace(0).first;
|
||||
}
|
||||
|
||||
long getTscFreq();
|
||||
|
||||
void *kalloc(std::size_t size,
|
||||
|
|
@ -161,6 +171,8 @@ private:
|
|||
|
||||
std::atomic<long> m_tsc_freq{0};
|
||||
|
||||
shared_mutex m_thread_id_mtx;
|
||||
OwningIdMap<char, long, 256, 0> m_thread_id_map;
|
||||
mutable shared_mutex m_proc_mtx;
|
||||
utils::LinkedNode<Process> *m_processes = nullptr;
|
||||
|
||||
|
|
|
|||
13
orbis-kernel/include/orbis/pipe.hpp
Normal file
13
orbis-kernel/include/orbis/pipe.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "KernelAllocator.hpp"
|
||||
#include "file.hpp"
|
||||
#include "utils/Rc.hpp"
|
||||
|
||||
namespace orbis {
|
||||
struct Pipe final : File {
|
||||
kvector<std::byte> data;
|
||||
};
|
||||
|
||||
Ref<Pipe> createPipe();
|
||||
} // namespace orbis
|
||||
|
|
@ -70,6 +70,7 @@ struct ProcessOps {
|
|||
SysResult (*thr_wake)(Thread *thread, slong id);
|
||||
SysResult (*thr_set_name)(Thread *thread, slong id, ptr<const char> name);
|
||||
|
||||
SysResult (*fork)(Thread *thread, slong status);
|
||||
SysResult (*exit)(Thread *thread, sint status);
|
||||
|
||||
SysResult (*processNeeded)(Thread *thread);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
namespace orbis {
|
||||
inline namespace utils {
|
||||
// IPC-ready lightweight condition variable
|
||||
class shared_cv {
|
||||
class shared_cv final {
|
||||
enum : unsigned {
|
||||
c_waiter_mask = 0xffff,
|
||||
c_signal_mask = 0x7fff0000,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ KernelContext &g_context = *[]() -> KernelContext * {
|
|||
auto ptr = mmap(reinterpret_cast<void *>(0x200'0000'0000), 0x1'0000'0000,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
if (!ptr)
|
||||
if (ptr == MAP_FAILED)
|
||||
std::abort();
|
||||
|
||||
return new (ptr) KernelContext;
|
||||
|
|
@ -163,6 +163,9 @@ void KernelContext::kfree(void *ptr, std::size_t size) {
|
|||
~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);
|
||||
if (!size)
|
||||
std::abort();
|
||||
if ((uintptr_t)ptr == 0x2000001a2b0) {
|
||||
std::fprintf(stderr, "free %p-%p (%zu)\n", ptr, (char *)ptr + size, size);
|
||||
}
|
||||
std::memset(ptr, 0xcc, size);
|
||||
|
||||
pthread_mutex_lock(&m_heap_mtx);
|
||||
|
|
|
|||
61
orbis-kernel/src/pipe.cpp
Normal file
61
orbis-kernel/src/pipe.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include "pipe.hpp"
|
||||
#include "error/ErrorCode.hpp"
|
||||
#include "file.hpp"
|
||||
#include "uio.hpp"
|
||||
#include <span>
|
||||
#include <thread>
|
||||
|
||||
static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *thread) {
|
||||
auto pipe = static_cast<orbis::Pipe *>(file);
|
||||
while (true) {
|
||||
if (pipe->data.empty()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
std::lock_guard lock(pipe->mtx);
|
||||
|
||||
if (pipe->data.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
|
||||
auto size = std::min<std::size_t>(pipe->data.size(), vec.len);
|
||||
uio->offset += size;
|
||||
std::memcpy(vec.base, pipe->data.data(), size);
|
||||
|
||||
if (pipe->data.size() == size) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::memmove(pipe->data.data(), pipe->data.data() + size,
|
||||
pipe->data.size() - size);
|
||||
pipe->data.resize(pipe->data.size() - size);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *thread) {
|
||||
auto pipe = static_cast<orbis::Pipe *>(file);
|
||||
std::lock_guard lock(pipe->mtx);
|
||||
|
||||
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
|
||||
auto offset = pipe->data.size();
|
||||
pipe->data.resize(offset + vec.len);
|
||||
std::memcpy(pipe->data.data(), vec.base, vec.len);
|
||||
}
|
||||
uio->resid = 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static orbis::FileOps pipe_ops = {.read = pipe_read, .write = pipe_write};
|
||||
|
||||
orbis::Ref<orbis::Pipe> orbis::createPipe() {
|
||||
auto result = knew<Pipe>();
|
||||
result->ops = &pipe_ops;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#include "KernelContext.hpp"
|
||||
#include "sys/sysproto.hpp"
|
||||
#include "utils/Logs.hpp"
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
|
||||
|
|
@ -11,42 +10,8 @@ orbis::SysResult orbis::sys_pdfork(Thread *thread, ptr<sint> fdp, sint flags) {
|
|||
|
||||
orbis::SysResult orbis::sys_vfork(Thread *thread) { return ErrorCode::NOSYS; }
|
||||
orbis::SysResult orbis::sys_rfork(Thread *thread, sint flags) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__, flags);
|
||||
|
||||
int hostPid = ::fork();
|
||||
if (hostPid) {
|
||||
thread->retval[0] = 10001;
|
||||
thread->retval[1] = 0;
|
||||
} else {
|
||||
auto process = g_context.createProcess(10001);
|
||||
std::lock_guard lock(thread->tproc->fileDescriptors.mutex);
|
||||
process->sysent = thread->tproc->sysent;
|
||||
process->onSysEnter = thread->tproc->onSysEnter;
|
||||
process->onSysExit = thread->tproc->onSysExit;
|
||||
process->ops = thread->tproc->ops;
|
||||
process->isSystem = thread->tproc->isSystem;
|
||||
for (auto [id, mod] : thread->tproc->modulesMap) {
|
||||
if (!process->modulesMap.insert(id, mod)) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [id, mod] : thread->tproc->fileDescriptors) {
|
||||
if (!process->fileDescriptors.insert(id, mod)) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
auto [baseId, newThread] = process->threadsMap.emplace();
|
||||
newThread->tproc = process;
|
||||
newThread->tid = process->pid + baseId;
|
||||
newThread->state = orbis::ThreadState::RUNNING;
|
||||
newThread->context = thread->context;
|
||||
newThread->fsBase = thread->fsBase;
|
||||
|
||||
orbis::g_currentThread = newThread;
|
||||
newThread->retval[0] = 0;
|
||||
newThread->retval[1] = 1;
|
||||
if (auto fork = thread->tproc->ops->fork) {
|
||||
return fork(thread, flags);
|
||||
}
|
||||
return {};
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
#include <pipe.hpp>
|
||||
|
||||
orbis::SysResult orbis::sys_pipe(Thread *thread) { return ErrorCode::NOSYS; }
|
||||
orbis::SysResult orbis::sys_pipe(Thread *thread) {
|
||||
auto pipe = createPipe();
|
||||
thread->retval[0] = thread->tproc->fileDescriptors.insert(pipe);
|
||||
thread->retval[1] = thread->tproc->fileDescriptors.insert(pipe);
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ add_executable(rpcsx-os
|
|||
iodev/hmd_snsr.cpp
|
||||
iodev/icc_configuration.cpp
|
||||
iodev/mbus.cpp
|
||||
iodev/metadbg.cpp
|
||||
iodev/notification.cpp
|
||||
iodev/npdrm.cpp
|
||||
iodev/null.cpp
|
||||
|
|
|
|||
|
|
@ -28,3 +28,4 @@ IoDevice *createMBusCharacterDevice();
|
|||
IoDevice *createBtCharacterDevice();
|
||||
IoDevice *createXptCharacterDevice();
|
||||
IoDevice *createCdCharacterDevice();
|
||||
IoDevice *createMetaDbgCharacterDevice();
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@ static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request,
|
|||
}
|
||||
}
|
||||
|
||||
thread->where();
|
||||
ORBIS_LOG_FATAL("Unhandled dmem ioctl", device->index, request);
|
||||
thread->where();
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
41
rpcsx-os/iodev/metadbg.cpp
Normal file
41
rpcsx-os/iodev/metadbg.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <bits/chrono.h>
|
||||
#include <thread>
|
||||
|
||||
struct MetaDbgFile : orbis::File {};
|
||||
|
||||
static orbis::ErrorCode metadbg_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
|
||||
ORBIS_LOG_FATAL("Unhandled metadbg ioctl", request);
|
||||
return {};
|
||||
}
|
||||
static orbis::ErrorCode metadbg_read(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::days(1));
|
||||
return {};
|
||||
}
|
||||
|
||||
static const orbis::FileOps fileOps = {
|
||||
.ioctl = metadbg_ioctl,
|
||||
.read = metadbg_read,
|
||||
};
|
||||
|
||||
struct MetaDbgDevice : IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode,
|
||||
orbis::Thread *thread) override {
|
||||
auto newFile = orbis::knew<MetaDbgFile>();
|
||||
newFile->ops = &fileOps;
|
||||
newFile->device = this;
|
||||
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
IoDevice *createMetaDbgCharacterDevice() { return orbis::knew<MetaDbgDevice>(); }
|
||||
|
|
@ -1,13 +1,19 @@
|
|||
#include "io-device.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/file.hpp"
|
||||
#include "orbis/uio.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "orbis/utils/SharedMutex.hpp"
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
struct NotificationFile : orbis::File {};
|
||||
struct NotificationDevice : IoDevice {
|
||||
int index;
|
||||
orbis::shared_mutex mutex;
|
||||
orbis::kvector<std::byte> data;
|
||||
|
||||
NotificationDevice(int index) : index(index) {}
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
|
|
@ -23,14 +29,57 @@ static orbis::ErrorCode notification_ioctl(orbis::File *file, std::uint64_t requ
|
|||
}
|
||||
|
||||
static orbis::ErrorCode notification_read(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) {
|
||||
ORBIS_LOG_FATAL("Unhandled notification_read");
|
||||
std::this_thread::sleep_for(std::chrono::hours(120));
|
||||
auto dev = dynamic_cast<NotificationDevice *>(file->device.get());
|
||||
ORBIS_LOG_FATAL(__FUNCTION__, dev->index);
|
||||
|
||||
while (true) {
|
||||
if (dev->data.empty()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
std::lock_guard lock(dev->mutex);
|
||||
|
||||
if (dev->data.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
|
||||
auto size = std::min<std::size_t>(dev->data.size(), vec.len);
|
||||
uio->offset += size;
|
||||
std::memcpy(vec.base, dev->data.data(), size);
|
||||
|
||||
if (dev->data.size() == size) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::memmove(dev->data.data(), dev->data.data() + size, dev->data.size() - size);
|
||||
dev->data.resize(dev->data.size() - size);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static orbis::ErrorCode notification_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) {
|
||||
auto dev = dynamic_cast<NotificationDevice *>(file->device.get());
|
||||
ORBIS_LOG_FATAL(__FUNCTION__, dev->index);
|
||||
|
||||
std::lock_guard lock(dev->mutex);
|
||||
|
||||
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
|
||||
auto offset = dev->data.size();
|
||||
dev->data.resize(offset + vec.len);
|
||||
std::memcpy(dev->data.data(), vec.base, vec.len);
|
||||
}
|
||||
uio->resid = 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
static const orbis::FileOps fileOps = {
|
||||
.ioctl = notification_ioctl,
|
||||
.read = notification_read,
|
||||
.write = notification_write,
|
||||
};
|
||||
|
||||
orbis::ErrorCode NotificationDevice::open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ struct UrandomDevice : public IoDevice {
|
|||
};
|
||||
struct UrandomFile : public orbis::File {};
|
||||
|
||||
static orbis::ErrorCode zero_read(orbis::File *file, orbis::Uio *uio,
|
||||
static orbis::ErrorCode urandom_read(orbis::File *file, orbis::Uio *uio,
|
||||
orbis::Thread *) {
|
||||
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
|
||||
std::memset(entry.base, 0, entry.len);
|
||||
|
|
@ -22,7 +22,7 @@ static orbis::ErrorCode zero_read(orbis::File *file, orbis::Uio *uio,
|
|||
}
|
||||
|
||||
static const orbis::FileOps ops = {
|
||||
.read = zero_read,
|
||||
.read = urandom_read,
|
||||
};
|
||||
|
||||
orbis::ErrorCode UrandomDevice::open(orbis::Ref<orbis::File> *file,
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ static int ps4Exec(orbis::Thread *mainThread,
|
|||
rx::vfs::addDevice("ajm", createAjmCharacterDevice());
|
||||
rx::vfs::addDevice("urandom", createUrandomCharacterDevice());
|
||||
rx::vfs::addDevice("mbus", createMBusCharacterDevice());
|
||||
rx::vfs::addDevice("metadbg", createMetaDbgCharacterDevice());
|
||||
rx::vfs::addDevice("bt", createBtCharacterDevice());
|
||||
rx::vfs::addDevice("xpt0", createXptCharacterDevice());
|
||||
rx::vfs::addDevice("cd0", createXptCharacterDevice());
|
||||
|
|
@ -645,8 +646,9 @@ int main(int argc, const char *argv[]) {
|
|||
}
|
||||
|
||||
// rx::vm::printHostStats();
|
||||
auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10);
|
||||
pthread_setname_np(pthread_self(), "10.MAINTHREAD");
|
||||
orbis::g_context.allocatePid();
|
||||
auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 11);
|
||||
pthread_setname_np(pthread_self(), "11.MAINTHREAD");
|
||||
|
||||
std::thread{[] {
|
||||
pthread_setname_np(pthread_self(), "Bridge");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "orbis/umtx.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include "orbis/utils/Rc.hpp"
|
||||
#include "orbis/utils/SharedCV.hpp"
|
||||
#include "orbis/utils/SharedMutex.hpp"
|
||||
#include "orbis/vm.hpp"
|
||||
#include "thread.hpp"
|
||||
#include "vfs.hpp"
|
||||
|
|
@ -19,15 +21,19 @@
|
|||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <linux/prctl.h>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <sys/prctl.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace orbis;
|
||||
|
||||
extern "C" void __register_frame(const void *);
|
||||
void setupSigHandlers();
|
||||
|
||||
namespace {
|
||||
static std::pair<SysResult, Ref<Module>>
|
||||
|
|
@ -617,6 +623,95 @@ SysResult processNeeded(Thread *thread) {
|
|||
return {};
|
||||
}
|
||||
|
||||
SysResult fork(Thread *thread, slong flags) {
|
||||
ORBIS_LOG_TODO(__FUNCTION__, flags);
|
||||
|
||||
auto childPid = g_context.allocatePid() * 10000 + 1;
|
||||
auto mtx = knew<shared_mutex>();
|
||||
auto cv = knew<shared_cv>();
|
||||
|
||||
int hostPid = ::fork();
|
||||
|
||||
if (hostPid) {
|
||||
mtx->lock();
|
||||
cv->wait(*mtx);
|
||||
|
||||
kdelete(cv);
|
||||
kdelete(mtx);
|
||||
|
||||
thread->retval[0] = childPid;
|
||||
thread->retval[1] = 0;
|
||||
return{};
|
||||
}
|
||||
|
||||
auto process = g_context.createProcess(childPid);
|
||||
process->sysent = thread->tproc->sysent;
|
||||
process->onSysEnter = thread->tproc->onSysEnter;
|
||||
process->onSysExit = thread->tproc->onSysExit;
|
||||
process->ops = thread->tproc->ops;
|
||||
process->isSystem = thread->tproc->isSystem;
|
||||
process->parentProcess = thread->tproc;
|
||||
for (auto [id, mod] : thread->tproc->modulesMap) {
|
||||
if (!process->modulesMap.insert(id, mod)) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (false) {
|
||||
std::lock_guard lock(thread->tproc->fileDescriptors.mutex);
|
||||
for (auto [id, mod] : thread->tproc->fileDescriptors) {
|
||||
if (!process->fileDescriptors.insert(id, mod)) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rx::vm::fork(thread->tproc->pid);
|
||||
rx::vfs::fork();
|
||||
|
||||
cv->notify_one(*mtx);
|
||||
|
||||
auto [baseId, newThread] = process->threadsMap.emplace();
|
||||
newThread->tproc = process;
|
||||
newThread->tid = process->pid + baseId;
|
||||
newThread->state = orbis::ThreadState::RUNNING;
|
||||
newThread->context = thread->context;
|
||||
newThread->fsBase = thread->fsBase;
|
||||
|
||||
orbis::g_currentThread = newThread;
|
||||
newThread->retval[0] = 0;
|
||||
newThread->retval[1] = 1;
|
||||
|
||||
thread = orbis::g_currentThread;
|
||||
|
||||
setupSigHandlers();
|
||||
rx::thread::initialize();
|
||||
|
||||
if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON,
|
||||
(void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) {
|
||||
perror("prctl failed\n");
|
||||
std::exit(-1);
|
||||
}
|
||||
|
||||
auto ttyFd =
|
||||
::open(("tty-" + std::to_string(thread->tproc->pid) + ".txt").c_str(),
|
||||
O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
||||
auto logFd =
|
||||
::open(("log-" + std::to_string(thread->tproc->pid) + ".txt").c_str(),
|
||||
O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
||||
|
||||
dup2(logFd, 1);
|
||||
dup2(logFd, 2);
|
||||
|
||||
auto tty = createFdWrapDevice(ttyFd);
|
||||
|
||||
rx::vfs::addDevice("stdout", tty);
|
||||
rx::vfs::addDevice("stderr", tty);
|
||||
rx::vfs::addDevice("deci_stdout", tty);
|
||||
rx::vfs::addDevice("deci_stderr", tty);
|
||||
return{};
|
||||
}
|
||||
|
||||
SysResult registerEhFrames(Thread *thread) {
|
||||
for (auto [id, module] : thread->tproc->modulesMap) {
|
||||
if (module->ehFrame != nullptr) {
|
||||
|
|
@ -670,6 +765,7 @@ ProcessOps rx::procOpsTable = {
|
|||
.thr_suspend = thr_suspend,
|
||||
.thr_wake = thr_wake,
|
||||
.thr_set_name = thr_set_name,
|
||||
.fork = fork,
|
||||
.exit = exit,
|
||||
.processNeeded = processNeeded,
|
||||
.registerEhFrames = registerEhFrames,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
#include "thread.hpp"
|
||||
#include "backtrace.hpp"
|
||||
#include "orbis/sys/sysentry.hpp"
|
||||
#include "orbis/thread/Process.hpp"
|
||||
#include "orbis/thread/Thread.hpp"
|
||||
#include <asm/prctl.h>
|
||||
#include <csignal>
|
||||
#include <immintrin.h>
|
||||
#include <link.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <string>
|
||||
#include <sys/prctl.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -33,8 +32,6 @@ static auto setContext = [] {
|
|||
return setContextStorage.getCode<void (*)(const mcontext_t &)>();
|
||||
}();
|
||||
|
||||
void setupSigHandlers();
|
||||
|
||||
static __attribute__((no_stack_protector)) void
|
||||
handleSigSys(int sig, siginfo_t *info, void *ucontext) {
|
||||
if (auto hostFs = _readgsbase_u64()) {
|
||||
|
|
@ -46,19 +43,7 @@ handleSigSys(int sig, siginfo_t *info, void *ucontext) {
|
|||
auto thread = orbis::g_currentThread;
|
||||
auto prevContext = std::exchange(thread->context, ucontext);
|
||||
orbis::syscall_entry(thread);
|
||||
if (thread != orbis::g_currentThread) {
|
||||
thread = orbis::g_currentThread;
|
||||
|
||||
setupSigHandlers();
|
||||
rx::thread::initialize();
|
||||
|
||||
if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON,
|
||||
(void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) {
|
||||
perror("prctl failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
thread = orbis::g_currentThread;
|
||||
thread->context = prevContext;
|
||||
_writefsbase_u64(thread->fsBase);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
static std::map<std::string, orbis::Ref<IoDevice>, std::greater<>> sMountsMap;
|
||||
|
||||
struct DevFs : IoDevice {
|
||||
std::map<std::string, orbis::Ref<IoDevice>> devices;
|
||||
|
||||
|
|
@ -25,7 +23,6 @@ struct DevFs : IoDevice {
|
|||
return orbis::ErrorCode::NOENT;
|
||||
}
|
||||
};
|
||||
static orbis::Ref<DevFs> sDevFs;
|
||||
|
||||
struct ProcFs : IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
|
|
@ -37,19 +34,43 @@ struct ProcFs : IoDevice {
|
|||
}
|
||||
};
|
||||
|
||||
static orbis::shared_mutex gMountMtx;
|
||||
static std::map<std::string, orbis::Ref<IoDevice>, std::greater<>> gMountsMap;
|
||||
static orbis::Ref<DevFs> gDevFs;
|
||||
|
||||
void rx::vfs::fork() {
|
||||
std::lock_guard lock(gMountMtx);
|
||||
|
||||
// NOTE: do not decrease reference counter, it managed by parent process
|
||||
auto parentDevFs = gDevFs.release();
|
||||
|
||||
for (auto &mount : gMountsMap) {
|
||||
mount.second->incRef(); // increase reference for new process
|
||||
}
|
||||
|
||||
gDevFs = orbis::knew<DevFs>();
|
||||
gMountsMap.emplace("/dev/", gDevFs);
|
||||
gMountsMap.emplace("/proc/", orbis::knew<ProcFs>());
|
||||
|
||||
for (auto &fs : parentDevFs->devices) {
|
||||
gDevFs->devices[fs.first] = fs.second;
|
||||
}
|
||||
}
|
||||
|
||||
void rx::vfs::initialize() {
|
||||
sDevFs = orbis::knew<DevFs>();
|
||||
sMountsMap.emplace("/dev/", sDevFs);
|
||||
sMountsMap.emplace("/proc/", orbis::knew<ProcFs>());
|
||||
gDevFs = orbis::knew<DevFs>();
|
||||
gMountsMap.emplace("/dev/", gDevFs);
|
||||
gMountsMap.emplace("/proc/", orbis::knew<ProcFs>());
|
||||
}
|
||||
|
||||
void rx::vfs::deinitialize() {
|
||||
sDevFs = nullptr;
|
||||
sMountsMap.clear();
|
||||
gDevFs = nullptr;
|
||||
gMountsMap.clear();
|
||||
}
|
||||
|
||||
void rx::vfs::addDevice(std::string name, IoDevice *device) {
|
||||
sDevFs->devices[std::move(name)] = device;
|
||||
std::lock_guard lock(gMountMtx);
|
||||
gDevFs->devices[std::move(name)] = device;
|
||||
}
|
||||
|
||||
static std::pair<orbis::Ref<IoDevice>, std::string>
|
||||
|
|
@ -59,7 +80,9 @@ get(const std::filesystem::path &guestPath) {
|
|||
orbis::Ref<IoDevice> device;
|
||||
std::string_view prefix;
|
||||
|
||||
for (auto &mount : sMountsMap) {
|
||||
std::lock_guard lock(gMountMtx);
|
||||
|
||||
for (auto &mount : gMountsMap) {
|
||||
if (!path.starts_with(mount.first)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -79,7 +102,9 @@ orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath,
|
|||
mp += "/";
|
||||
}
|
||||
|
||||
auto [it, inserted] = sMountsMap.emplace(std::move(mp), dev);
|
||||
std::lock_guard lock(gMountMtx);
|
||||
|
||||
auto [it, inserted] = gMountsMap.emplace(std::move(mp), dev);
|
||||
|
||||
if (!inserted) {
|
||||
return orbis::ErrorCode::EXIST;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
struct IoDevice;
|
||||
|
||||
namespace rx::vfs {
|
||||
void fork();
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
void addDevice(std::string name, IoDevice *device);
|
||||
|
|
|
|||
|
|
@ -634,6 +634,45 @@ static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) {
|
|||
gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated);
|
||||
}
|
||||
|
||||
void rx::vm::fork(std::uint64_t pid) {
|
||||
gMemoryShm = ::shm_open(("/rpcsx-os-memory-" + std::to_string(pid)).c_str(),
|
||||
O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (gMemoryShm == -1) {
|
||||
std::fprintf(stderr, "Memory: failed to open /rpcsx-os-memory\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (::ftruncate64(gMemoryShm, kMemorySize) < 0) {
|
||||
std::fprintf(stderr, "Memory: failed to allocate /rpcsx-os-memory\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
for (auto address = kMinAddress; address < kMaxAddress;
|
||||
address += kPageSize) {
|
||||
auto prot = gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection(
|
||||
(address & kBlockMask) >> rx::vm::kPageShift);
|
||||
|
||||
if (prot & kMapProtCpuAll) {
|
||||
auto mapping = utils::map(nullptr, kPageSize, PROT_WRITE, MAP_SHARED,
|
||||
gMemoryShm, address - kMinAddress);
|
||||
assert(mapping != MAP_FAILED);
|
||||
|
||||
utils::protect(reinterpret_cast<void *>(address), kPageSize, PROT_READ);
|
||||
std::memcpy(mapping, reinterpret_cast<void *>(address), kPageSize);
|
||||
utils::unmap(mapping, kPageSize);
|
||||
utils::unmap(reinterpret_cast<void *>(address), kPageSize);
|
||||
|
||||
mapping = utils::map(reinterpret_cast<void *>(address), kPageSize,
|
||||
prot & kMapProtCpuAll, MAP_FIXED | MAP_SHARED,
|
||||
gMemoryShm, address - kMinAddress);
|
||||
assert(mapping != MAP_FAILED);
|
||||
}
|
||||
|
||||
// TODO: copy gpu memory?
|
||||
}
|
||||
}
|
||||
|
||||
void rx::vm::initialize() {
|
||||
std::printf("Memory: initialization\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ std::string mapFlagsToString(std::int32_t flags);
|
|||
std::string mapProtToString(std::int32_t prot);
|
||||
|
||||
void printHostStats();
|
||||
void fork(std::uint64_t pid);
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
void *map(void *addr, std::uint64_t len, std::int32_t prot, std::int32_t flags,
|
||||
|
|
|
|||
Loading…
Reference in a new issue