diff --git a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp index bdcca505..9b23dd8b 100644 --- a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp +++ b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp @@ -166,23 +166,23 @@ struct BridgePusher { } void sendMapDmem(std::uint32_t pid, std::uint32_t dmemIndex, std::uint64_t address, std::uint64_t size, std::uint32_t prot, std::uint64_t offset) { - if (pid == expGpuPid) { + // if (pid == expGpuPid) { sendCommand(CommandId::MapDmem, {pid, dmemIndex, address, size, prot, offset}); - } + // } } void sendCommandBuffer(std::uint32_t pid, std::uint64_t queue, std::uint64_t address, std::uint64_t size) { - if (pid == expGpuPid) { + // if (pid == expGpuPid) { sendCommand(CommandId::CommandBuffer, {pid, queue, address, size}); - } + // } } void sendFlip(std::uint32_t pid, std::uint32_t bufferIndex, std::uint64_t arg) { - if (pid == expGpuPid) { + // if (pid == expGpuPid) { sendCommand(CommandId::Flip, {pid, bufferIndex, arg}); - } + // } } void wait() { diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 4ce58527..75483f28 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -1,16 +1,15 @@ #pragma once +#include "AudioOut.hpp" +#include "KernelAllocator.hpp" #include "evf.hpp" #include "ipmi.hpp" -#include "orbis/utils/IdMap.hpp" #include "osem.hpp" +#include "thread/types.hpp" +#include "utils/IdMap.hpp" #include "utils/LinkedNode.hpp" #include "utils/SharedCV.hpp" #include "utils/SharedMutex.hpp" -#include "AudioOut.hpp" -#include "KernelAllocator.hpp" -#include "orbis/thread/types.hpp" -#include #include #include #include @@ -175,6 +174,10 @@ class alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) KernelContext final { AudioOut *audioOut = nullptr; uint sdkVersion{}; uint fwSdkVersion{}; + uint safeMode{}; + + shared_mutex regMgrMtx; + kmap regMgrInt; private: mutable pthread_mutex_t m_heap_mtx; diff --git a/orbis-kernel/include/orbis/file.hpp b/orbis-kernel/include/orbis/file.hpp index bd3ee7c5..4949866b 100644 --- a/orbis-kernel/include/orbis/file.hpp +++ b/orbis-kernel/include/orbis/file.hpp @@ -57,8 +57,8 @@ struct FileOps { Thread *thread) = nullptr; ErrorCode (*sendmsg)(orbis::File *file, msghdr *msg, sint flags, Thread *thread) = nullptr; - ErrorCode (*recvfrom)(orbis::File *file, void *buf, size_t len, - sint flags, SocketAddress *from, uint32_t *fromlenaddr, + ErrorCode (*recvfrom)(orbis::File *file, void *buf, size_t len, sint flags, + SocketAddress *from, uint32_t *fromlenaddr, Thread *thread) = nullptr; ErrorCode (*recvmsg)(orbis::File *file, msghdr *msg, sint flags, Thread *thread) = nullptr; @@ -75,11 +75,15 @@ struct FileOps { struct File : RcBase { shared_mutex mtx; - EventEmitter event; + Ref event; const FileOps *ops = nullptr; Ref device; std::uint64_t nextOff = 0; + int flags = 0; + int mode = 0; int hostFd = -1; utils::kvector dirEntries; + + bool noBlock() const { return (flags & 4) != 0; } }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/ipmi.hpp b/orbis-kernel/include/orbis/ipmi.hpp index 1472d455..a7d828f3 100644 --- a/orbis-kernel/include/orbis/ipmi.hpp +++ b/orbis-kernel/include/orbis/ipmi.hpp @@ -16,7 +16,7 @@ struct Thread; struct IpmiServer : RcBase { struct IpmiPacketInfo { - ptr userData; + ulong inputSize; uint type; uint clientKid; ptr eventHandler; @@ -26,6 +26,8 @@ struct IpmiServer : RcBase { struct Packet { IpmiPacketInfo info; + lwpid_t clientTid; + Ref session; kvector message; }; @@ -36,6 +38,7 @@ struct IpmiServer : RcBase { slong serverTid{}; }; + kmap tidToClientTid; kstring name; ptr serverImpl; ptr eventHandler; @@ -51,24 +54,36 @@ struct IpmiServer : RcBase { }; struct IpmiClient : RcBase { + struct MessageQueue { + shared_cv messageCv; + kdeque> messages; + }; + + struct AsyncResponse { + uint methodId; + sint errorCode; + kvector> data; + }; + kstring name; ptr clientImpl; ptr userData; Ref session; shared_mutex mutex; shared_cv sessionCv; - sint pid; - kdeque> messages; + Process *process; + kdeque messageQueues; kdeque eventFlags; - shared_cv messageCv; + kdeque asyncResponses; explicit IpmiClient(kstring name) : name(std::move(name)) {} }; struct IpmiSession : RcBase { - struct MessageResponse { + struct SyncResponse { sint errorCode; - kvector data; + std::uint32_t callerTid; + kvector> data; }; ptr sessionImpl; @@ -77,9 +92,9 @@ struct IpmiSession : RcBase { Ref server; shared_mutex mutex; shared_cv responseCv; - kdeque messageResponses; + kdeque syncResponses; shared_cv connectCv; - bool expectedOutput = false; // TODO: verify + uint expectedOutput{0}; sint connectionStatus{0}; }; @@ -108,20 +123,19 @@ static_assert(sizeof(IpmiCreateClientConfig) == 0x150); struct IpmiBufferInfo { ptr data; + uint64_t capacity; uint64_t size; }; - struct IpmiDataInfo { ptr data; uint64_t size; - uint64_t capacity; //? }; -static_assert(sizeof(IpmiBufferInfo) == 0x10); -static_assert(sizeof(IpmiDataInfo) == 0x18); +// static_assert(sizeof(IpmiBufferInfo) == 0x18); +// static_assert(sizeof(IpmiDataInfo) == 0x10); -struct IpmiSyncMessageHeader { +struct [[gnu::packed]] IpmiSyncMessageHeader { orbis::ptr sessionImpl; orbis::uint pid; orbis::uint methodId; @@ -129,10 +143,18 @@ struct IpmiSyncMessageHeader { orbis::uint numOutData; }; +struct [[gnu::packed]] IpmiAsyncMessageHeader { + orbis::ptr sessionImpl; + orbis::uint methodId; + orbis::uint pid; + orbis::uint numInData; +}; + static_assert(sizeof(IpmiSyncMessageHeader) == 0x18); ErrorCode ipmiCreateClient(Process *proc, void *clientImpl, const char *name, - const IpmiCreateClientConfig &config, Ref &result); + const IpmiCreateClientConfig &config, + Ref &result); ErrorCode ipmiCreateServer(Process *proc, void *serverImpl, const char *name, const IpmiCreateServerConfig &config, Ref &result); @@ -162,9 +184,10 @@ SysResult sysIpmiSessionRespondSync(Thread *thread, ptr result, uint kid, SysResult sysIpmiClientInvokeAsyncMethod(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); -SysResult sysIpmiClientTryGetResult(Thread *thread, ptr result, - uint kid, ptr params, - uint64_t paramsSz); +SysResult sysImpiSessionRespondAsync(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); +SysResult sysIpmiClientTryGetResult(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); SysResult sysIpmiClientGetMessage(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiClientTryGetMessage(Thread *thread, ptr result, uint kid, @@ -181,10 +204,15 @@ SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint64_t paramsSz); SysResult sysIpmiClientConnect(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); +SysResult sysIpmiSessionGetClientAppId(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); SysResult sysIpmiSessionGetUserData(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiServerGetName(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); +SysResult sysIpmiClientGetName(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); SysResult sysIpmiClientWaitEventFlag(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiClientPollEventFlag(Thread *thread, ptr result, uint kid, diff --git a/orbis-kernel/include/orbis/note.hpp b/orbis-kernel/include/orbis/note.hpp index 0e9692fd..f6212d56 100644 --- a/orbis-kernel/include/orbis/note.hpp +++ b/orbis-kernel/include/orbis/note.hpp @@ -84,7 +84,7 @@ struct KNote { ~KNote(); }; -struct EventEmitter { +struct EventEmitter : orbis::RcBase { shared_mutex mutex; std::set, kallocator> notes; diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index b86a450f..b1d30c06 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -1,6 +1,8 @@ +#include "orbis-config.hpp" #include -#include -#include +#include +#include +#include namespace orbis { using acl_type_t = sint; @@ -11,17 +13,24 @@ using cpuwhich_t = sint; using cpulevel_t = sint; using SceKernelModule = ModuleHandle; +struct Thread; struct AuthInfo; struct MemoryProtection; struct ModuleInfo; struct ModuleInfoEx; struct KEvent; struct timespec; +struct timesec; +struct timezone; +struct timeval; struct Stat; struct stack_t; struct IoVec; struct BatchMapEntry; struct UContext; +struct SigSet; +struct SigAction; +struct SocketAddress; SysResult nosys(Thread *thread); @@ -29,7 +38,7 @@ SysResult sys_exit(Thread *thread, sint status); SysResult sys_fork(Thread *thread); SysResult sys_read(Thread *thread, sint fd, ptr buf, size_t nbyte); SysResult sys_write(Thread *thread, sint fd, ptr buf, size_t nbyte); -SysResult sys_open(Thread *thread, ptr path, sint flags, sint mode); +SysResult sys_open(Thread *thread, ptr path, sint flags, sint mode); SysResult sys_close(Thread *thread, sint fd); SysResult sys_wait4(Thread *thread, sint pid, ptr status, sint options, ptr rusage); @@ -125,15 +134,14 @@ SysResult sys_bind(Thread *thread, sint s, caddr_t name, sint namelen); SysResult sys_setsockopt(Thread *thread, sint s, sint level, sint name, caddr_t val, sint valsize); SysResult sys_listen(Thread *thread, sint s, sint backlog); -SysResult sys_gettimeofday(Thread *thread, ptr tp, - ptr tzp); +SysResult sys_gettimeofday(Thread *thread, ptr tp, ptr tzp); SysResult sys_getrusage(Thread *thread, sint who, ptr rusage); SysResult sys_getsockopt(Thread *thread, sint s, sint level, sint name, caddr_t val, ptr avalsize); SysResult sys_readv(Thread *thread, sint fd, ptr iovp, uint iovcnt); SysResult sys_writev(Thread *thread, sint fd, ptr iovp, uint iovcnt); SysResult sys_settimeofday(Thread *thread, ptr tp, - ptr tzp); + ptr tzp); SysResult sys_fchown(Thread *thread, sint fd, sint uid, sint gid); SysResult sys_fchmod(Thread *thread, sint fd, sint mode); SysResult sys_setreuid(Thread *thread, sint ruid, sint euid); @@ -230,8 +238,8 @@ SysResult sys_ktimer_settime(Thread *thread, sint timerid, sint flags, SysResult sys_ktimer_gettime(Thread *thread, sint timerid, ptr value); SysResult sys_ktimer_getoverrun(Thread *thread, sint timerid); -SysResult sys_nanosleep(Thread *thread, cptr rqtp, - ptr rmtp); +SysResult sys_nanosleep(Thread *thread, cptr rqtp, + ptr rmtp); SysResult sys_ntp_gettime(Thread *thread, ptr ntvp); SysResult sys_minherit(Thread *thread, ptr addr, size_t len, sint inherit); @@ -305,14 +313,14 @@ SysResult sys_jail(Thread *thread, ptr jail); SysResult sys_nnpfs_syscall(Thread *thread, sint operation, ptr a_pathP, sint opcode, ptr a_paramsP, sint a_followSymlinks); -SysResult sys_sigprocmask(Thread *thread, sint how, ptr set, - ptr oset); -SysResult sys_sigsuspend(Thread *thread, ptr set); -SysResult sys_sigpending(Thread *thread, ptr set); -SysResult sys_sigtimedwait(Thread *thread, ptr set, +SysResult sys_sigprocmask(Thread *thread, sint how, ptr set, + ptr oset); +SysResult sys_sigsuspend(Thread *thread, ptr set); +SysResult sys_sigpending(Thread *thread, ptr set); +SysResult sys_sigtimedwait(Thread *thread, ptr set, ptr info, ptr timeout); -SysResult sys_sigwaitinfo(Thread *thread, ptr set, +SysResult sys_sigwaitinfo(Thread *thread, ptr set, ptr info); SysResult sys___acl_get_file(Thread *thread, ptr path, acl_type_t type, ptr aclp); @@ -412,13 +420,13 @@ SysResult sys_extattr_delete_link(Thread *thread, ptr path, sint attrnamespace, ptr attrname); SysResult sys___mac_execve(Thread *thread, ptr fname, ptr> argv, ptr> envv, ptr mac_p); -SysResult sys_sigaction(Thread *thread, sint sig, ptr act, - ptr oact); -SysResult sys_sigreturn(Thread *thread, ptr sigcntxp); -SysResult sys_getcontext(Thread *thread, ptr ucp); -SysResult sys_setcontext(Thread *thread, ptr ucp); -SysResult sys_swapcontext(Thread *thread, ptr oucp, - ptr ucp); +SysResult sys_sigaction(Thread *thread, sint sig, ptr act, + ptr oact); +SysResult sys_sigreturn(Thread *thread, ptr sigcntxp); +SysResult sys_getcontext(Thread *thread, ptr ucp); +SysResult sys_setcontext(Thread *thread, ptr ucp); +SysResult sys_swapcontext(Thread *thread, ptr oucp, + ptr ucp); SysResult sys_swapoff(Thread *thread, ptr name); SysResult sys___acl_get_link(Thread *thread, ptr path, acl_type_t type, ptr aclp); @@ -428,10 +436,9 @@ SysResult sys___acl_delete_link(Thread *thread, ptr path, acl_type_t type); SysResult sys___acl_aclcheck_link(Thread *thread, ptr path, acl_type_t type, ptr aclp); -SysResult sys_sigwait(Thread *thread, ptr set, - ptr sig); -SysResult sys_thr_create(Thread *thread, ptr ctxt, - ptr arg, sint flags); +SysResult sys_sigwait(Thread *thread, ptr set, ptr sig); +SysResult sys_thr_create(Thread *thread, ptr ctxt, ptr arg, + sint flags); SysResult sys_thr_exit(Thread *thread, ptr state); SysResult sys_thr_self(Thread *thread, ptr id); SysResult sys_thr_kill(Thread *thread, slong id, sint sig); @@ -636,8 +643,9 @@ SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value, ptr pNumWaitThreads); SysResult sys_query_memory_protection(Thread *thread, ptr address, ptr protection); -SysResult sys_batch_map(Thread *thread, sint unk, sint flags, ptr entries, - sint entriesCount, ptr processedCount); +SysResult sys_batch_map(Thread *thread, sint unk, sint flags, + ptr entries, sint entriesCount, + ptr processedCount); SysResult sys_osem_create(Thread *thread, ptr name, uint attrs, sint initCount, sint maxCount); SysResult sys_osem_delete(Thread *thread, sint id); @@ -746,15 +754,16 @@ SysResult sys_physhm_unlink(Thread *thread /* TODO */); SysResult sys_resume_internal_hdd(Thread *thread /* TODO */); SysResult sys_thr_suspend_ucontext(Thread *thread, lwpid_t tid); SysResult sys_thr_resume_ucontext(Thread *thread, lwpid_t tid); -SysResult sys_thr_get_ucontext(Thread *thread, lwpid_t tid, ptr context); -SysResult sys_thr_set_ucontext(Thread *thread, lwpid_t tid, ptr context); +SysResult sys_thr_get_ucontext(Thread *thread, lwpid_t tid, + ptr context); +SysResult sys_thr_set_ucontext(Thread *thread, lwpid_t tid, + ptr context); SysResult sys_set_timezone_info(Thread *thread /* TODO */); SysResult sys_set_phys_fmem_limit(Thread *thread /* TODO */); SysResult sys_utc_to_localtime(Thread *thread, int64_t time, int64_t *localtime, - orbis::timesec *_sec, int *_dst_sec); + timesec *_sec, int *_dst_sec); SysResult sys_localtime_to_utc(Thread *thread, int64_t time, uint unk, - int64_t *ptime, orbis::timesec *_sec, - int *_dst_sec); + int64_t *ptime, timesec *_sec, int *_dst_sec); SysResult sys_set_uevt(Thread *thread /* TODO */); SysResult sys_get_cpu_usage_proc(Thread *thread /* TODO */); SysResult sys_get_map_statistics(Thread *thread /* TODO */); diff --git a/orbis-kernel/include/orbis/thread/Process.hpp b/orbis-kernel/include/orbis/thread/Process.hpp index 302b04b8..b824e292 100644 --- a/orbis-kernel/include/orbis/thread/Process.hpp +++ b/orbis-kernel/include/orbis/thread/Process.hpp @@ -66,6 +66,7 @@ struct Process final { bool isInSandbox = false; EventEmitter event; + std::uint32_t sdkVersion = -1; std::uint64_t nextTlsSlot = 1; std::uint64_t lastTlsOffset = 0; @@ -81,6 +82,8 @@ struct Process final { utils::kmap namedObjNames; utils::OwningIdMap namedObjIds; + utils::kmap sigActions; + // Named memory ranges for debugging utils::shared_mutex namedMemMutex; utils::kmap namedMem; diff --git a/orbis-kernel/include/orbis/thread/ProcessOps.hpp b/orbis-kernel/include/orbis/thread/ProcessOps.hpp index b07293e6..71508bf2 100644 --- a/orbis-kernel/include/orbis/thread/ProcessOps.hpp +++ b/orbis-kernel/include/orbis/thread/ProcessOps.hpp @@ -12,6 +12,7 @@ struct timespec; struct File; struct MemoryProtection; struct IoVec; +struct UContext; struct ProcessOps { SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot, @@ -64,7 +65,7 @@ struct ProcessOps { uint64_t arg3); SysResult (*dynlib_unload_prx)(Thread *thread, ModuleHandle handle); - SysResult (*thr_create)(Thread *thread, ptr ctxt, + SysResult (*thr_create)(Thread *thread, ptr ctxt, ptr arg, sint flags); SysResult (*thr_new)(Thread *thread, ptr param, sint param_size); SysResult (*thr_exit)(Thread *thread, ptr state); diff --git a/orbis-kernel/include/orbis/thread/RegisterId.hpp b/orbis-kernel/include/orbis/thread/RegisterId.hpp index cda5efc3..be63423a 100644 --- a/orbis-kernel/include/orbis/thread/RegisterId.hpp +++ b/orbis-kernel/include/orbis/thread/RegisterId.hpp @@ -19,5 +19,6 @@ enum class RegisterId { rax, rsp, rflags, + rip, }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/Thread.hpp b/orbis-kernel/include/orbis/thread/Thread.hpp index 6e9a8b21..84418cfb 100644 --- a/orbis-kernel/include/orbis/thread/Thread.hpp +++ b/orbis-kernel/include/orbis/thread/Thread.hpp @@ -4,12 +4,16 @@ #include "orbis-config.hpp" #include "types.hpp" +#include "../KernelAllocator.hpp" +#include "../ucontext.hpp" #include "../utils/SharedCV.hpp" #include "../utils/SharedMutex.hpp" +#include #include namespace orbis { struct Process; + struct Thread { utils::shared_mutex mtx; Process *tproc = nullptr; @@ -21,8 +25,14 @@ struct Thread { uint64_t gsBase{}; char name[32]{}; - uint64_t sigMask[4] = {0x7fff'ffff, 0}; + SigSet sigMask = {0x7fff'ffff, ~0u, ~0u, ~0u}; + utils::shared_mutex suspend_mtx; + utils::shared_cv suspend_cv; + kdeque signalQueue; + kvector sigReturns; + std::atomic suspended{0}; + std::int64_t hostTid = -1; lwpid_t tid = -1; ThreadState state = ThreadState::INACTIVE; std::thread handle; @@ -35,6 +45,10 @@ struct Thread { // Print backtrace void where(); + void suspend(); + void resume(); + void sendSignal(int signo); + // FIXME: implement thread destruction void incRef() {} void decRef() {} diff --git a/orbis-kernel/include/orbis/ucontext.hpp b/orbis-kernel/include/orbis/ucontext.hpp index 2afb3e4f..3d8cff4b 100644 --- a/orbis-kernel/include/orbis/ucontext.hpp +++ b/orbis-kernel/include/orbis/ucontext.hpp @@ -54,7 +54,20 @@ struct Stack { }; struct SigSet { - ulong bits[2]; + static constexpr auto min = 1; + static constexpr auto max = 128; + + uint bits[4]; + + bool test(unsigned signal) const { + return (bits[(signal - 1) >> 5] & (1 << ((signal - 1) & 31))) != 0; + } + void set(unsigned signal) { + bits[(signal - 1) >> 5] |= (1 << ((signal - 1) & 31)); + } + void clear(unsigned signal) { + bits[(signal - 1) >> 5] &= ~(1 << ((signal - 1) & 31)); + } }; struct UContext { @@ -67,4 +80,87 @@ struct UContext { sint spare[4]; sint unk1[3]; }; + +static_assert(sizeof(UContext) == 0x500); + + +enum Signal { + kSigHup = 1, + kSigInt = 2, + kSigQuit = 3, + kSigIll = 4, + kSigTrap = 5, + kSigAbrt = 6, + kSigEmt = 7, + kSigFpe = 8, + kSigKill = 9, + kSigBus = 10, + kSigSegv = 11, + kSigSys = 12, + kSigPipe = 13, + kSigAlrm = 14, + kSigUrg = 16, + kSigStop = 17, + kSigTstp = 18, + kSigCont = 19, + kSigChld = 20, + kSigTtin = 21, + kSigTtou = 22, + kSigIo = 23, + kSigXcpu = 24, + kSigXfsz = 25, + kSigVtalrm = 26, + kSigProf = 27, + kSigWinch = 28, + kSigInfo = 29, + kSigUsr1 = 30, + kSigUsr2 = 31, + kSigThr = 32, +}; + +struct SigAction { + ptr handler; + sint flags; + SigSet mask; +}; + +union SigVal { + sint integer; + ptr pointer; +}; + +struct SigInfo { + sint signo; + sint errno_; + sint code; + sint pid; + slong uid; + sint status; + ptr addr; + SigVal value; + + union { + struct { + sint trapno; + } fault; + + struct { + sint timerid; + sint overrun; + } timer; + + struct { + sint mqd; + } mesgq; + + struct { + slong band; + } poll; + + struct { + slong spare1; + sint spare2[7]; + } spare; + } reason; +}; } // namespace orbis diff --git a/orbis-kernel/include/orbis/utils/SharedCV.hpp b/orbis-kernel/include/orbis/utils/SharedCV.hpp index c378a353..8de8bc1b 100644 --- a/orbis-kernel/include/orbis/utils/SharedCV.hpp +++ b/orbis-kernel/include/orbis/utils/SharedCV.hpp @@ -34,7 +34,7 @@ class shared_cv final { } // Internal waiting function - void impl_wait(shared_mutex &mutex, unsigned _val, + int impl_wait(shared_mutex &mutex, unsigned _val, std::uint64_t usec_timeout) noexcept; // Try to notify up to _count threads @@ -43,14 +43,14 @@ class shared_cv final { public: constexpr shared_cv() = default; - void wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept { + int wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept { const unsigned _val = add_waiter(); if (!_val) { - return; + return 0; } mutex.unlock(); - impl_wait(mutex, _val, usec_timeout); + return impl_wait(mutex, _val, usec_timeout); } // Wake one thread diff --git a/orbis-kernel/include/orbis/utils/SharedMutex.hpp b/orbis-kernel/include/orbis/utils/SharedMutex.hpp index d96fa8c8..265ad37e 100644 --- a/orbis-kernel/include/orbis/utils/SharedMutex.hpp +++ b/orbis-kernel/include/orbis/utils/SharedMutex.hpp @@ -20,7 +20,7 @@ class shared_mutex final { void impl_lock_shared(unsigned val); void impl_unlock_shared(unsigned old); - void impl_wait(); + int impl_wait(); void impl_signal(); void impl_lock(unsigned val); void impl_unlock(unsigned old); diff --git a/orbis-kernel/src/KernelContext.cpp b/orbis-kernel/src/KernelContext.cpp index f6c8ec47..7c533192 100644 --- a/orbis-kernel/src/KernelContext.cpp +++ b/orbis-kernel/src/KernelContext.cpp @@ -4,8 +4,9 @@ #include "orbis/utils/Logs.hpp" #include #include -#include +#include #include +#include namespace orbis { thread_local Thread *g_currentThread; @@ -13,7 +14,7 @@ thread_local Thread *g_currentThread; KernelContext &g_context = *[]() -> KernelContext * { // Allocate global shared kernel memory // TODO: randomize for hardening and reduce size - auto ptr = mmap(reinterpret_cast(0x200'0000'0000), 0x1'0000'0000, + auto ptr = mmap(reinterpret_cast(0x200'0000'0000), 0x2'0000'0000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (ptr == MAP_FAILED) @@ -32,7 +33,7 @@ KernelContext::KernelContext() { pthread_mutexattr_destroy(&mtx_attr); // std::printf("orbis::KernelContext initialized, addr=%p\n", this); - // std::printf("TSC frequency: %lu\n", getTscFreq()); + std::printf("TSC frequency: %lu\n", getTscFreq()); } KernelContext::~KernelContext() {} @@ -71,7 +72,7 @@ void KernelContext::deleteProcess(Process *proc) { } Process *KernelContext::findProcessById(pid_t pid) const { - for (std::size_t i = 0; i < 5; ++i) { + for (std::size_t i = 0; i < 20; ++i) { { std::lock_guard lock(m_proc_mtx); for (auto proc = m_processes; proc != nullptr; proc = proc->next) { @@ -87,7 +88,7 @@ Process *KernelContext::findProcessById(pid_t pid) const { } Process *KernelContext::findProcessByHostId(std::uint64_t pid) const { - for (std::size_t i = 0; i < 5; ++i) { + for (std::size_t i = 0; i < 20; ++i) { { std::lock_guard lock(m_proc_mtx); for (auto proc = m_processes; proc != nullptr; proc = proc->next) { @@ -215,6 +216,7 @@ KernelContext::getUmtxChainIndexed(int i, Thread *t, uint32_t flags, if (flags & 1) { pid = 0; // Process shared (TODO) ORBIS_LOG_WARNING("Using process-shared umtx", t->tid, ptr, (p % 0x4000)); + t->where(); } auto n = p + pid; if (flags & 1) @@ -238,5 +240,21 @@ void log_class_string::format(std::string &out, const void *arg) { } } // namespace logs +void Thread::suspend() { + sendSignal(-1); +} + +void Thread::resume() { + sendSignal(-2); +} + +void Thread::sendSignal(int signo) { + std::lock_guard lock(mtx); + signalQueue.push_back(signo); + if (::tgkill(tproc->hostPid, hostTid, SIGUSR1) < 0) { + perror("tgkill"); + } +} + void Thread::where() { tproc->ops->where(this); } } // namespace orbis diff --git a/orbis-kernel/src/event.cpp b/orbis-kernel/src/event.cpp index d68631bc..407b0953 100644 --- a/orbis-kernel/src/event.cpp +++ b/orbis-kernel/src/event.cpp @@ -21,8 +21,12 @@ void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) { if (note->event.filter != filter) { continue; } - if (fflags != 0 && ((note->event.fflags & fflags) == 0)) { - continue; + if (fflags != 0) { + if ((note->event.fflags & fflags) == 0) { + continue; + } + + note->event.fflags = fflags; } std::lock_guard lock(note->mutex); diff --git a/orbis-kernel/src/evf.cpp b/orbis-kernel/src/evf.cpp index 063362f4..fc6b8bee 100644 --- a/orbis-kernel/src/evf.cpp +++ b/orbis-kernel/src/evf.cpp @@ -33,6 +33,7 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode, thread->evfIsCancelled = -1; std::unique_lock lock(queueMtx); + int result = 0; while (true) { if (isDeleted) { if (thread->evfIsCancelled == UINT64_MAX) @@ -77,10 +78,10 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode, waitingThreads.emplace_back(waitingThread); if (timeout) { - thread->sync_cv.wait(queueMtx, *timeout); + result = thread->sync_cv.wait(queueMtx, *timeout); update_timeout(); } else { - thread->sync_cv.wait(queueMtx); + result = thread->sync_cv.wait(queueMtx); } if (thread->evfIsCancelled == UINT64_MAX) { @@ -89,7 +90,7 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode, } // TODO: update thread state - return {}; + return ErrorCode{result}; } orbis::ErrorCode orbis::EventFlag::tryWait(Thread *thread, @@ -137,7 +138,7 @@ std::size_t orbis::EventFlag::notify(NotifyType type, std::uint64_t bits) { // TODO: update thread state // release wait on waiter thread - thread->thread->sync_cv.notify_one(queueMtx); + thread->thread->sync_cv.notify_all(queueMtx); return true; }; diff --git a/orbis-kernel/src/ipmi.cpp b/orbis-kernel/src/ipmi.cpp index f81a4962..a0fbe6fa 100644 --- a/orbis-kernel/src/ipmi.cpp +++ b/orbis-kernel/src/ipmi.cpp @@ -3,6 +3,7 @@ #include "thread/Process.hpp" #include "utils/Logs.hpp" #include +#include orbis::ErrorCode orbis::ipmiCreateClient(Process *proc, void *clientImpl, const char *name, @@ -15,9 +16,10 @@ orbis::ErrorCode orbis::ipmiCreateClient(Process *proc, void *clientImpl, client->clientImpl = clientImpl; client->name = name; - client->pid = proc->pid; + client->process = proc; client->userData = config.userData; client->eventFlags.resize(32); + client->messageQueues.resize(32); result = client; return {}; } @@ -72,7 +74,7 @@ orbis::ErrorCode orbis::ipmiCreateSession(Thread *thread, void *sessionImpl, session->client = conReq.client; session->server = server; conReq.client->session = session; - conReq.client->sessionCv.notify_all(conReq.client->mutex); + conReq.client->sessionCv.notify_one(conReq.client->mutex); return {}; } @@ -241,7 +243,6 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread, IpmiServer::Packet _packet; - ORBIS_LOG_ERROR(__FUNCTION__, server->name, ": waiting for packet"); { std::lock_guard lock(server->mutex); while (server->packets.empty()) { @@ -251,20 +252,39 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread, _packet = std::move(server->packets.front()); server->packets.pop_front(); } - ORBIS_LOG_ERROR(__FUNCTION__, server->name, ": got packet"); if (_packet.info.type == 0x1) { // on connection packet for (auto &conn : server->connectionRequests) { - if ((ptr)conn.clientTid == _packet.info.userData) { + if (conn.clientTid == _packet.info.inputSize) { conn.serverTid = thread->tid; - _packet.info.userData = nullptr; + _packet.info.inputSize = 0; break; } } + } else if ((_packet.info.type & ~(0x10 | 0x8000)) == 0x41) { + auto syncMessage = (IpmiSyncMessageHeader *)_packet.message.data(); + ORBIS_LOG_ERROR(__FUNCTION__, server->name, syncMessage->methodId, + syncMessage->numInData, syncMessage->numOutData, + syncMessage->pid); + } else if ((_packet.info.type & ~0x10) == 0x43) { + auto asyncMessage = (IpmiAsyncMessageHeader *)_packet.message.data(); + ORBIS_LOG_ERROR(__FUNCTION__, server->name, asyncMessage->methodId, + asyncMessage->numInData, asyncMessage->pid); + + ORBIS_LOG_ERROR(__FUNCTION__, server->name, + *(std::uint64_t *)(*(long *)server->eventHandler + 0x18)); + } + + if (_params.bufferSize < _packet.message.size()) { + ORBIS_LOG_ERROR(__FUNCTION__, "too small buffer", _params.bufferSize, + _packet.message.size()); + return ErrorCode::INVAL; } + server->tidToClientTid[thread->tid] = _packet.clientTid; + ORBIS_RET_ON_ERROR(uwriteRaw((ptr)_params.buffer, _packet.message.data(), _packet.message.size())); _params.bufferSize = _packet.message.size(); @@ -280,7 +300,6 @@ orbis::SysResult orbis::sysIpmiSendConnectResult(Thread *thread, ptr params, uint64_t paramsSz) { if (paramsSz != sizeof(sint)) { - ORBIS_LOG_ERROR(__FUNCTION__, "wrong param size"); return ErrorCode::INVAL; } @@ -296,9 +315,9 @@ orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread, uint64_t paramsSz) { struct IpmiRespondParams { sint errorCode; - uint32_t unk1; - ptr buffers; uint32_t bufferCount; + ptr buffers; + uint32_t flags; uint32_t padding; }; @@ -316,35 +335,37 @@ orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread, IpmiRespondParams _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); - if (_params.bufferCount > 1) { - ORBIS_LOG_ERROR(__FUNCTION__, "unexpected buffers count"); - return ErrorCode::INVAL; - } - - ORBIS_LOG_ERROR(__FUNCTION__, session->client->name); - thread->where(); + kvector> buffers; - kvector data; + if ((_params.flags & 1) || _params.bufferCount != 1) { + auto count = _params.bufferCount; + buffers.reserve(count); + for (uint32_t i = 0; i < count; ++i) { + IpmiBufferInfo _buffer; + ORBIS_RET_ON_ERROR(uread(_buffer, _params.buffers + i)); - if (_params.errorCode == 0 && _params.bufferCount > 0 && - session->expectedOutput) { - IpmiBufferInfo _buffer; - ORBIS_RET_ON_ERROR(uread(_buffer, _params.buffers)); - - data.resize(_buffer.size); - ORBIS_RET_ON_ERROR(ureadRaw(data.data(), _buffer.data, _buffer.size)); + auto &bufferData = buffers.emplace_back(); + bufferData.resize(_buffer.size); + ORBIS_RET_ON_ERROR( + ureadRaw(bufferData.data(), _buffer.data, _buffer.size)); + } } std::lock_guard lock(session->mutex); - ORBIS_LOG_ERROR(__FUNCTION__, _params.errorCode); + std::uint32_t clientTid; + { + std::lock_guard serverLock(session->server->mutex); + clientTid = session->server->tidToClientTid.at(thread->tid); + } - session->messageResponses.push_front({ + session->syncResponses.push_front({ .errorCode = _params.errorCode, - .data = std::move(data), + .callerTid = clientTid, + .data = std::move(buffers), }); - session->responseCv.notify_one(session->mutex); + session->responseCv.notify_all(session->mutex); return uwrite(result, 0u); } orbis::SysResult orbis::sysIpmiClientInvokeAsyncMethod(Thread *thread, @@ -354,8 +375,8 @@ orbis::SysResult orbis::sysIpmiClientInvokeAsyncMethod(Thread *thread, uint64_t paramsSz) { struct IpmiAsyncCallParams { uint32_t method; - uint32_t unkNotifee0; - uint64_t unkNotifee1; + uint32_t evfIndex; + uint64_t evfValue; uint32_t numInData; uint32_t padding1; ptr pInData; @@ -378,20 +399,121 @@ orbis::SysResult orbis::sysIpmiClientInvokeAsyncMethod(Thread *thread, IpmiAsyncCallParams _params; ORBIS_RET_ON_ERROR(uread(_params, (ptr)params)); - ORBIS_LOG_TODO(__FUNCTION__, thread->tid, client->name, _params.method, - _params.unkNotifee0, _params.unkNotifee1, _params.numInData, - _params.padding1, _params.pInData, _params.pResult, - _params.flags); - thread->where(); + if (_params.flags > 1) { + return ErrorCode::INVAL; + } + + std::lock_guard clientLock(client->mutex); + auto session = client->session; + + if (session == nullptr) { + return ErrorCode::INVAL; + } + + std::lock_guard sessionLock(session->mutex); + auto server = session->server; + + if (server == nullptr) { + return ErrorCode::INVAL; + } + + { + std::lock_guard serverLock(server->mutex); + + std::size_t inSize = 0; + for (auto &data : std::span(_params.pInData, _params.numInData)) { + inSize += data.size; + } + + auto size = sizeof(IpmiAsyncMessageHeader) + inSize + + _params.numInData * sizeof(uint32_t); + kvector message(size); + auto msg = new (message.data()) IpmiAsyncMessageHeader; + msg->sessionImpl = session->sessionImpl; + msg->pid = thread->tproc->pid; + msg->methodId = _params.method; + msg->numInData = _params.numInData; + + auto bufLoc = std::bit_cast(msg + 1); + + for (auto &data : std::span(_params.pInData, _params.numInData)) { + *std::bit_cast(bufLoc) = data.size; + bufLoc += sizeof(uint32_t); + ORBIS_RET_ON_ERROR(ureadRaw(bufLoc, data.data, data.size)); + bufLoc += data.size; + } + + uint type = 0x43; + + if ((_params.flags & 1) == 0) { + type |= 0x10; + } + + server->packets.push_back( + {{.type = type, .clientKid = kid}, 0, session, std::move(message)}); + server->receiveCv.notify_one(server->mutex); + } - if (_params.unkNotifee0 != -1) { - client->eventFlags[_params.unkNotifee0].set(1); - } + if (_params.evfIndex != -1 && _params.evfValue != 0) { + client->eventFlags[_params.evfIndex].set(_params.evfValue); + } ORBIS_RET_ON_ERROR(uwrite(_params.pResult, 0)); return uwrite(result, 0u); } +orbis::SysResult orbis::sysImpiSessionRespondAsync(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct IpmiAsyncRespondParams { + uint method; + uint pid; + sint result; + uint32_t numOutData; + ptr pOutData; + uint32_t unk2; // == 1 + }; + + static_assert(sizeof(IpmiAsyncRespondParams) == 0x20); + + if (paramsSz != sizeof(IpmiAsyncRespondParams)) { + return ErrorCode::INVAL; + } + + auto session = thread->tproc->ipmiMap.get(kid).cast(); + + if (session == nullptr) { + return ErrorCode::INVAL; + } + + auto client = session->client; + + if (client == nullptr) { + return ErrorCode::INVAL; + } + + IpmiAsyncRespondParams _params; + ORBIS_RET_ON_ERROR(uread(_params, (ptr)params)); + + kvector> outData; + outData.reserve(_params.numOutData); + for (auto data : std::span(_params.pOutData, _params.numOutData)) { + auto &elem = outData.emplace_back(); + elem.resize(data.size); + ORBIS_RET_ON_ERROR(ureadRaw(elem.data(), data.data, data.size)); + } + + std::lock_guard clientLock(client->mutex); + client->asyncResponses.push_back({ + .methodId = _params.method, + .errorCode = _params.result, + .data = std::move(outData), + }); + + return uwrite(result, 0u); +} + orbis::SysResult orbis::sysIpmiClientTryGetResult(Thread *thread, ptr result, uint kid, ptr params, @@ -421,19 +543,66 @@ orbis::SysResult orbis::sysIpmiClientTryGetResult(Thread *thread, return ErrorCode::INVAL; } - ORBIS_LOG_TODO(__FUNCTION__, thread->tid, client->name, _params.method, - _params.unk, _params.pResult, _params.numOutData, - _params.padding, _params.pOutData, _params.padding2); - thread->where(); - ORBIS_RET_ON_ERROR(uwrite(_params.pResult, 0)); - return uwrite(result, 0u); + while (true) { + { + std::lock_guard clientLock(client->mutex); + + for (auto it = client->asyncResponses.begin(); + it != client->asyncResponses.end(); ++it) { + if (it->methodId != _params.method) { + continue; + } + + auto response = std::move(*it); + client->asyncResponses.erase(it); + + ORBIS_RET_ON_ERROR(uwrite(_params.pResult, it->errorCode)); + + if (response.data.size() != _params.numOutData) { + ORBIS_LOG_ERROR(__FUNCTION__, "responses count mismatch", + response.data.size(), _params.numOutData); + } + + for (std::size_t i = 0; i < response.data.size(); ++i) { + if (response.data.size() > _params.numOutData) { + ORBIS_LOG_ERROR(__FUNCTION__, "too many responses", + response.data.size(), _params.numOutData); + break; + } + + IpmiBufferInfo _outData; + ORBIS_RET_ON_ERROR(uread(_outData, _params.pOutData + i)); + + auto &data = response.data[i]; + + if (_outData.capacity < data.size()) { + ORBIS_LOG_ERROR(__FUNCTION__, "too big response", _outData.capacity, + data.size()); + continue; + } + + _outData.size = data.size(); + ORBIS_RET_ON_ERROR( + uwriteRaw(_outData.data, data.data(), data.size())); + ORBIS_RET_ON_ERROR(uwrite(_params.pOutData + i, _outData)); + } + + return uwrite(result, 0u); + } + } + + std::this_thread::sleep_for(std::chrono::microseconds(200)); + } + + // return uwrite(result, 0x80020000 + static_cast(ErrorCode::AGAIN)); } + orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz) { struct SceIpmiClientGetArgs { - uint32_t unk; // 0 + uint32_t queueIndex; uint32_t padding; ptr message; ptr pSize; @@ -456,23 +625,24 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, SceIpmiClientGetArgs _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); - ORBIS_LOG_ERROR(__FUNCTION__, client->name, client->messages.size(), - _params.unk, _params.padding, _params.message, _params.pSize, - _params.maxSize, _params.pTimeout); - std::lock_guard lock(client->mutex); + if (_params.queueIndex >= client->messageQueues.size()) { + return ErrorCode::INVAL; + } + + auto &queue = client->messageQueues[_params.queueIndex]; + using clock = std::chrono::high_resolution_clock; clock::time_point timeoutPoint = clock::time_point::max(); if (_params.pTimeout != nullptr) { std::uint32_t timeout{}; - ORBIS_LOG_ERROR(__FUNCTION__, timeout); ORBIS_RET_ON_ERROR(uread(timeout, _params.pTimeout)); timeoutPoint = clock::now() + std::chrono::microseconds(timeout); } - if (client->messages.empty()) { + if (queue.messages.empty()) { if (timeoutPoint != clock::time_point::max()) { while (true) { auto now = clock::now(); @@ -484,9 +654,9 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, auto waitTime = std::chrono::duration_cast( timeoutPoint - now); - client->messageCv.wait(client->mutex, waitTime.count()); + queue.messageCv.wait(client->mutex, waitTime.count()); - if (!client->messages.empty()) { + if (!queue.messages.empty()) { now = clock::now(); if (now >= timeoutPoint) { @@ -503,13 +673,13 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, } } } else { - while (client->messages.empty()) { - client->messageCv.wait(client->mutex); + while (queue.messages.empty()) { + queue.messageCv.wait(client->mutex); } } } - auto &message = client->messages.front(); + auto &message = queue.messages.front(); if (_params.maxSize < message.size()) { ORBIS_LOG_ERROR(__FUNCTION__, "too small buffer"); @@ -520,7 +690,7 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread, ORBIS_RET_ON_ERROR(uwrite(_params.pSize, message.size())); ORBIS_RET_ON_ERROR( uwriteRaw(_params.message, message.data(), message.size())); - client->messages.pop_front(); + queue.messages.pop_front(); return uwrite(result, 0); } @@ -529,7 +699,7 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, ptr params, uint64_t paramsSz) { struct SceIpmiClientTryGetArgs { - uint32_t unk; // 0 + uint32_t queueIndex; uint32_t padding; ptr message; ptr pSize; @@ -548,18 +718,23 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, return ErrorCode::INVAL; } - // ORBIS_LOG_ERROR(__FUNCTION__, client->name, client->messages.size()); - SceIpmiClientTryGetArgs _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); std::lock_guard lock(client->mutex); - if (client->messages.empty()) { + + if (_params.queueIndex >= client->messageQueues.size()) { + return ErrorCode::INVAL; + } + + auto &queue = client->messageQueues[_params.queueIndex]; + + if (queue.messages.empty()) { return uwrite(result, 0x80020000 + static_cast(ErrorCode::AGAIN)); } - auto &message = client->messages.front(); + auto &message = queue.messages.front(); if (_params.maxSize < message.size()) { ORBIS_LOG_ERROR(__FUNCTION__, "too small buffer"); @@ -570,7 +745,7 @@ orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread, ORBIS_RET_ON_ERROR(uwrite(_params.pSize, message.size())); ORBIS_RET_ON_ERROR( uwriteRaw(_params.message, message.data(), message.size())); - client->messages.pop_front(); + queue.messages.pop_front(); return uwrite(result, 0); } @@ -579,7 +754,7 @@ orbis::SysResult orbis::sysIpmiSessionTrySendMessage(Thread *thread, ptr params, uint64_t paramsSz) { struct SceIpmiClientTrySendArgs { - uint32_t unk; // 0 + uint32_t queueIndex; uint32_t padding; ptr message; uint64_t size; @@ -609,12 +784,16 @@ orbis::SysResult orbis::sysIpmiSessionTrySendMessage(Thread *thread, auto client = session->client; std::lock_guard lockClient(client->mutex); - ORBIS_LOG_ERROR(__FUNCTION__, session->server->name, client->name, - client->messages.size(), _params.message, _params.size); - auto &message = client->messages.emplace_back(); + if (_params.queueIndex >= client->messageQueues.size()) { + return ErrorCode::INVAL; + } + + auto &queue = client->messageQueues[_params.queueIndex]; + + auto &message = queue.messages.emplace_back(); message.resize(_params.size); ORBIS_RET_ON_ERROR(ureadRaw(message.data(), _params.message, _params.size)); - client->messageCv.notify_one(client->mutex); + queue.messageCv.notify_all(client->mutex); return uwrite(result, 0); } @@ -640,11 +819,6 @@ orbis::SysResult orbis::sysIpmiClientDisconnect(Thread *thread, ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); ORBIS_LOG_ERROR(__FUNCTION__, client->name, _params.status); - - std::lock_guard lock(client->mutex); - - auto &message = client->messages.front(); - ORBIS_RET_ON_ERROR(uwrite(_params.status, 0)); return uwrite(result, 0); } @@ -669,7 +843,8 @@ orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread, IpmiGetClientPidParams _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); - ORBIS_RET_ON_ERROR(uwrite(_params.pid, session->client->pid)); + ORBIS_RET_ON_ERROR( + uwrite(_params.pid, session->client->process->pid)); return uwrite(result, 0); } orbis::SysResult @@ -680,8 +855,8 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, uint32_t numInData; uint32_t numOutData; uint32_t unk; - ptr pInData; - ptr pOutData; + ptr pInData; + ptr pOutData; ptr pResult; uint32_t flags; }; @@ -705,23 +880,12 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, return ErrorCode::INVAL; } - std::lock_guard clientLock(client->mutex); auto session = client->session; if (session == nullptr) { - // ORBIS_LOG_TODO(__FUNCTION__, "waiting for connection", client->name, - // _params.method); - - // while (session == nullptr) { - // client->sessionCv.wait(client->mutex); - // session = client->session; - // } return ErrorCode::INVAL; } - ORBIS_LOG_ERROR(__FUNCTION__, client->name, "sync call", _params.method); - // thread->where(); - std::lock_guard sessionLock(session->mutex); auto server = session->server; @@ -732,23 +896,14 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, { std::lock_guard serverLock(server->mutex); - // ORBIS_LOG_TODO("IPMI: invokeSyncMethod", client->name, _params.method, - // _params.numInData, _params.unk, _params.numOutData, - // _params.pInData, _params.pOutData, _params.pResult, - // _params.flags); std::size_t inSize = 0; for (auto &data : std::span(_params.pInData, _params.numInData)) { inSize += data.size; } - std::size_t outSize = 0; - for (auto &data : std::span(_params.pOutData, _params.numOutData)) { - outSize += data.size; - } - - auto size = sizeof(IpmiSyncMessageHeader) + inSize + outSize + - _params.numInData * sizeof(uint32_t) + - _params.numOutData * sizeof(uint32_t); + auto headerSize = sizeof(IpmiSyncMessageHeader) + inSize + + _params.numInData * sizeof(uint32_t); + auto size = headerSize + _params.numOutData * sizeof(uint); kvector message(size); auto msg = new (message.data()) IpmiSyncMessageHeader; @@ -758,8 +913,6 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, msg->numInData = _params.numInData; msg->numOutData = _params.numOutData; - ORBIS_LOG_TODO("IPMI: sync call", client->name, _params.method, - thread->tproc->pid); auto bufLoc = std::bit_cast(msg + 1); for (auto &data : std::span(_params.pInData, _params.numInData)) { @@ -770,51 +923,87 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, } for (auto &data : std::span(_params.pOutData, _params.numOutData)) { - *std::bit_cast(bufLoc) = data.size; - bufLoc += sizeof(uint32_t) + data.size; + *std::bit_cast(bufLoc) = data.capacity; + bufLoc += sizeof(uint32_t); } uint type = 0x41; - if (_params.numInData == 1 && _params.numOutData == 1 && - server->pid == thread->tproc->pid) { + if ((_params.flags & 1) == 0) { type |= 0x10; } - if ((_params.flags & 1) == 0) { + if (server->pid == thread->tproc->pid) { type |= 0x8000; } - session->expectedOutput = _params.numOutData > 0; server->packets.push_back( - {{.type = type, .clientKid = kid}, std::move(message)}); - server->receiveCv.notify_all(server->mutex); + {{.inputSize = headerSize, .type = type, .clientKid = kid}, + thread->tid, + session, + std::move(message)}); + server->receiveCv.notify_one(server->mutex); } - while (session->messageResponses.empty()) { + IpmiSession::SyncResponse response; + + while (true) { session->responseCv.wait(session->mutex); - } - auto response = std::move(session->messageResponses.front()); - session->messageResponses.pop_front(); + bool found = false; + for (auto it = session->syncResponses.begin(); + it != session->syncResponses.end(); ++it) { + if (it->callerTid != thread->tid) { + continue; + } + + response = std::move(*it); + session->syncResponses.erase(it); + found = true; + break; + } + if (found) { + break; + } + } if (response.errorCode != 0) { thread->where(); } ORBIS_RET_ON_ERROR(uwrite(_params.pResult, response.errorCode)); - if (_params.numOutData > 0 && _params.pOutData->size < response.data.size()) { - return ErrorCode::INVAL; + + if (response.data.size() != _params.numOutData) { + ORBIS_LOG_ERROR(__FUNCTION__, "responses amount mismatch", + response.data.size(), _params.numOutData); } - if (_params.numOutData && _params.pOutData->size) { - ORBIS_RET_ON_ERROR(uwriteRaw(_params.pOutData->data, response.data.data(), - response.data.size())); - _params.pOutData->size = response.data.size(); + for (std::size_t i = 0; i < response.data.size(); ++i) { + if (response.data.size() > _params.numOutData) { + ORBIS_LOG_ERROR(__FUNCTION__, "too many responses", response.data.size(), + _params.numOutData); + break; + } + + IpmiBufferInfo _outData; + ORBIS_RET_ON_ERROR(uread(_outData, _params.pOutData + i)); + + auto &data = response.data[i]; + + if (_outData.capacity < data.size()) { + ORBIS_LOG_ERROR(__FUNCTION__, "too big response", _outData.capacity, + data.size()); + continue; + } + + ORBIS_LOG_ERROR(__FUNCTION__, i, _outData.data, _outData.capacity, + data.size()); + + _outData.size = data.size(); + ORBIS_RET_ON_ERROR(uwriteRaw(_outData.data, data.data(), data.size())); + ORBIS_RET_ON_ERROR(uwrite(_params.pOutData + i, _outData)); } - ORBIS_LOG_TODO(__FUNCTION__, "sync message response", client->name, - _params.method, response.errorCode, response.data.size()); return uwrite(result, 0); } @@ -822,10 +1011,10 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz) { struct IpmiClientConnectParams { - ptr arg0; - ptr arg1; + ptr userData; + ulong userDataLen; ptr status; - ptr arg3; + ptr arg3; }; static_assert(sizeof(IpmiClientConnectParams) == 0x20); @@ -847,17 +1036,10 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, IpmiClientConnectParams _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); - ORBIS_LOG_ERROR(__FUNCTION__, client->name, "connect"); - auto server = g_context.findIpmiServer(client->name); if (server == nullptr) { - ORBIS_LOG_ERROR(__FUNCTION__, "waiting for server", client->name); - - while (server == nullptr) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - server = g_context.findIpmiServer(client->name); - } + return SysResult::notAnError(ErrorCode::NOENT); } std::lock_guard clientLock(client->mutex); @@ -889,8 +1071,8 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, }; struct ConnectMessageHeader { - uint32_t pid; - uint32_t unk0; + uint32_t clientPid; + uint32_t clientKid; QueueStats sync; QueueStats async; uint numEventFlag; @@ -903,34 +1085,49 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, static_assert(sizeof(ConnectMessageHeader) == 0x150); - struct ConnectFields { - uint unk0; - uint unk1; - }; - - kvector message{sizeof(ConnectMessageHeader) + - sizeof(ConnectFields)}; + kvector message{ + sizeof(ConnectMessageHeader) + sizeof(uint) + + std::max(_params.userDataLen, 0x10)}; auto header = new (message.data()) ConnectMessageHeader{}; - header->pid = thread->tproc->pid; + header->clientPid = thread->tproc->pid; + header->clientKid = kid; - server->packets.push_back( - {{ - .userData = (ptr)static_cast(thread->tid), - .type = 1, - .clientKid = kid, - }, - std::move(message)}); + header->sync.maxOutstanding = 1; + header->sync.inDataSizeHardLimit = 0x10000; + header->sync.outDataSizeHardLimit = 0x10000; + header->async.maxOutstanding = 8; + header->async.inDataSizeHardLimit = 0x10000; + header->async.outDataSizeHardLimit = 0x10000; + header->numEventFlag = client->eventFlags.size(); + header->numMsgQueue = client->messageQueues.size(); + + for (auto &size : header->msgQueueSize) { + size = 0x10000; + } + + if (_params.userDataLen != 0) { + auto bufLoc = std::bit_cast(header + 1); + *std::bit_cast(bufLoc) = _params.userDataLen; + ORBIS_RET_ON_ERROR(ureadRaw(bufLoc + sizeof(uint), _params.userData, + _params.userDataLen)); + } + + server->packets.push_back({{ + .inputSize = static_cast(thread->tid), + .type = 1, + .clientKid = kid, + }, + 0, + nullptr, + std::move(message)}); server->receiveCv.notify_one(server->mutex); } - ORBIS_LOG_ERROR(__FUNCTION__, client->name, "connect: packet sent"); - while (client->session == nullptr) { client->sessionCv.wait(client->mutex); } - ORBIS_LOG_ERROR(__FUNCTION__, client->name, "connect: session created"); ORBIS_RET_ON_ERROR(uwrite(_params.status, 0)); // TODO { @@ -940,6 +1137,32 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, return uwrite(result, 0u); } +orbis::SysResult orbis::sysIpmiSessionGetClientAppId(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct IpmiGetUserDataParam { + ptr data; + }; + + if (paramsSz != sizeof(IpmiGetUserDataParam)) { + return ErrorCode::INVAL; + } + + auto session = + dynamic_cast(thread->tproc->ipmiMap.get(kid).get()); + + if (session == nullptr) { + return ErrorCode::INVAL; + } + + IpmiGetUserDataParam _params; + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + ORBIS_RET_ON_ERROR( + uwrite(_params.data, session->client->process->appInfo.appId)); + return uwrite(result, 0); +} + orbis::SysResult orbis::sysIpmiSessionGetUserData(Thread *thread, ptr result, uint kid, ptr params, @@ -990,6 +1213,31 @@ orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr result, return uwrite(result, 0); } +orbis::SysResult orbis::sysIpmiClientGetName(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + struct IpmiGetClientNameParams { + ptr name; + }; + + if (paramsSz != sizeof(IpmiGetClientNameParams)) { + return ErrorCode::INVAL; + } + + auto client = thread->tproc->ipmiMap.get(kid).cast(); + + if (client == nullptr) { + return ErrorCode::INVAL; + } + + IpmiGetClientNameParams _param; + ORBIS_RET_ON_ERROR(uread(_param, ptr(params))); + ORBIS_RET_ON_ERROR( + uwriteRaw(_param.name, client->name.c_str(), client->name.size() + 1)); + + return uwrite(result, 0); +} + orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread, ptr result, uint kid, ptr params, @@ -1015,10 +1263,6 @@ orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread, return ErrorCode::INVAL; } - ORBIS_LOG_TODO(__FUNCTION__, thread->tid, kid, client->name, _params.index, - _params.padding0, _params.patternSet, _params.mode, - _params.padding1, _params.pPatternSet, _params.pTimeout); - if (client->eventFlags.size() <= _params.index) { return ErrorCode::INVAL; } @@ -1030,17 +1274,20 @@ orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread, } auto &evf = client->eventFlags[_params.index]; - auto waitResult = - evf.wait(thread, _params.mode, _params.patternSet, &resultTimeout); + auto waitResult = evf.wait(thread, _params.mode, _params.patternSet, + _params.pTimeout != 0 ? &resultTimeout : nullptr); + + if (_params.pPatternSet != nullptr) { + ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, thread->evfResultPattern)); + } - // FIXME - // if (_params.pPatternSet != nullptr) { - // ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, thread->evfResultPattern)); - // } ORBIS_RET_ON_ERROR(uwrite(result, 0u)); if (_params.pTimeout != nullptr) { ORBIS_RET_ON_ERROR(uwrite(_params.pTimeout, resultTimeout)); } + if (waitResult == ErrorCode::TIMEDOUT) { + return SysResult::notAnError(ErrorCode::TIMEDOUT); + } return waitResult; } @@ -1072,10 +1319,6 @@ orbis::SysResult orbis::sysIpmiClientPollEventFlag(Thread *thread, return ErrorCode::INVAL; } - // ORBIS_LOG_TODO(__FUNCTION__, thread->tid, kid, client->name, _params.index, - // _params.padding0, _params.patternSet, _params.mode, - // _params.padding1, _params.pPatternSet); - if (client->eventFlags.size() <= _params.index) { return ErrorCode::INVAL; } @@ -1116,8 +1359,6 @@ orbis::SysResult orbis::sysIpmiSessionSetEventFlag(Thread *thread, return ErrorCode::INVAL; } - ORBIS_LOG_TODO(__FUNCTION__, session->client->name, _params.patternSet, - _params.index); auto client = session->client; if (client == nullptr) { return ErrorCode::INVAL; diff --git a/orbis-kernel/src/module.cpp b/orbis-kernel/src/module.cpp index 0bb103bf..f78e0c67 100644 --- a/orbis-kernel/src/module.cpp +++ b/orbis-kernel/src/module.cpp @@ -172,7 +172,7 @@ static orbis::SysResult doPltRelocation(orbis::Process *process, return orbis::ErrorCode::INVAL; } - *where = reinterpret_cast(defObj->base) + S; + *where = S ? reinterpret_cast(defObj->base) + S : 0; } return {}; } @@ -285,7 +285,7 @@ static orbis::SysResult doRelocation(orbis::Process *process, if (defObj == nullptr) { return orbis::ErrorCode::INVAL; } - *where = reinterpret_cast(defObj->base) + S + A; + *where = S ? reinterpret_cast(defObj->base) + S + A : 0; return {}; } return {}; @@ -295,7 +295,7 @@ static orbis::SysResult doRelocation(orbis::Process *process, if (defObj == nullptr) { return orbis::ErrorCode::INVAL; } - *where32 = reinterpret_cast(defObj->base) + S + A - P; + *where32 = S ? reinterpret_cast(defObj->base) + S + A - P : 0; return {}; } // case kRelCopy: @@ -306,7 +306,7 @@ static orbis::SysResult doRelocation(orbis::Process *process, if (defObj == nullptr) { return orbis::ErrorCode::INVAL; } - *where = reinterpret_cast(defObj->base) + S; + *where = S ? reinterpret_cast(defObj->base) + S : 0; return {}; } case kRelRelative: diff --git a/orbis-kernel/src/pipe.cpp b/orbis-kernel/src/pipe.cpp index ca207720..1458c0a7 100644 --- a/orbis-kernel/src/pipe.cpp +++ b/orbis-kernel/src/pipe.cpp @@ -47,7 +47,7 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, break; } - file->event.emit(orbis::kEvFiltWrite); + pipe->event->emit(orbis::kEvFiltWrite); return {}; } @@ -64,7 +64,7 @@ static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio, cnt += vec.len; } - file->event.emit(orbis::kEvFiltRead); + pipe->event->emit(orbis::kEvFiltRead); pipe->cv.notify_one(file->mtx); uio->resid -= cnt; uio->offset += cnt; @@ -82,6 +82,8 @@ static orbis::FileOps pipe_ops = { std::pair, orbis::Ref> orbis::createPipe() { auto a = knew(); auto b = knew(); + a->event = knew(); + b->event = knew(); a->ops = &pipe_ops; b->ops = &pipe_ops; a->other = b; diff --git a/orbis-kernel/src/sys/sys_context.cpp b/orbis-kernel/src/sys/sys_context.cpp index dd16c861..cfd0c2d6 100644 --- a/orbis-kernel/src/sys/sys_context.cpp +++ b/orbis-kernel/src/sys/sys_context.cpp @@ -1,15 +1,15 @@ #include "sys/sysproto.hpp" orbis::SysResult orbis::sys_getcontext(Thread *thread, - ptr ucp) { + ptr ucp) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_setcontext(Thread *thread, - ptr ucp) { + ptr ucp) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_swapcontext(Thread *thread, - ptr oucp, - ptr ucp) { + ptr oucp, + ptr ucp) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_descrip.cpp b/orbis-kernel/src/sys/sys_descrip.cpp index d4288620..300d72b9 100644 --- a/orbis-kernel/src/sys/sys_descrip.cpp +++ b/orbis-kernel/src/sys/sys_descrip.cpp @@ -1,6 +1,9 @@ +#include "file.hpp" #include "orbis/utils/Logs.hpp" #include "stat.hpp" #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" orbis::SysResult orbis::sys_getdtablesize(Thread *thread) { return ErrorCode::NOSYS; diff --git a/orbis-kernel/src/sys/sys_environment.cpp b/orbis-kernel/src/sys/sys_environment.cpp index e22a3de9..50f247f7 100644 --- a/orbis-kernel/src/sys/sys_environment.cpp +++ b/orbis-kernel/src/sys/sys_environment.cpp @@ -1,6 +1,7 @@ #include "sys/sysproto.hpp" #include "KernelContext.hpp" +#include "thread/Process.hpp" orbis::SysResult orbis::sys_kenv(Thread *thread, sint what, ptr name, ptr value, diff --git a/orbis-kernel/src/sys/sys_event.cpp b/orbis-kernel/src/sys/sys_event.cpp index 7c687cae..c69475a3 100644 --- a/orbis-kernel/src/sys/sys_event.cpp +++ b/orbis-kernel/src/sys/sys_event.cpp @@ -104,14 +104,20 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { return ErrorCode::BADF; } - std::unique_lock lock(fd->event.mutex); nodeIt->file = fd; - // if (change.filter == kEvFiltWrite) { - // nodeIt->triggered = true; - // kq->cv.notify_all(kq->mtx); - // } - fd->event.notes.insert(&*nodeIt); + if (auto eventEmitter = fd->event) { + std::unique_lock lock(eventEmitter->mutex); + // if (change.filter == kEvFiltWrite) { + // nodeIt->triggered = true; + // kq->cv.notify_all(kq->mtx); + // } + nodeIt->triggered = true; + eventEmitter->notes.insert(&*nodeIt); + kq->cv.notify_all(kq->mtx); + } else if (note.file->hostFd < 0) { + ORBIS_LOG_ERROR("Unimplemented event emitter", change.ident); + } } } } @@ -156,13 +162,23 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { (nodeIt->event.fflags & ~kNoteFFlagsMask) | (fflags & kNoteFFlagsMask); if (change.fflags & kNoteTrigger) { + nodeIt->event.udata = change.udata; nodeIt->triggered = true; kq->cv.notify_all(kq->mtx); } - } else if (change.filter == kEvFiltGraphicsCore || - change.filter == kEvFiltDisplay || change.filter == kEvFiltRegEv) { + } else if (change.filter == kEvFiltGraphicsCore) { nodeIt->triggered = true; + + if (change.ident == 0x84) { + // clock change event + nodeIt->event.data |= 1000ull << 16; // clock + } kq->cv.notify_all(kq->mtx); + } else if (change.filter == kEvFiltDisplay) { + if (change.ident != 0x51000100000000 && change.ident != 0x63010100000000) { + nodeIt->triggered = true; + kq->cv.notify_all(kq->mtx); + } } return {}; @@ -233,7 +249,7 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, auto now = clock::now(); auto nowValue = now.time_since_epoch().count(); - if (nowValue < nowValue + nsec) { + if (nowValue <= nowValue + nsec) { timeoutPoint = now + std::chrono::nanoseconds(nsec); } } @@ -242,76 +258,101 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, std::vector result; result.reserve(nevents); + ErrorCode errorCode{}; + if (kq->notes.empty()) { // ORBIS_LOG_ERROR(__FUNCTION__, "attempt to wait empty kqueue", fd, - // nevents, timeoutPoint.time_since_epoch().count()); thread->where(); + // nevents, + // timeoutPoint.time_since_epoch().count()); + // thread->where(); + // return{}; // std::abort(); return {}; } + // ORBIS_LOG_TODO(__FUNCTION__, "kevent wait", fd); + while (true) { bool waitHack = false; bool canSleep = true; - std::lock_guard lock(kq->mtx); - for (auto it = kq->notes.begin(); it != kq->notes.end();) { - if (result.size() >= nevents) { - break; - } - auto ¬e = *it; - std::lock_guard lock(note.mutex); + { + std::lock_guard lock(kq->mtx); + for (auto it = kq->notes.begin(); it != kq->notes.end();) { + if (result.size() >= nevents) { + break; + } - if (!note.triggered) { - if (note.event.filter == kEvFiltRead) { - if (note.file->hostFd < 0 || - isReadEventTriggered(note.file->hostFd)) { - note.triggered = true; - } else { - canSleep = false; - } - } else if (note.event.filter == kEvFiltWrite) { - if (note.file->hostFd < 0 || - isWriteEventTriggered(note.file->hostFd)) { - note.triggered = true; - } else { - canSleep = false; + auto ¬e = *it; + bool erase = false; + { + std::lock_guard lock(note.mutex); + + if (!note.triggered) { + if (note.event.filter == kEvFiltRead) { + if (note.file->hostFd >= 0 ) { + if (isReadEventTriggered(note.file->hostFd)) { + note.triggered = true; + } else { + canSleep = false; + } + } + } else if (note.event.filter == kEvFiltWrite) { + if (note.file->hostFd >= 0) { + if (isWriteEventTriggered(note.file->hostFd)) { + note.triggered = true; + } else { + canSleep = false; + } + } + } } - } - } - if (note.enabled && note.triggered) { - result.push_back(note.event); + if (note.enabled && note.triggered) { + result.push_back(note.event); - if (note.event.filter == kEvFiltGraphicsCore || - note.event.filter == kEvFiltDisplay) { - waitHack = true; - } + if (note.event.filter == kEvFiltGraphicsCore || + note.event.filter == kEvFiltDisplay) { + waitHack = true; + } + + if (note.event.flags & kEvDispatch) { + note.enabled = false; + } - if (note.event.flags & kEvDispatch) { - note.enabled = false; + if (note.event.flags & kEvOneshot) { + erase = true; + } + + if (note.event.filter == kEvFiltRead || note.event.filter == kEvFiltWrite) { + note.triggered = false; + } + } } - if (note.event.flags & kEvOneshot) { + if (erase) { it = kq->notes.erase(it); - continue; + } else { + ++it; } } - - ++it; } if (!result.empty()) { // if (waitHack) { - // std::this_thread::sleep_for(std::chrono::milliseconds(3)); + // std::this_thread::sleep_for(std::chrono::milliseconds(30)); // } break; } + if (timeoutPoint != clock::time_point::max()) { + std::lock_guard lock(kq->mtx); auto now = clock::now(); if (now >= timeoutPoint) { + errorCode = ErrorCode::TIMEDOUT; break; } @@ -322,13 +363,27 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, } } else { if (canSleep) { + std::lock_guard lock(kq->mtx); kq->cv.wait(kq->mtx); + } else { + std::this_thread::sleep_for(std::chrono::microseconds(30)); } } } // ORBIS_LOG_TODO(__FUNCTION__, "kevent wakeup", fd); + // for (auto evt : result) { + // ORBIS_LOG_TODO(__FUNCTION__, + // evt.ident, + // evt.filter, + // evt.flags, + // evt.fflags, + // evt.data, + // evt.udata + // ); + // } + ORBIS_RET_ON_ERROR( uwriteRaw(eventlist, result.data(), result.size() * sizeof(KEvent))); thread->retval[0] = result.size(); diff --git a/orbis-kernel/src/sys/sys_exec.cpp b/orbis-kernel/src/sys/sys_exec.cpp index 719d2250..cf423b5a 100644 --- a/orbis-kernel/src/sys/sys_exec.cpp +++ b/orbis-kernel/src/sys/sys_exec.cpp @@ -1,4 +1,7 @@ #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" +#include "thread/ProcessOps.hpp" orbis::SysResult orbis::sys_execve(Thread *thread, ptr fname, ptr> argv, ptr> envv) { diff --git a/orbis-kernel/src/sys/sys_exit.cpp b/orbis-kernel/src/sys/sys_exit.cpp index 2eb984fe..85d14419 100644 --- a/orbis-kernel/src/sys/sys_exit.cpp +++ b/orbis-kernel/src/sys/sys_exit.cpp @@ -1,11 +1,11 @@ #include "KernelContext.hpp" #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" #include "utils/Logs.hpp" -#include #include #include -#include #include +#include "thread/Process.hpp" orbis::SysResult orbis::sys_exit(Thread *thread, sint status) { if (auto exit = thread->tproc->ops->exit) { diff --git a/orbis-kernel/src/sys/sys_fork.cpp b/orbis-kernel/src/sys/sys_fork.cpp index 2747306e..4c70633e 100644 --- a/orbis-kernel/src/sys/sys_fork.cpp +++ b/orbis-kernel/src/sys/sys_fork.cpp @@ -1,5 +1,7 @@ #include "KernelContext.hpp" #include "sys/sysproto.hpp" +#include "thread/Process.hpp" +#include "thread/ProcessOps.hpp" #include #include diff --git a/orbis-kernel/src/sys/sys_generic.cpp b/orbis-kernel/src/sys/sys_generic.cpp index fdcc40f3..cc8a8189 100644 --- a/orbis-kernel/src/sys/sys_generic.cpp +++ b/orbis-kernel/src/sys/sys_generic.cpp @@ -1,5 +1,8 @@ +#include "file.hpp" #include "orbis/utils/Logs.hpp" #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" #include "uio.hpp" #include @@ -39,11 +42,13 @@ orbis::SysResult orbis::sys_read(Thread *thread, sint fd, ptr buf, auto cnt = io.offset - file->nextOff; file->nextOff = io.offset; + // ORBIS_LOG_ERROR(__FUNCTION__, fd, buf, nbyte, cnt); thread->retval[0] = cnt; return {}; } orbis::SysResult orbis::sys_pread(Thread *thread, sint fd, ptr buf, size_t nbyte, off_t offset) { + // ORBIS_LOG_ERROR(__FUNCTION__, fd, buf, nbyte, offset); Ref file = thread->tproc->fileDescriptors.get(fd); if (file == nullptr) { return ErrorCode::BADF; diff --git a/orbis-kernel/src/sys/sys_p1003_1b.cpp b/orbis-kernel/src/sys/sys_p1003_1b.cpp index ca4a9bd2..69d0ce19 100644 --- a/orbis-kernel/src/sys/sys_p1003_1b.cpp +++ b/orbis-kernel/src/sys/sys_p1003_1b.cpp @@ -1,4 +1,5 @@ #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" #include "utils/Logs.hpp" #include diff --git a/orbis-kernel/src/sys/sys_pipe.cpp b/orbis-kernel/src/sys/sys_pipe.cpp index f14c6203..0c959e96 100644 --- a/orbis-kernel/src/sys/sys_pipe.cpp +++ b/orbis-kernel/src/sys/sys_pipe.cpp @@ -1,4 +1,6 @@ #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" #include "utils/Logs.hpp" #include diff --git a/orbis-kernel/src/sys/sys_prot.cpp b/orbis-kernel/src/sys/sys_prot.cpp index 7ea95b91..4ec23efb 100644 --- a/orbis-kernel/src/sys/sys_prot.cpp +++ b/orbis-kernel/src/sys/sys_prot.cpp @@ -1,4 +1,6 @@ #include "sys/sysproto.hpp" +#include "thread/Process.hpp" +#include "thread/Thread.hpp" #include "utils/Logs.hpp" orbis::SysResult orbis::sys_getpid(Thread *thread) { @@ -16,7 +18,10 @@ orbis::SysResult orbis::sys_getpgid(Thread *thread, pid_t pid) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_getsid(Thread *thread, pid_t pid) { return {}; } -orbis::SysResult orbis::sys_getuid(Thread *thread) { return ErrorCode::NOSYS; } +orbis::SysResult orbis::sys_getuid(Thread *thread) { + thread->retval[0] = 1; + return {}; +} orbis::SysResult orbis::sys_geteuid(Thread *thread) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_getgid(Thread *thread) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_getegid(Thread *thread) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_resource.cpp b/orbis-kernel/src/sys/sys_resource.cpp index 8b868f66..5bb10ba9 100644 --- a/orbis-kernel/src/sys/sys_resource.cpp +++ b/orbis-kernel/src/sys/sys_resource.cpp @@ -1,4 +1,5 @@ #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" #include "utils/Logs.hpp" namespace orbis { @@ -88,5 +89,5 @@ orbis::SysResult orbis::sys_getrlimit(Thread *thread, uint which, } orbis::SysResult orbis::sys_getrusage(Thread *thread, sint who, ptr rusage) { - return ErrorCode::NOSYS; + return {}; } diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index 0a0f0e47..c263e4ca 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -8,10 +8,16 @@ #include "orbis/time.hpp" #include "osem.hpp" #include "sys/sysproto.hpp" +#include "thread/Process.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "ucontext.hpp" +#include "uio.hpp" #include "utils/Logs.hpp" #include #include #include +#include orbis::SysResult orbis::sys_netcontrol(Thread *thread, sint fd, uint op, ptr buf, uint nbuf) { @@ -63,24 +69,33 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, // ORBIS_LOG_ERROR(__FUNCTION__, op, id, len); // thread->where(); + std::lock_guard lock(orbis::g_context.regMgrMtx); + + if (op == 1) { + // set int + if (len != sizeof(uint32_t)) { + return ErrorCode::INVAL; + } + + ORBIS_LOG_ERROR(__FUNCTION__, op, id, *(std::uint32_t *)value); + g_context.regMgrInt[id] = *(std::uint32_t *)value; + return {}; + } if (op == 2) { // get int if (len != sizeof(uint32_t)) { return ErrorCode::INVAL; } - if (id == 0x2010000) { - return uwrite((ptr)value, 0u); - } - if (id == 0x7802c000) { - return uwrite((ptr)value, 0u); - } - if (id == 0x78020500) { - return uwrite((ptr)value, 0u); - } - if (id == 0x78020b00) { + auto intValIt = g_context.regMgrInt.find(id); + if (intValIt == g_context.regMgrInt.end()) { + ORBIS_LOG_ERROR("registry int entry not exists", op, id, len); + thread->where(); + // return ErrorCode::NOENT; return uwrite((ptr)value, 0u); + return {}; } + return uwrite((ptr)value, intValIt->second); return {}; } @@ -93,6 +108,8 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, return ErrorCode::INVAL; } + std::memset(value, 0, len); + ORBIS_LOG_ERROR(__FUNCTION__, op, id, len); thread->where(); return {}; @@ -319,8 +336,8 @@ orbis::SysResult orbis::sys_evf_trywait(Thread *thread, sint id, } auto result = evf->tryWait(thread, mode, patternSet); - ORBIS_LOG_TRACE(__FUNCTION__, evf->name, thread->tid, id, patternSet, mode, - pPatternSet, result); + ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, evf->name, thread->tid, id, + patternSet, mode, pPatternSet, result); if (pPatternSet != nullptr) { ORBIS_RET_ON_ERROR(uwrite(pPatternSet, thread->evfResultPattern)); @@ -670,7 +687,9 @@ orbis::SysResult orbis::sys_namedobj_delete(Thread *thread, uint id, return {}; } orbis::SysResult orbis::sys_set_vm_container(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; + ORBIS_LOG_TODO(__FUNCTION__); + thread->where(); + return {}; } orbis::SysResult orbis::sys_debug_init(Thread *thread /* TODO */) { return ErrorCode::NOSYS; @@ -956,7 +975,21 @@ orbis::SysResult orbis::sys_mdbg_service(Thread *thread, uint32_t op, } case 7: { - // TODO: read string from userspace + if (auto open = thread->tproc->ops->open) { + Ref console; + auto result = open(thread, "/dev/console", 0, 0, &console); + if (!result.value() && console && console->ops->write) { + IoVec vec{.base = (char *)arg0, .len = std::strlen((char *)arg0)}; + + Uio uio{ + .iov = &vec, + .iovcnt = 1, + }; + if (console->ops->write(console.get(), &uio, thread) == ErrorCode{}) { + return {}; + } + } + } ORBIS_LOG_NOTICE("sys_mdbg_service", (char *)arg0); break; } @@ -1189,6 +1222,8 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, case 0x241: return sysIpmiClientInvokeAsyncMethod(thread, result, kid, params, paramsSz); + case 0x242: + return sysImpiSessionRespondAsync(thread, result, kid, params, paramsSz); case 0x243: return sysIpmiClientTryGetResult(thread, result, kid, params, paramsSz); case 0x251: @@ -1205,10 +1240,14 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, return sysIpmiClientInvokeSyncMethod(thread, result, kid, params, paramsSz); case 0x400: return sysIpmiClientConnect(thread, result, kid, params, paramsSz); + case 0x463: + return sysIpmiSessionGetClientAppId(thread, result, kid, params, paramsSz); case 0x468: return sysIpmiSessionGetUserData(thread, result, kid, params, paramsSz); case 0x46a: return sysIpmiServerGetName(thread, result, kid, params, paramsSz); + case 0x46b: + return sysIpmiClientGetName(thread, result, kid, params, paramsSz); case 0x490: return sysIpmiClientWaitEventFlag(thread, result, kid, params, paramsSz); case 0x491: @@ -1279,15 +1318,85 @@ orbis::SysResult orbis::sys_resume_internal_hdd(Thread *thread /* TODO */) { } orbis::SysResult orbis::sys_thr_suspend_ucontext(Thread *thread, lwpid_t tid) { // ORBIS_LOG_FATAL(__FUNCTION__, tid); + auto t = tid == thread->tid ? thread + : thread->tproc->threadsMap.get(tid % 10000 - 1); + if (t == nullptr) { + return ErrorCode::SRCH; + } + + while (true) { + unsigned prevSuspend = 0; + if (t->suspended.compare_exchange_strong(prevSuspend, 1)) { + t->suspend(); + + while (t->suspended == 0) { + std::this_thread::yield(); + } + + break; + } + + if (t->suspended.compare_exchange_strong(prevSuspend, prevSuspend + 1)) { + break; + } + } + return {}; } orbis::SysResult orbis::sys_thr_resume_ucontext(Thread *thread, lwpid_t tid) { // ORBIS_LOG_FATAL(__FUNCTION__, tid); + auto t = tid == thread->tid ? thread + : thread->tproc->threadsMap.get(tid % 10000 - 1); + if (t == nullptr) { + return ErrorCode::SRCH; + } + + while (true) { + unsigned prevSuspend = 1; + if (t->suspended.compare_exchange_strong(prevSuspend, 0)) { + t->resume(); + + while (t->suspended != 0) { + std::this_thread::yield(); + } + + break; + } + + if (prevSuspend == 0) { + return ErrorCode::INVAL; + } + + if (t->suspended.compare_exchange_strong(prevSuspend, prevSuspend - 1)) { + break; + } + } return {}; } orbis::SysResult orbis::sys_thr_get_ucontext(Thread *thread, lwpid_t tid, ptr context) { // ORBIS_LOG_FATAL(__FUNCTION__, tid, context); + + auto t = tid == thread->tid ? thread + : thread->tproc->threadsMap.get(tid % 10000 - 1); + if (t == nullptr) { + return ErrorCode::SRCH; + } + + std::lock_guard lock(t->mtx); + + if (t->suspended == 0) { + return ErrorCode::INVAL; + } + + for (auto it = t->sigReturns.rbegin(); it != t->sigReturns.rend(); ++it) { + auto &savedContext = t->sigReturns.back(); + if (savedContext.mcontext.rip < 0x100'0000'0000) { + return uwrite(context, savedContext); + } + } + ORBIS_LOG_FATAL(__FUNCTION__, "not found guest context"); + *context = {}; return {}; } orbis::SysResult orbis::sys_thr_set_ucontext(Thread *thread, lwpid_t tid, @@ -1296,7 +1405,9 @@ orbis::SysResult orbis::sys_thr_set_ucontext(Thread *thread, lwpid_t tid, return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_set_timezone_info(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; + ORBIS_LOG_ERROR(__FUNCTION__); + thread->where(); + return {}; } orbis::SysResult orbis::sys_set_phys_fmem_limit(Thread *thread /* TODO */) { return ErrorCode::NOSYS; @@ -1423,7 +1534,9 @@ orbis::SysResult orbis::sys_blockpool_batch(Thread *thread /* TODO */) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_fdatasync(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; + ORBIS_LOG_TODO(__FUNCTION__); + thread->where(); + return {}; } orbis::SysResult orbis::sys_dynlib_get_list2(Thread *thread /* TODO */) { return ErrorCode::NOSYS; diff --git a/orbis-kernel/src/sys/sys_sig.cpp b/orbis-kernel/src/sys/sys_sig.cpp index 1207a48b..fac5550e 100644 --- a/orbis-kernel/src/sys/sys_sig.cpp +++ b/orbis-kernel/src/sys/sys_sig.cpp @@ -1,67 +1,90 @@ #include "KernelContext.hpp" #include "sys/sysproto.hpp" +#include "thread/Process.hpp" +#include "thread/Thread.hpp" +#include "ucontext.hpp" #include "utils/Logs.hpp" #include orbis::SysResult orbis::sys_sigaction(Thread *thread, sint sig, - ptr act, - ptr oact) { + ptr act, ptr oact) { + ORBIS_LOG_WARNING(__FUNCTION__, sig, act, oact); + + auto &sigAct = thread->tproc->sigActions[sig]; + if (oact != nullptr) { + if (auto errc = uwrite(oact, sigAct); errc != orbis::ErrorCode{}) { + return errc; + } + } + + if (act != nullptr) { + if (auto errc = uread(sigAct, act); errc != ErrorCode{}) { + return errc; + } + + ORBIS_LOG_WARNING(__FUNCTION__, sigAct.handler, sigAct.flags, + sigAct.mask.bits[0], sigAct.mask.bits[1], + sigAct.mask.bits[2], sigAct.mask.bits[3]); + } + return {}; } + orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how, - ptr set, ptr oset) { + ptr set, ptr oset) { if (oset) { - for (std::size_t i = 0; i < 2; ++i) { - oset[i] = thread->sigMask[i]; - } + ORBIS_RET_ON_ERROR(uwrite(oset, thread->sigMask)); } if (set) { + SigSet _set; + ORBIS_RET_ON_ERROR(uread(_set, set)); + switch (how) { - case 0: // unblock - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] &= ~set[i]; - } case 1: // block - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] |= set[i]; + for (std::size_t i = 0; i < 4; ++i) { + thread->sigMask.bits[i] |= _set.bits[i]; } break; - case 3: // set - for (std::size_t i = 0; i < 2; ++i) { - thread->sigMask[i] = set[i]; + + case 2: // unblock + for (std::size_t i = 0; i < 4; ++i) { + thread->sigMask.bits[i] &= ~_set.bits[i]; } break; + case 3: // set + thread->sigMask = _set; + break; default: ORBIS_LOG_ERROR("sys_sigprocmask: unimplemented how", how); thread->where(); - return {}; + return ErrorCode::INVAL; } + + thread->sigMask.clear(kSigKill); + thread->sigMask.clear(kSigStop); } + return {}; } -orbis::SysResult orbis::sys_sigwait(Thread *thread, - ptr set, +orbis::SysResult orbis::sys_sigwait(Thread *thread, ptr set, ptr sig) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigtimedwait(Thread *thread, - ptr set, +orbis::SysResult orbis::sys_sigtimedwait(Thread *thread, ptr set, ptr info, ptr timeout) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigwaitinfo(Thread *thread, - ptr set, +orbis::SysResult orbis::sys_sigwaitinfo(Thread *thread, ptr set, ptr info) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigpending(Thread *thread, ptr set) { +orbis::SysResult orbis::sys_sigpending(Thread *thread, ptr set) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigsuspend(Thread *thread, - ptr set) { +orbis::SysResult orbis::sys_sigsuspend(Thread *thread, ptr set) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_sigaltstack(Thread *thread, ptr ss, @@ -69,7 +92,7 @@ orbis::SysResult orbis::sys_sigaltstack(Thread *thread, ptr ss, return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) { - ORBIS_LOG_ERROR(__FUNCTION__, pid, signum); + ORBIS_LOG_WARNING(__FUNCTION__, pid, signum); int hostPid = pid; if (pid > 0) { @@ -81,10 +104,10 @@ orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) { } // TODO: wrap signal - int result = ::kill(hostPid, signum); - if (result < 0) { - return static_cast(errno); - } + // int result = ::kill(hostPid, signum); + // if (result < 0) { + // return static_cast(errno); + // } return {}; } @@ -96,8 +119,18 @@ orbis::SysResult orbis::sys_sigqueue(Thread *thread, pid_t pid, sint signum, ptr value) { return ErrorCode::NOSYS; } -orbis::SysResult orbis::sys_sigreturn(Thread *thread, - ptr sigcntxp) { - return ErrorCode::NOSYS; +orbis::SysResult orbis::sys_sigreturn(Thread *thread, ptr sigcntxp) { + ORBIS_LOG_WARNING(__FUNCTION__, sigcntxp); + + // auto sigRet = thread->sigReturns.front(); + // thread->sigReturns.erase(thread->sigReturns.begin(), thread->sigReturns.begin() + 1); + // writeRegister(thread->context, RegisterId::rip, sigRet.rip); + // writeRegister(thread->context, RegisterId::rsp, sigRet.rsp); + // ORBIS_LOG_ERROR(__FUNCTION__, sigRet.rip, sigRet.rsp); + return {}; +} + +orbis::SysResult orbis::nosys(Thread *thread) { + thread->sendSignal(kSigSys); + return{}; } -orbis::SysResult orbis::nosys(Thread *thread) { return ErrorCode::NOSYS; } diff --git a/orbis-kernel/src/sys/sys_sysctl.cpp b/orbis-kernel/src/sys/sys_sysctl.cpp index 60ccd2b9..80c14567 100644 --- a/orbis-kernel/src/sys/sys_sysctl.cpp +++ b/orbis-kernel/src/sys/sys_sysctl.cpp @@ -1,16 +1,20 @@ #include "KernelContext.hpp" #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" +#include "time.hpp" #include "utils/Logs.hpp" -orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, - uint namelen, ptr old, - ptr oldlenp, ptr new_, - size_t newlen) { +namespace orbis { +SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, + ptr old, ptr oldlenp, ptr new_, + size_t newlen) { enum sysctl_ctl { unspec, kern, vm, vfs, net, debug, hw, machdep, user }; enum sysctl_kern { - usrstack = 33, proc = 14, + boottime = 21, + usrstack = 33, arnd = 37, // FIXME @@ -22,10 +26,12 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, rng_pseudo, backup_restore_mode, console, - init_safe_mode + init_safe_mode, + geom, }; enum sysctl_hw { + ncpu = 3, pagesize = 7, // FIXME @@ -49,6 +55,8 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, tsc_freq = 1000, liverpool, bootparams, + idps, + openpsid_for_sys, }; enum sysctl_machdep_liverpool { @@ -59,6 +67,10 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, is_main_on_standby = 1000, }; + enum sysctl_kern_geom { + updtfmt = 1000, + }; + struct ProcInfo { char data[0x448]; }; @@ -139,9 +151,47 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, *(uint64_t *)old = 0; return {}; } + + if (name[0] == kern && name[1] == geom && name[2] == updtfmt) { + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { + return ErrorCode::INVAL; + } + + *(uint32_t *)old = 0; + return {}; + } } if (namelen == 4) { + if (name[0] == kern && name[1] == proc && name[2] == 37) { + if (oldlenp && old && *oldlenp == 4) { + return uwrite(ptr(old), ~0u); + } + } + + if (name[0] == kern && name[1] == proc && name[2] == 36) { + Process *process = thread->tproc; + if (process->pid != name[3]) { + process = g_context.findProcessById(name[3]); + if (process == nullptr) { + ORBIS_LOG_ERROR("get sdk version by pid: process not found", name[3], + thread->tproc->pid); + return ErrorCode::SRCH; + } + } + + size_t oldlen; + ORBIS_RET_ON_ERROR(uread(oldlen, oldlenp)); + + if (oldlen < sizeof(uint32_t)) { + return ErrorCode::INVAL; + } + + ORBIS_RET_ON_ERROR(uwrite(ptr(old), process->sdkVersion)); + ORBIS_LOG_ERROR("get sdk version by pid", name[3], process->sdkVersion); + return uwrite(oldlenp, sizeof(uint32_t)); + } + if (name[0] == kern && name[1] == proc && name[2] == 1) { ORBIS_LOG_ERROR("KERN_PROC_PROC 2"); @@ -388,6 +438,31 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, dest[count++] = hw; dest[count++] = config; dest[count++] = optical_out; + } else if (searchName == "machdep.idps") { + if (*oldlenp < 2 * sizeof(uint32_t)) { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = machdep; + dest[count++] = idps; + } else if (searchName == "kern.geom.updtfmt") { + if (*oldlenp < 3 * sizeof(uint32_t)) { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = kern; + dest[count++] = geom; + dest[count++] = updtfmt; + } else if (searchName == "machdep.openpsid_for_sys") { + if (*oldlenp < 2 * sizeof(uint32_t)) { + std::fprintf(stderr, " %s error\n", searchName.data()); + return ErrorCode::INVAL; + } + + dest[count++] = machdep; + dest[count++] = openpsid_for_sys; } if (count == 0) { @@ -409,6 +484,19 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, case sysctl_ctl::kern: switch (name[1]) { + case sysctl_kern::boottime: { + // FIXME: implement boottime support + if (*oldlenp < sizeof(timeval) || new_ != nullptr || newlen != 0) { + return ErrorCode::INVAL; + } + + *oldlenp = sizeof(timeval); + *ptr(old) = { + .tv_sec = 60, + .tv_usec = 0, + }; + return {}; + } case sysctl_kern::usrstack: { if (*oldlenp != 8 || new_ != nullptr || newlen != 0) { return ErrorCode::INVAL; @@ -424,7 +512,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, return ErrorCode::INVAL; } - *(uint32_t *)old = 1; + *(uint32_t *)old = 6; return {}; case sysctl_kern::sdk_version: { @@ -432,8 +520,8 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, return ErrorCode::INVAL; } - std::printf("Reporting SDK version %x\n", g_context.sdkVersion); - *(uint32_t *)old = g_context.sdkVersion; + std::printf("Reporting SDK version %x\n", thread->tproc->sdkVersion); + *(uint32_t *)old = thread->tproc->sdkVersion; return {}; } @@ -501,6 +589,22 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, *(std::uint32_t *)old = 0; return {}; + case sysctl_kern::init_safe_mode: + if (old && oldlenp) { + ORBIS_LOG_ERROR("sysctl: get kern.init_safe_mode", oldlenp, new_, + newlen); + if (*oldlenp != 4) { + return ErrorCode::INVAL; + } + + *(std::uint32_t *)old = g_context.safeMode; + } + if (new_ != nullptr && newlen == 4) { + ORBIS_LOG_ERROR("sysctl: set kern.init_safe_mode", + *(std::uint32_t *)new_, newlen); + } + return {}; + default: return ErrorCode::INVAL; } @@ -550,6 +654,15 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, *(uint32_t *)old = 0x4000; return {}; + case sysctl_hw::ncpu: + if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { + + } else { + + *(uint32_t *)old = 7; + return {}; + } + default: break; } @@ -562,13 +675,37 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, return ErrorCode::INVAL; } - *(uint64_t *)old = g_context.getTscFreq(); + if (std::string_view((char *)thread->tproc->appInfo.titleId) == + "NPXS20973") { + ORBIS_LOG_ERROR("get tsc freq: returning patched value"); + *(uint64_t *)old = 1000000; + } else { + *(uint64_t *)old = g_context.getTscFreq(); + } + return {}; + } + + case sysctl_machdep::idps: { + if (*oldlenp != 16 || new_ != nullptr || newlen != 0) { + return ErrorCode::INVAL; + } + + std::memset(old, 0, 16); + return uwrite((short *)((char *)old + 4), 0x8401); + } + + case sysctl_machdep::openpsid_for_sys: { + if (*oldlenp != 16 || new_ != nullptr || newlen != 0) { + return ErrorCode::INVAL; + } + + std::memset(old, 0, 16); return {}; + } default: break; } - } case sysctl_ctl::user: break; } @@ -588,3 +725,29 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, thread->where(); return {}; } +} // namespace orbis + +orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, + uint namelen, ptr old, + ptr oldlenp, ptr new_, + size_t newlen) { + + auto result = kern_sysctl(thread, name, namelen, old, oldlenp, new_, newlen); + + if (result.isError()) { + std::string concatName; + for (unsigned int i = 0; i < namelen; ++i) { + if (i != 0) { + concatName += '.'; + } + + concatName += std::to_string(name[i]); + } + + std::size_t oldLen = oldlenp ? *oldlenp : 0; + ORBIS_LOG_TODO(__FUNCTION__, concatName, oldLen, new_, newlen); + thread->where(); + } + + return result; +} \ No newline at end of file diff --git a/orbis-kernel/src/sys/sys_thr.cpp b/orbis-kernel/src/sys/sys_thr.cpp index d377f4b5..d5f3d694 100644 --- a/orbis-kernel/src/sys/sys_thr.cpp +++ b/orbis-kernel/src/sys/sys_thr.cpp @@ -1,7 +1,11 @@ #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" +#include "ucontext.hpp" orbis::SysResult orbis::sys_thr_create(Thread *thread, - ptr ctxt, + ptr ctxt, ptr arg, sint flags) { if (auto thr_create = thread->tproc->ops->thr_create) { return thr_create(thread, ctxt, arg, flags); diff --git a/orbis-kernel/src/sys/sys_time.cpp b/orbis-kernel/src/sys/sys_time.cpp index cd671b69..82c6f49f 100644 --- a/orbis-kernel/src/sys/sys_time.cpp +++ b/orbis-kernel/src/sys/sys_time.cpp @@ -1,7 +1,7 @@ #include "sys/sysproto.hpp" #include "time.hpp" #include "utils/Logs.hpp" -#include +#include enum class ClockId { Realtime = 0, diff --git a/orbis-kernel/src/sys/sys_uipc.cpp b/orbis-kernel/src/sys/sys_uipc.cpp index 6918ea5e..1d04ffed 100644 --- a/orbis-kernel/src/sys/sys_uipc.cpp +++ b/orbis-kernel/src/sys/sys_uipc.cpp @@ -1,4 +1,8 @@ +#include "file.hpp" #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" #include "uio.hpp" #include "utils/Logs.hpp" #include diff --git a/orbis-kernel/src/sys/sys_uipc_shm.cpp b/orbis-kernel/src/sys/sys_uipc_shm.cpp index f9714305..7883d0cd 100644 --- a/orbis-kernel/src/sys/sys_uipc_shm.cpp +++ b/orbis-kernel/src/sys/sys_uipc_shm.cpp @@ -1,5 +1,9 @@ +#include "file.hpp" #include "orbis-config.hpp" #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" orbis::SysResult orbis::sys_shm_open(Thread *thread, ptr path, sint flags, mode_t mode) { diff --git a/orbis-kernel/src/sys/sys_umtx.cpp b/orbis-kernel/src/sys/sys_umtx.cpp index df785d85..457b0532 100644 --- a/orbis-kernel/src/sys/sys_umtx.cpp +++ b/orbis-kernel/src/sys/sys_umtx.cpp @@ -1,5 +1,6 @@ #include "orbis/utils/Logs.hpp" #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" #include "time.hpp" #include "umtx.hpp" #include diff --git a/orbis-kernel/src/sys/sys_vfs.cpp b/orbis-kernel/src/sys/sys_vfs.cpp index cc476579..5d28963d 100644 --- a/orbis-kernel/src/sys/sys_vfs.cpp +++ b/orbis-kernel/src/sys/sys_vfs.cpp @@ -1,5 +1,8 @@ #include "stat.hpp" #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" #include "utils/Logs.hpp" #include #include @@ -26,7 +29,7 @@ orbis::SysResult orbis::sys_statfs(Thread *thread, ptr path, return {}; } - std::strncpy(buf->f_fstypename, "exfatfs", sizeof(buf->f_fstypename)); + std::strncpy(buf->f_fstypename, "unionfs", sizeof(buf->f_fstypename)); std::strncpy(buf->f_mntfromname, "/dev/super-hdd", sizeof(buf->f_mntfromname)); std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname)); @@ -41,7 +44,7 @@ orbis::SysResult orbis::sys_fstatfs(Thread *thread, sint fd, return {}; } - std::strncpy(buf->f_fstypename, "exfatfs", sizeof(buf->f_fstypename)); + std::strncpy(buf->f_fstypename, "unionfs", sizeof(buf->f_fstypename)); std::strncpy(buf->f_mntfromname, "/dev/super-hdd", sizeof(buf->f_mntfromname)); std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname)); @@ -66,7 +69,9 @@ orbis::SysResult orbis::sys_chroot(Thread *thread, ptr path) { thread->tproc->root = path; return {}; } -orbis::SysResult orbis::sys_open(Thread *thread, ptr path, sint flags, + +// volatile bool debuggerPresent = false; +orbis::SysResult orbis::sys_open(Thread *thread, ptr path, sint flags, sint mode) { if (auto open = thread->tproc->ops->open) { Ref file; @@ -77,7 +82,17 @@ orbis::SysResult orbis::sys_open(Thread *thread, ptr path, sint flags, auto fd = thread->tproc->fileDescriptors.insert(file); thread->retval[0] = fd; - // ORBIS_LOG_NOTICE(__FUNCTION__, path, flags, mode, fd); + // if (path == std::string_view{"/app0/psm/Application/resource/Sce.Vsh.ShellUI.SystemMessage.rco"}) { + ORBIS_LOG_SUCCESS(__FUNCTION__, thread->tid, path, flags, mode, fd); + if (path == std::string_view{"/app0/wave/wave1.fbxd"}) { + thread->where(); + } + + // while (debuggerPresent == false) { + // std::this_thread::sleep_for(std::chrono::seconds(1)); + // } + // // thread->where(); + // } return {}; } @@ -85,6 +100,23 @@ orbis::SysResult orbis::sys_open(Thread *thread, ptr path, sint flags, } orbis::SysResult orbis::sys_openat(Thread *thread, sint fd, ptr path, sint flag, mode_t mode) { + ORBIS_LOG_WARNING(__FUNCTION__, fd, path, flag, mode); + + if (fd == -100) { + std::string cwd; + { + std::lock_guard lock(thread->tproc->mtx); + cwd = std::string(thread->tproc->cwd); + } + + return sys_open(thread, (cwd + "/" + path).c_str(), flag, mode); + } + + Ref file = thread->tproc->fileDescriptors.get(fd); + if (file == nullptr) { + return ErrorCode::BADF; + } + return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_mknod(Thread *thread, ptr path, sint mode, @@ -171,6 +203,7 @@ orbis::SysResult orbis::sys_lseek(Thread *thread, sint fd, off_t offset, return ErrorCode::NOSYS; } + ORBIS_LOG_ERROR(__FUNCTION__, fd, offset, whence, file->nextOff); thread->retval[0] = file->nextOff; return {}; } @@ -195,6 +228,7 @@ orbis::SysResult orbis::sys_eaccess(Thread *thread, ptr path, return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_stat(Thread *thread, ptr path, ptr ub) { + ORBIS_LOG_WARNING(__FUNCTION__, path); Ref file; auto result = thread->tproc->ops->open(thread, path, 0, 0, &file); if (result.isError()) { @@ -246,7 +280,21 @@ orbis::SysResult orbis::sys_lpathconf(Thread *thread, ptr path, } orbis::SysResult orbis::sys_readlink(Thread *thread, ptr path, ptr buf, size_t count) { - return ErrorCode::INVAL; + char _path[1024]; + ORBIS_RET_ON_ERROR(ureadString(_path, sizeof(_path), path)); + auto pathLen = std::strlen(_path); + if (pathLen > count) { + return ErrorCode::NAMETOOLONG; + } + + Ref file; + if (auto error = thread->tproc->ops->open(thread, path, 0, 0, &file); error.value()) { + return error; + } + + ORBIS_RET_ON_ERROR(uwriteRaw(buf, _path, pathLen)); + thread->retval[0] = pathLen; + return{}; } orbis::SysResult orbis::sys_readlinkat(Thread *thread, sint fd, ptr path, ptr buf, size_t bufsize) { @@ -390,6 +438,10 @@ orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd, if (result.isError()) return result; + for (auto &entry : std::span(entries + pos, next - pos)) { + ORBIS_LOG_ERROR(__FUNCTION__, entry.name); + } + if (basep) { result = uwrite(basep, slong(file->nextOff)); if (result.isError()) diff --git a/orbis-kernel/src/sys/sys_vfs_cache.cpp b/orbis-kernel/src/sys/sys_vfs_cache.cpp index b4aa4a71..1455c965 100644 --- a/orbis-kernel/src/sys/sys_vfs_cache.cpp +++ b/orbis-kernel/src/sys/sys_vfs_cache.cpp @@ -1,6 +1,23 @@ #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" +#include +#include orbis::SysResult orbis::sys___getcwd(Thread *thread, ptr buf, uint buflen) { - return ErrorCode::NOSYS; + + std::string cwd; + + { + std::lock_guard lock(thread->tproc->mtx); + cwd = std::string(thread->tproc->cwd); + } + + if (buflen < cwd.size() + 1) { + return ErrorCode::NOMEM; + } + + ORBIS_RET_ON_ERROR(uwriteRaw(buf, cwd.data(), cwd.size() + 1)); + return{}; } diff --git a/orbis-kernel/src/sys/sys_vfs_mount.cpp b/orbis-kernel/src/sys/sys_vfs_mount.cpp index 6797f34b..2bb249ef 100644 --- a/orbis-kernel/src/sys/sys_vfs_mount.cpp +++ b/orbis-kernel/src/sys/sys_vfs_mount.cpp @@ -1,4 +1,7 @@ #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" orbis::SysResult orbis::sys_mount(Thread *thread, ptr type, ptr path, sint flags, caddr_t data) { diff --git a/orbis-kernel/src/sys/sys_vm_mmap.cpp b/orbis-kernel/src/sys/sys_vm_mmap.cpp index fa074841..da11ea11 100644 --- a/orbis-kernel/src/sys/sys_vm_mmap.cpp +++ b/orbis-kernel/src/sys/sys_vm_mmap.cpp @@ -1,5 +1,8 @@ #include "error.hpp" #include "sys/sysproto.hpp" +#include "thread/ProcessOps.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" orbis::SysResult orbis::sys_sbrk(Thread *, sint) { return ErrorCode::OPNOTSUPP; diff --git a/orbis-kernel/src/sysvec.cpp b/orbis-kernel/src/sysvec.cpp index 8eb1bfb8..2430f027 100644 --- a/orbis-kernel/src/sysvec.cpp +++ b/orbis-kernel/src/sysvec.cpp @@ -1,6 +1,8 @@ #include "sys/syscall.hpp" #include "sys/sysentry.hpp" #include "sys/sysproto.hpp" +#include "thread/Thread.hpp" +#include "thread/Process.hpp" #include #include diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index 6bb52a03..406e4a48 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -33,7 +33,7 @@ uint UmtxChain::notify_one(const UmtxKey &key) { if (it == sleep_queue.end()) return 0; it->second.thr = nullptr; - it->second.cv.notify_one(mtx); + it->second.cv.notify_all(mtx); this->erase(&*it); return 1; } @@ -62,7 +62,7 @@ orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr umtx, orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr addr, ulong id, std::uint64_t ut, bool is32, bool ipc) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, id, ut, is32); + ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, addr, id, ut, is32); auto [chain, key, lock] = g_context.getUmtxChain0(thread, ipc, addr); auto node = chain.enqueue(key, thread); ErrorCode result = {}; @@ -74,15 +74,15 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr addr, ulong id, if (val == id) { if (ut + 1 == 0) { while (true) { - node->second.cv.wait(chain.mtx); - if (node->second.thr != thread) + result = ErrorCode{node->second.cv.wait(chain.mtx)}; + if (result != ErrorCode{} || node->second.thr != thread) break; } } else { auto start = std::chrono::steady_clock::now(); std::uint64_t udiff = 0; while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); + result = ErrorCode{node->second.cv.wait(chain.mtx, ut - udiff)}; if (node->second.thr != thread) break; udiff = std::chrono::duration_cast( @@ -92,16 +92,21 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr addr, ulong id, result = ErrorCode::TIMEDOUT; break; } + if (result != ErrorCode{}) { + break; + } } } } + + ORBIS_LOG_NOTICE(__FUNCTION__, "wakeup", thread->tid, addr); if (node->second.thr == thread) chain.erase(node); return result; } orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr addr, sint n_wake) { - ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake); + ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, addr, n_wake); auto [chain, key, lock] = g_context.getUmtxChain0(thread, true, addr); std::size_t count = chain.sleep_queue.count(key); if (key.pid == 0) { @@ -174,16 +179,14 @@ static ErrorCode do_lock_normal(Thread *thread, ptr m, uint flags, auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m); auto node = chain.enqueue(key, thread); if (m->owner.compare_exchange_strong(owner, owner | kUmutexContested)) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr == thread) { + error = ErrorCode{node->second.cv.wait(chain.mtx, ut)}; + if (error == ErrorCode{} && node->second.thr == thread) { error = ErrorCode::TIMEDOUT; } } if (node->second.thr == thread) chain.erase(node); } - - return {}; } static ErrorCode do_lock_pi(Thread *thread, ptr m, uint flags, std::uint64_t ut, umutex_lock_mode mode) { @@ -219,7 +222,7 @@ static ErrorCode do_unlock_normal(Thread *thread, ptr m, uint flags) { return {}; } if (count) - chain.notify_one(key); + chain.notify_all(key); if (!ok) return ErrorCode::INVAL; return {}; @@ -303,12 +306,24 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, return ErrorCode::INVAL; } if ((wflags & kCvWaitClockId) != 0 && ut + 1) { - ORBIS_LOG_FATAL("umtx_cv_wait: CLOCK_ID unimplemented", wflags); - std::abort(); + ORBIS_LOG_WARNING("umtx_cv_wait: CLOCK_ID", wflags, cv->clockid); + // std::abort(); return ErrorCode::NOSYS; + } if ((wflags & kCvWaitAbsTime) != 0 && ut + 1) { - ORBIS_LOG_FATAL("umtx_cv_wait: ABSTIME unimplemented", wflags); + ORBIS_LOG_WARNING("umtx_cv_wait: ABSTIME unimplemented", wflags); + auto now = std::chrono::time_point_cast( + std::chrono::high_resolution_clock::now()) + .time_since_epoch() + .count(); + + if (now > ut) { + ut = 0; + } else { + ut = ut - now; + } + std::abort(); return ErrorCode::NOSYS; } @@ -316,29 +331,39 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv); auto node = chain.enqueue(key, thread); - if (!cv->has_waiters.load(std::memory_order::relaxed)) + if (!cv->has_waiters.load(std::memory_order::relaxed)) { cv->has_waiters.store(1, std::memory_order::relaxed); + } ErrorCode result = umtx_unlock_umutex(thread, m); if (result == ErrorCode{}) { if (ut + 1 == 0) { while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) + result = ErrorCode{node->second.cv.wait(chain.mtx, ut)}; + if (result != ErrorCode{} || node->second.thr != thread) { break; + } } } else { auto start = std::chrono::steady_clock::now(); std::uint64_t udiff = 0; while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); - if (node->second.thr != thread) + ORBIS_LOG_WARNING(__FUNCTION__, ut - udiff); + result = ErrorCode{node->second.cv.wait(chain.mtx, ut - udiff)}; + if (node->second.thr != thread) { + ORBIS_LOG_WARNING(__FUNCTION__, "wakeup"); break; + } udiff = std::chrono::duration_cast( std::chrono::steady_clock::now() - start) .count(); if (udiff >= ut) { result = ErrorCode::TIMEDOUT; + ORBIS_LOG_WARNING(__FUNCTION__, "timeout"); + break; + } + + if (result != ErrorCode{}) { break; } } @@ -421,8 +446,8 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr rwlock, if (ut + 1 == 0) { while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) { + result = ErrorCode{node->second.cv.wait(chain.mtx, ut)}; + if (result != ErrorCode{} || node->second.thr != thread) { break; } } @@ -430,7 +455,7 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr rwlock, auto start = std::chrono::steady_clock::now(); std::uint64_t udiff = 0; while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); + result = ErrorCode{node->second.cv.wait(chain.mtx, ut - udiff)}; if (node->second.thr != thread) break; udiff = std::chrono::duration_cast( @@ -440,6 +465,10 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr rwlock, result = ErrorCode::TIMEDOUT; break; } + + if (result != ErrorCode{}) { + break; + } } } @@ -517,8 +546,8 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr rwlock, if (ut + 1 == 0) { while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) { + error = ErrorCode{node->second.cv.wait(chain.mtx, ut)}; + if (error != ErrorCode{} || node->second.thr != thread) { break; } } @@ -526,7 +555,7 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr rwlock, auto start = std::chrono::steady_clock::now(); std::uint64_t udiff = 0; while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); + error = ErrorCode{node->second.cv.wait(chain.mtx, ut - udiff)}; if (node->second.thr != thread) break; udiff = std::chrono::duration_cast( @@ -536,6 +565,9 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr rwlock, error = ErrorCode::TIMEDOUT; break; } + if (error != ErrorCode{}) { + break; + } } } @@ -697,15 +729,15 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr sem, if (!sem->count) { if (ut + 1 == 0) { while (true) { - node->second.cv.wait(chain.mtx, ut); - if (node->second.thr != thread) + result = ErrorCode{node->second.cv.wait(chain.mtx, ut)}; + if (result != ErrorCode{} || node->second.thr != thread) break; } } else { auto start = std::chrono::steady_clock::now(); std::uint64_t udiff = 0; while (true) { - node->second.cv.wait(chain.mtx, ut - udiff); + result = ErrorCode{node->second.cv.wait(chain.mtx, ut - udiff)}; if (node->second.thr != thread) break; udiff = std::chrono::duration_cast( @@ -715,6 +747,9 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr sem, result = ErrorCode::TIMEDOUT; break; } + if (result != ErrorCode{}) { + break; + } } } } diff --git a/orbis-kernel/src/utils/SharedCV.cpp b/orbis-kernel/src/utils/SharedCV.cpp index 5482cc22..a73bb22a 100644 --- a/orbis-kernel/src/utils/SharedCV.cpp +++ b/orbis-kernel/src/utils/SharedCV.cpp @@ -5,7 +5,7 @@ #include namespace orbis::utils { -void shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, +int shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, std::uint64_t usec_timeout) noexcept { // Not supposed to fail if (!_val) { @@ -17,8 +17,10 @@ void shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, timeout.tv_nsec = (usec_timeout % 1000'000) * 1000; timeout.tv_sec = (usec_timeout / 1000'000); + int result = 0; + while (true) { - auto result = syscall(SYS_futex, &m_value, FUTEX_WAIT, _val, + result = syscall(SYS_futex, &m_value, FUTEX_WAIT, _val, usec_timeout + 1 ? &timeout : nullptr, 0, 0); if (result < 0) { result = errno; @@ -27,7 +29,7 @@ void shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, // Cleanup const auto old = atomic_fetch_op(m_value, [&](unsigned &value) { // Remove waiter if no signals - if (!(value & ~c_waiter_mask) && result != EAGAIN && result != EINTR) { + if (!(value & ~c_waiter_mask) && result != EAGAIN) { value -= 1; } @@ -43,22 +45,24 @@ void shared_cv::impl_wait(shared_mutex &mutex, unsigned _val, // Lock is already acquired if (old & c_locked_mask) { - return; + return 0; } // Wait directly (waiter has been added) if (old & c_signal_mask) { - mutex.impl_wait(); - return; + return mutex.impl_wait(); } // Possibly spurious wakeup - if (result != EAGAIN && result != EINTR) { + if (result != EAGAIN) { break; } + + _val = old; } mutex.lock(); + return result; } void shared_cv::impl_wake(shared_mutex &mutex, int _count) noexcept { diff --git a/orbis-kernel/src/utils/SharedMutex.cpp b/orbis-kernel/src/utils/SharedMutex.cpp index 1aa78f3a..0cd345bb 100644 --- a/orbis-kernel/src/utils/SharedMutex.cpp +++ b/orbis-kernel/src/utils/SharedMutex.cpp @@ -48,7 +48,7 @@ void shared_mutex::impl_lock_shared(unsigned val) { if ((old % c_sig) + c_one >= c_sig) std::abort(); // "shared_mutex overflow" - impl_wait(); + while (impl_wait() != 0) {} lock_downgrade(); } void shared_mutex::impl_unlock_shared(unsigned old) { @@ -60,7 +60,7 @@ void shared_mutex::impl_unlock_shared(unsigned old) { impl_signal(); } } -void shared_mutex::impl_wait() { +int shared_mutex::impl_wait() { while (true) { const auto [old, ok] = atomic_fetch_op(m_value, [](unsigned &value) { if (value >= c_sig) { @@ -75,8 +75,15 @@ void shared_mutex::impl_wait() { break; } - syscall(SYS_futex, &m_value, FUTEX_WAIT, old, 0, 0, 0); + int result = syscall(SYS_futex, &m_value, FUTEX_WAIT, old, 0, 0, 0); + if (result < 0) { + result = errno; + } + if (result == EINTR) { + return EINTR; + } } + return{}; } void shared_mutex::impl_signal() { m_value += c_sig; @@ -116,7 +123,7 @@ void shared_mutex::impl_lock(unsigned val) { if ((old % c_sig) + c_one >= c_sig) std::abort(); // "shared_mutex overflow" - impl_wait(); + while (impl_wait() != 0) {} } void shared_mutex::impl_unlock(unsigned old) { if (old - c_one >= c_err) @@ -148,7 +155,7 @@ void shared_mutex::impl_lock_upgrade() { return; } - impl_wait(); + while (impl_wait() != 0) {} } bool shared_mutex::lock_forced(int count) { if (count == 0) diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx-os/CMakeLists.txt index 8f68f093..d9ecd0b6 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx-os/CMakeLists.txt @@ -43,6 +43,11 @@ add_executable(rpcsx-os iodev/devctl.cpp iodev/uvd.cpp iodev/vce.cpp + iodev/evlg.cpp + iodev/srtc.cpp + iodev/sshot.cpp + iodev/lvdctl.cpp + iodev/icc_power.cpp main.cpp backtrace.cpp diff --git a/rpcsx-os/backtrace.cpp b/rpcsx-os/backtrace.cpp index a6e8ad5c..4b102aa5 100644 --- a/rpcsx-os/backtrace.cpp +++ b/rpcsx-os/backtrace.cpp @@ -1,11 +1,35 @@ #include "backtrace.hpp" +#include "thread.hpp" +#include "xbyak/xbyak.h" #include #include #include #include #include +#include #include +extern std::uint64_t monoPimpAddress; + +static auto callGuest = [] { + struct SetContext : Xbyak::CodeGenerator { + SetContext() { + mov(rbx, rsp); + mov(rsp, rdx); + sub(rsp, 128); + push(rbx); + call(rsi); + pop(rsp); + ret(); + } + } static setContextStorage; + + return setContextStorage + .getCode(); +}(); + +bool allowMonoDebug = false; + std::size_t rx::printAddressLocation(char *dest, std::size_t destLen, orbis::Thread *thread, std::uint64_t address) { @@ -19,10 +43,22 @@ std::size_t rx::printAddressLocation(char *dest, std::size_t destLen, continue; } - return std::snprintf(dest, destLen, "%s+%#" PRIx64 " (%#" PRIx64 ")", + const char *name = ""; + if (monoPimpAddress && allowMonoDebug && (std::string_view(module->soName).contains(".dll.") || std::string_view(module->soName).contains(".exe."))) { + allowMonoDebug = false; + auto ctx = reinterpret_cast(thread->context); + rx::thread::setupSignalStack(); + auto prevFs = _readfsbase_u64(); + _writefsbase_u64(thread->fsBase); + name = callGuest(address, monoPimpAddress, ctx->uc_mcontext.gregs[REG_RSP]); + _writefsbase_u64(prevFs); + allowMonoDebug = true; + } + + return std::snprintf(dest, destLen, "%s+%#" PRIx64 " (%#" PRIx64 ") %s", module->soName[0] != '\0' ? module->soName : module->moduleName, - address - moduleBase, address); + address - moduleBase, address, name); } return 0; @@ -68,7 +104,7 @@ void rx::printStackTrace(ucontext_t *context, int fileno) { static_cast(proc_res == 0 ? off : 0)); write(fileno, buffer, len); count++; - } while (unw_step(&cursor) > 0 && count < 32); + } while (unw_step(&cursor) > 0 && count < 64); funlockfile(stderr); } @@ -123,6 +159,6 @@ void rx::printStackTrace(ucontext_t *context, orbis::Thread *thread, write(fileno, buffer, offset); count++; - } while (unw_step(&cursor) > 0 && count < 32); + } while (unw_step(&cursor) > 0 && count < 64); funlockfile(stderr); } diff --git a/rpcsx-os/backtrace.hpp b/rpcsx-os/backtrace.hpp index bd350e3d..2b487bad 100644 --- a/rpcsx-os/backtrace.hpp +++ b/rpcsx-os/backtrace.hpp @@ -1,8 +1,12 @@ #pragma once -#include "orbis/thread/Thread.hpp" #include -#include +#include +#include + +namespace orbis { +struct Thread; +} namespace rx { std::size_t printAddressLocation(char *dest, std::size_t destLen, diff --git a/rpcsx-os/io-device.cpp b/rpcsx-os/io-device.cpp index d341bfd9..4f26af9e 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx-os/io-device.cpp @@ -434,6 +434,7 @@ static orbis::ErrorCode socket_read(orbis::File *file, orbis::Uio *uio, return orbis::ErrorCode::INVAL; } + ORBIS_LOG_FATAL(__FUNCTION__, file, uio->iov->len); return host_fd_read(socket->hostFd, uio); } @@ -448,6 +449,7 @@ static orbis::ErrorCode socket_write(orbis::File *file, orbis::Uio *uio, return {}; } + ORBIS_LOG_FATAL(__FUNCTION__, file, uio->iov->len); return host_fd_write(socket->hostFd, uio); } @@ -700,6 +702,39 @@ orbis::ErrorCode createSocket(orbis::Ref *file, return {}; } +static std::optional findFileInDir(const std::filesystem::path &dir, const char *name) { + for (auto entry : std::filesystem::directory_iterator(dir)) { + auto entryName = entry.path().filename(); + if (strcasecmp(entryName.c_str(), name) == 0) { + return entryName; + } + } + return{}; +} + +static std::optional toRealPath(const std::filesystem::path &inp) { + if (inp.empty()) { + return{}; + } + + std::filesystem::path result; + for (auto elem : inp) { + if (result.empty() || std::filesystem::exists(result / elem)) { + result /= elem; + continue; + } + + auto icaseElem = findFileInDir(result, elem.c_str()); + if (!icaseElem) { + return{}; + } + + result /= *icaseElem; + } + + return result; +} + orbis::ErrorCode HostFsDevice::open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) { @@ -754,8 +789,21 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref *file, int hostFd = ::open(realPath.c_str(), realFlags, 0777); + orbis::ErrorCode error{}; + if (hostFd < 0) { + error = convertErrno(); + + if (auto icaseRealPath = toRealPath(realPath)) { + ORBIS_LOG_WARNING(__FUNCTION__, path, realPath.c_str(), icaseRealPath->c_str()); + hostFd = ::open(icaseRealPath->c_str(), realFlags, 0777); + + if (hostFd < 0) { + ORBIS_LOG_ERROR("host_open failed", path, realPath.c_str(), icaseRealPath->c_str(), error); + return convertErrno(); + } + } + } if (hostFd < 0) { - auto error = convertErrno(); ORBIS_LOG_ERROR("host_open failed", path, realPath.c_str(), error); return error; } diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index d3809e35..76319ff9 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -1,5 +1,6 @@ #pragma once +#include struct IoDevice; IoDevice *createDceCharacterDevice(); @@ -29,7 +30,7 @@ IoDevice *createBtCharacterDevice(); IoDevice *createXptCharacterDevice(); IoDevice *createCdCharacterDevice(); IoDevice *createMetaDbgCharacterDevice(); -IoDevice *createHddCharacterDevice(); +IoDevice *createHddCharacterDevice(std::uint64_t size); IoDevice *createAoutCharacterDevice(); IoDevice *createAVControlCharacterDevice(); IoDevice *createHDMICharacterDevice(); @@ -42,3 +43,8 @@ IoDevice *createDevCtlCharacterDevice(); IoDevice *createDevActCharacterDevice(); IoDevice *createUVDCharacterDevice(); IoDevice *createVCECharacterDevice(); +IoDevice *createEvlgCharacterDevice(int outputFd); +IoDevice *createSrtcCharacterDevice(); +IoDevice *createScreenShotCharacterDevice(); +IoDevice *createLvdCtlCharacterDevice(); +IoDevice *createIccPowerCharacterDevice(); diff --git a/rpcsx-os/iodev/MBusEvent.hpp b/rpcsx-os/iodev/MBusEvent.hpp new file mode 100644 index 00000000..9ef51831 --- /dev/null +++ b/rpcsx-os/iodev/MBusEvent.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "orbis-config.hpp" + +struct MBusEvent { + orbis::uint32_t system; + orbis::uint32_t eventId; + orbis::uint64_t deviceId; + orbis::uint32_t unk1; // device type? + orbis::uint32_t subsystem; + orbis::uint64_t unk2; + orbis::uint64_t unk3; + orbis::uint64_t unk4; +}; + +static_assert(sizeof(MBusEvent) == 0x30); diff --git a/rpcsx-os/iodev/aout.cpp b/rpcsx-os/iodev/aout.cpp index deb35a4f..3ac39cc9 100644 --- a/rpcsx-os/iodev/aout.cpp +++ b/rpcsx-os/iodev/aout.cpp @@ -1,22 +1,19 @@ #include "io-device.hpp" +#include "iodev/mbus_av.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Process.hpp" +#include "orbis/thread/ProcessOps.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" #include -#include -#include struct AoutFile : orbis::File {}; static orbis::ErrorCode aout_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled aout ioctl", request); - if (request == 0xc004500a) { - std::this_thread::sleep_for(std::chrono::days(1)); - } thread->where(); return {}; } diff --git a/rpcsx-os/iodev/cd.cpp b/rpcsx-os/iodev/cd.cpp index 77171aea..ed6ed939 100644 --- a/rpcsx-os/iodev/cd.cpp +++ b/rpcsx-os/iodev/cd.cpp @@ -1,14 +1,21 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" struct CdFile : orbis::File {}; static orbis::ErrorCode cd_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { + void *argp, orbis::Thread *thread) { + if (request == 0xc4a81602) { + (*(std::uint32_t *)((char *)argp + 0x54)) = 1; + // std::this_thread::sleep_for(std::chrono::hours(120)); + return {}; + } ORBIS_LOG_FATAL("Unhandled cd ioctl", request); + thread->where(); return {}; } diff --git a/rpcsx-os/iodev/console.cpp b/rpcsx-os/iodev/console.cpp index e480c13c..d50005d6 100644 --- a/rpcsx-os/iodev/console.cpp +++ b/rpcsx-os/iodev/console.cpp @@ -2,6 +2,7 @@ #include "orbis/KernelAllocator.hpp" #include "orbis/error/ErrorCode.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" #include @@ -50,6 +51,11 @@ static orbis::ErrorCode console_write(orbis::File *file, orbis::Uio *uio, for (auto vec : std::span(uio->iov, uio->iovcnt)) { uio->offset += vec.len; + if (std::string_view((char *)vec.base, vec.len).contains("begin_setControllerFocus")) { + ORBIS_LOG_ERROR(__FUNCTION__, thread->tid); + thread->where(); + } + ::write(dev->outputFd, vec.base, vec.len); ::write(2, vec.base, vec.len); } diff --git a/rpcsx-os/iodev/dce.cpp b/rpcsx-os/iodev/dce.cpp index 9316718a..d8177fe0 100644 --- a/rpcsx-os/iodev/dce.cpp +++ b/rpcsx-os/iodev/dce.cpp @@ -3,10 +3,10 @@ #include "orbis/KernelAllocator.hpp" #include "orbis/error/ErrorCode.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Process.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/SharedMutex.hpp" -#include "orbis/thread/Thread.hpp" -#include "orbis/thread/Process.hpp" #include "vm.hpp" #include #include @@ -21,18 +21,18 @@ struct VideoOutBuffer { }; struct RegisterBuffer { - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 - std::uint32_t index; //buffer index - std::uint32_t vid; //video output port id ? - std::uint64_t address; //left buffer ptr - std::uint64_t address2; //right buffer ptr (Stereo) + std::uint64_t canary; // arg5 data in FlipControlArgs:0: *arg5 + std::uint32_t index; // buffer index + std::uint32_t vid; // video output port id ? + std::uint64_t address; // left buffer ptr + std::uint64_t address2; // right buffer ptr (Stereo) }; struct RegisterBufferAttributeArgs { - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 - std::uint8_t vid; //video output port id ? - std::uint8_t submit; //0 = RegisterBuffers ; 1 = SubmitChangeBufferAttribute - std::uint16_t unk3; //0 + std::uint64_t canary; // arg5 data in FlipControlArgs:0: *arg5 + std::uint8_t vid; // video output port id ? + std::uint8_t submit; // 0 = RegisterBuffers ; 1 = SubmitChangeBufferAttribute + std::uint16_t unk3; // 0 std::uint32_t pixelFormat; std::uint32_t tilingMode; // 1 // tilingMode? std::uint32_t pitch; @@ -45,29 +45,30 @@ struct RegisterBufferAttributeArgs { std::uint32_t reserved2; }; -struct FlipRequestArgs { //submit_flip - std::uint64_t canary; //arg5 data in FlipControlArgs:0: *arg5 +struct FlipRequestArgs { // submit_flip + std::uint64_t canary; // arg5 data in FlipControlArgs:0: *arg5 std::uint64_t displayBufferIndex; std::uint32_t flipMode; // flip mode? std::uint32_t unk1; std::uint64_t flipArg; - std::uint64_t flipArg2; //not used + std::uint64_t flipArg2; // not used std::uint32_t eop_nz; std::uint32_t unk2; std::uint32_t eop_val; std::uint32_t unk3; std::uint64_t unk4; - std::uint64_t* rout; //extraout of result error + std::uint64_t *rout; // extraout of result error }; struct FlipControlStatus { std::uint64_t flipArg; - std::uint64_t flipArg2; //not used + std::uint64_t flipArg2; // not used std::uint64_t count; std::uint64_t processTime; std::uint64_t tsc; std::uint32_t currentBuffer; - std::uint32_t flipPendingNum0; //flipPendingNum = flipPendingNum0 + gcQueueNum + flipPendingNum1 + std::uint32_t flipPendingNum0; // flipPendingNum = flipPendingNum0 + + // gcQueueNum + flipPendingNum1 std::uint32_t gcQueueNum; std::uint32_t flipPendingNum1; std::uint32_t submitTsc; @@ -76,7 +77,7 @@ struct FlipControlStatus { struct FlipControlArgs { std::uint32_t id; - // std::uint32_t padding; + std::uint32_t padding; std::uint64_t arg2; void *ptr; std::uint64_t size; // 0x48 // size? @@ -91,31 +92,31 @@ struct ResolutionStatus { std::uint32_t paneHeight; std::uint32_t refreshHz; std::uint32_t screenSizeInInch; - std::byte padding[20]; + std::byte padding[20]; }; - //refreshRate = 0 REFRESH_RATE_UNKNOWN - //refreshRate = 3; result.refreshHz = 0x426fc28f REFRESH_RATE_59_94HZ - //refreshRate = 2, result.refreshHz = 0x42480000 REFRESH_RATE_50HZ - //refreshRate = 1, result.refreshHz = 0x41bfd70a REFRESH_RATE_23_98HZ - //refreshRate = 4, result.refreshHz = 0x41c00000 - //refreshRate = 5, result.refreshHz = 0x41f00000 - //refreshRate = 6, result.refreshHz = 0x41efc28f REFRESH_RATE_29_97HZ - //refreshRate = 7, result.refreshHz = 0x41c80000 - //refreshRate = 9, result.refreshHz = 0x42700000 - //refreshRate = 10, result.refreshHz = 0x42400000 - //refreshRate = 0xb, result.refreshHz = 0x423fcccd - //refreshRate = 0xc, result.refreshHz = 0x42c80000 - //refreshRate = 0xd, result.refreshHz = 0x42efc28f REFRESH_RATE_119_88HZ - //refreshRate = 0xe, result.refreshHz = 0x42f00000 - //refreshRate = 0xf, result.refreshHz = 0x43480000 - //refreshRate = 0x10, result.refreshHz = 0x436fc28f - //refreshRate = 0x11, result.refreshHz = 0x43700000 - //refreshRate = 0x14, result.refreshHz = 0x413fd70a - //refreshRate = 0x15, result.refreshHz = 0x41400000 - //refreshRate = 0x16, result.refreshHz = 0x416fd70a - //refreshRate = 0x17, result.refreshHz = 0x41700000 - //refreshRate = 0x23, result.refreshHz = 0x42b3d1ec REFRESH_RATE_89_91HZ +// refreshRate = 0 REFRESH_RATE_UNKNOWN +// refreshRate = 3; result.refreshHz = 0x426fc28f REFRESH_RATE_59_94HZ +// refreshRate = 2, result.refreshHz = 0x42480000 REFRESH_RATE_50HZ +// refreshRate = 1, result.refreshHz = 0x41bfd70a REFRESH_RATE_23_98HZ +// refreshRate = 4, result.refreshHz = 0x41c00000 +// refreshRate = 5, result.refreshHz = 0x41f00000 +// refreshRate = 6, result.refreshHz = 0x41efc28f REFRESH_RATE_29_97HZ +// refreshRate = 7, result.refreshHz = 0x41c80000 +// refreshRate = 9, result.refreshHz = 0x42700000 +// refreshRate = 10, result.refreshHz = 0x42400000 +// refreshRate = 0xb, result.refreshHz = 0x423fcccd +// refreshRate = 0xc, result.refreshHz = 0x42c80000 +// refreshRate = 0xd, result.refreshHz = 0x42efc28f REFRESH_RATE_119_88HZ +// refreshRate = 0xe, result.refreshHz = 0x42f00000 +// refreshRate = 0xf, result.refreshHz = 0x43480000 +// refreshRate = 0x10, result.refreshHz = 0x436fc28f +// refreshRate = 0x11, result.refreshHz = 0x43700000 +// refreshRate = 0x14, result.refreshHz = 0x413fd70a +// refreshRate = 0x15, result.refreshHz = 0x41400000 +// refreshRate = 0x16, result.refreshHz = 0x416fd70a +// refreshRate = 0x17, result.refreshHz = 0x41700000 +// refreshRate = 0x23, result.refreshHz = 0x42b3d1ec REFRESH_RATE_89_91HZ struct DceFile : public orbis::File {}; @@ -182,6 +183,11 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, std::memcpy(args->ptr, &flipStatus, sizeof(FlipControlStatus)); } else if (args->id == 12) { *(std::uint64_t *)args->ptr = 0; + } else if (args->id == 18) { + // ORBIS_LOG_NOTICE("dce: get vblank status", args->size); + if (args->size) { + *(std::uint32_t *)args->size = 0xffff'0000; + } } else if (args->id == 19) { // get resolution status auto status = (ResolutionStatus *)args->ptr; @@ -189,21 +195,29 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, status->heigth = 1080; status->paneWidth = 1920; status->paneHeight = 1080; + status->refreshHz = 0x426fc28f; + status->screenSizeInInch = 867; } else if (args->id == 9) { ORBIS_LOG_NOTICE("dce: FlipControl allocate", args->id, args->arg2, args->ptr, args->size); *(std::uint64_t *)args->ptr = 0; // dev offset *(std::uint64_t *)args->size = 0x100000; // size } else if (args->id == 31) { - rx::bridge.header->bufferInUseAddress = args->size; + // if ((std::uint64_t)args->ptr == 0xc) { + // rx::bridge.header->bufferInUseAddress = args->size; + // } else { + // ORBIS_LOG_ERROR("buffer in use", args->ptr, args->size); + // thread->where(); + // } + // std::abort(); return {}; } else if (args->id == 33) { // adjust color std::printf("adjust color\n"); return {}; } else if (args->id == 0x1e) { // TODO - return{}; - } else if (args->id != 0 && args->id != 1) { // used during open/close + return {}; + } else if (args->id != 1) { // used during open/close ORBIS_LOG_NOTICE("dce: UNIMPLEMENTED FlipControl", args->id, args->arg2, args->ptr, args->size); @@ -242,8 +256,8 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, ORBIS_LOG_ERROR("dce: RegisterBufferAttributes", args->canary, args->vid, args->submit, args->unk3, args->pixelFormat, args->tilingMode, args->pitch, args->width, args->height, - args->unk4_zero, args->unk5_zero, args->options, args->reserved1, - args->reserved2); + args->unk4_zero, args->unk5_zero, args->options, + args->reserved1, args->reserved2); device->bufferAttributes.pixelFormat = args->pixelFormat; device->bufferAttributes.tilingMode = args->tilingMode; @@ -257,12 +271,22 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, // flip request auto args = reinterpret_cast(argp); - // ORBIS_LOG_ERROR("dce: FlipRequestArgs", args->arg1, - // args->displayBufferIndex, args->flipMode, args->flipArg, - // args->arg5, args->arg6, args->arg7, args->arg8); + // ORBIS_LOG_ERROR("dce: FlipRequestArgs", args->canary, + // args->displayBufferIndex, args->flipMode, args->unk1, + // args->flipArg, args->flipArg2, args->eop_nz, args->unk2, + // args->eop_val, args->unk3, args->unk4, args->rout); rx::bridge.sendFlip(thread->tproc->pid, args->displayBufferIndex, /*args->flipMode,*/ args->flipArg); + + // *args->rout = 0; + + // rx::bridge.header->flipBuffer = args->displayBufferIndex; + // rx::bridge.header->flipArg = args->flipArg; + // rx::bridge.header->flipCount += 1; + // *reinterpret_cast(rx::bridge.header->bufferInUseAddress) + // = + // 0; return {}; } diff --git a/rpcsx-os/iodev/devctl.cpp b/rpcsx-os/iodev/devctl.cpp index 2a703b51..440fad98 100644 --- a/rpcsx-os/iodev/devctl.cpp +++ b/rpcsx-os/iodev/devctl.cpp @@ -17,6 +17,7 @@ static const orbis::FileOps fileOps = { }; struct DevCtlDevice : IoDevice { + orbis::kstring data; orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override { diff --git a/rpcsx-os/iodev/evlg.cpp b/rpcsx-os/iodev/evlg.cpp new file mode 100644 index 00000000..63308d97 --- /dev/null +++ b/rpcsx-os/iodev/evlg.cpp @@ -0,0 +1,60 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/error/ErrorCode.hpp" +#include "orbis/file.hpp" +#include "orbis/uio.hpp" +#include "orbis/utils/Logs.hpp" +#include +#include + +struct EvlgFile : orbis::File {}; +struct EvlgDevice : IoDevice { + int outputFd; + + EvlgDevice(int outputFd) + : outputFd(outputFd) {} + + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; +}; + +static orbis::ErrorCode evlg_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + + ORBIS_LOG_FATAL("Unhandled evlg ioctl", request); + return {}; +} + +static orbis::ErrorCode evlg_write(orbis::File *file, orbis::Uio *uio, + orbis::Thread *thread) { + auto dev = dynamic_cast(file->device.get()); + + for (auto vec : std::span(uio->iov, uio->iovcnt)) { + uio->offset += vec.len; + ::write(dev->outputFd, vec.base, vec.len); + ::write(2, vec.base, vec.len); + } + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = evlg_ioctl, + .write = evlg_write, +}; + +orbis::ErrorCode EvlgDevice::open(orbis::Ref *file, + const char *path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread *thread) { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; +} + +IoDevice *createEvlgCharacterDevice(int outputFd) { + return orbis::knew(outputFd); +} diff --git a/rpcsx-os/iodev/gbase.cpp b/rpcsx-os/iodev/gbase.cpp index c893e784..4920622c 100644 --- a/rpcsx-os/iodev/gbase.cpp +++ b/rpcsx-os/iodev/gbase.cpp @@ -9,6 +9,24 @@ struct GbaseFile : orbis::File {}; static orbis::ErrorCode gbase_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { + if (request == 0xc0304510) { + ORBIS_LOG_WARNING("gbase ioctl", request); + struct Args { + std::uint64_t unk0; + std::uint64_t unk1; + std::uint32_t currentClock; + std::uint32_t unk2; + std::uint64_t unk3; + std::uint64_t unk4; + std::uint64_t unk5; + }; + + static_assert(sizeof(Args) == 48); + *reinterpret_cast(argp) = { + .currentClock = 1, + }; + return{}; + } ORBIS_LOG_FATAL("Unhandled gbase ioctl", request); thread->where(); return {}; diff --git a/rpcsx-os/iodev/gc.cpp b/rpcsx-os/iodev/gc.cpp index cd2a8803..7fa38169 100644 --- a/rpcsx-os/iodev/gc.cpp +++ b/rpcsx-os/iodev/gc.cpp @@ -54,7 +54,9 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, auto args = reinterpret_cast(argp); // flockfile(stderr); - // ORBIS_LOG_ERROR("gc ioctl 0xc0108102", args->arg0, args->count, args->cmds); + // if (thread->tproc->pid != amdgpu::bridge::expGpuPid) { + // ORBIS_LOG_ERROR("gc ioctl submit", args->arg0, args->count, args->cmds); + // } for (unsigned i = 0; i < args->count; ++i) { auto cmd = args->cmds + (i * 2); @@ -73,6 +75,11 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); // std::fprintf(stderr, " size = %lu\n", size); + // for (std::size_t i = 0; i < std::min(size, 64); i += 4) { + // std::fprintf(stderr, "%08x ", *(unsigned *)(address + i)); + // } + // std::fprintf(stderr, "\n"); + rx::bridge.sendCommandBuffer(thread->tproc->pid, cmdId, address, size); } // funlockfile(stderr); @@ -133,9 +140,8 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, } case 0xc0048116: { // submit done? - ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t *)argp); - *(std::uint32_t *)argp = 1; - thread->where(); + // ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t *)argp); + // thread->where(); break; } diff --git a/rpcsx-os/iodev/hdd.cpp b/rpcsx-os/iodev/hdd.cpp index 5fcb6e81..47102c29 100644 --- a/rpcsx-os/iodev/hdd.cpp +++ b/rpcsx-os/iodev/hdd.cpp @@ -9,20 +9,39 @@ struct HddFile : orbis::File {}; +struct HddDevice : IoDevice { + std::uint64_t size; + HddDevice(std::uint64_t size) : size(size) {} + + orbis::ErrorCode open(orbis::Ref *fs, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; +}; + +static_assert(0x120 - 24 == 0x108); static orbis::ErrorCode hdd_ioctl(orbis::File *fs, std::uint64_t request, void *argp, orbis::Thread *thread) { + auto device = fs->device.cast(); if (request == 0x40046480) { // DIOCGSECTORSIZE return orbis::uwrite(orbis::ptr(argp), 0x1000u); } + if (request == 0x40086481) { // hdd size + if (device->size == 0) { + ORBIS_LOG_FATAL("Unknown hdd size request", request); + thread->where(); + } + return orbis::uwrite(orbis::ptr(argp), device->size); + } + ORBIS_LOG_FATAL("Unhandled hdd ioctl", request); thread->where(); return {}; } static orbis::ErrorCode hdd_read(orbis::File *file, orbis::Uio *uio, - orbis::Thread *thread) { + orbis::Thread *thread) { auto dev = file->device.get(); ORBIS_LOG_ERROR(__FUNCTION__, uio->offset); @@ -41,10 +60,12 @@ static orbis::ErrorCode hdd_read(orbis::File *file, orbis::Uio *uio, return {}; } - static orbis::ErrorCode hdd_stat(orbis::File *fs, orbis::Stat *sb, orbis::Thread *thread) { // TODO + ORBIS_LOG_ERROR(__FUNCTION__); + *sb = {}; + sb->mode = 0x2000; return {}; } @@ -54,17 +75,17 @@ static const orbis::FileOps fsOps = { .stat = hdd_stat, }; -struct HddDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *fs, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override { - auto newFile = orbis::knew(); - newFile->ops = &fsOps; - newFile->device = this; +orbis::ErrorCode HddDevice::open(orbis::Ref *fs, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) { + auto newFile = orbis::knew(); + newFile->ops = &fsOps; + newFile->device = this; - *fs = newFile; - return {}; - } -}; + *fs = newFile; + return {}; +} -IoDevice *createHddCharacterDevice() { return orbis::knew(); } +IoDevice *createHddCharacterDevice(std::uint64_t size) { + return orbis::knew(size); +} diff --git a/rpcsx-os/iodev/hid.cpp b/rpcsx-os/iodev/hid.cpp index 6c2ad0c3..47cb5592 100644 --- a/rpcsx-os/iodev/hid.cpp +++ b/rpcsx-os/iodev/hid.cpp @@ -14,38 +14,39 @@ struct HidDevice : public IoDevice { }; struct HidFile : public orbis::File {}; +struct PadState { + std::uint64_t timestamp; + std::uint32_t unk; + std::uint32_t buttons; + std::uint8_t leftStickX; + std::uint8_t leftStickY; + std::uint8_t rightStickX; + std::uint8_t rightStickY; + std::uint8_t l2; + std::uint8_t r2; +}; + static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("hid ioctl", request); switch (request) { case 0x800c4802: + ORBIS_LOG_FATAL("hid ioctl", request); thread->retval[0] = 1; // hid id return {}; case 0x8030482e: { + ORBIS_LOG_FATAL("hid ioctl", request); // read state struct ReadStateArgs { std::uint32_t hidId; std::uint32_t unk0; - void *state; + amdgpu::bridge::PadState *state; std::uint32_t unk2; std::uint32_t *connected; std::uint32_t *unk4; std::uint64_t unk5; }; - // struct PadState { - // std::uint64_t timestamp; - // std::uint32_t unk; - // std::uint32_t buttons; - // std::uint8_t leftStickX; - // std::uint8_t leftStickY; - // std::uint8_t rightStickX; - // std::uint8_t rightStickY; - // std::uint8_t l2; - // std::uint8_t r2; - // }; - // enum { // kPadBtnL3 = 1 << 1, // kPadBtnR3 = 1 << 2, @@ -70,8 +71,7 @@ static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, // ORBIS_LOG_ERROR("hid read state", args.hidId, args.unk0, args.state, // args.unk2, args.connected, args.unk4, args.unk5); - auto state = (amdgpu::bridge::PadState *)args.state; - *state = rx::bridge.header->kbPadState; + *args.state = rx::bridge.header->kbPadState; *args.connected = 1; *args.unk4 = 1; // is wireless? thread->retval[0] = 1; @@ -84,8 +84,25 @@ static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, return {}; } + case 0x80204829: { + struct MiniReadStateArgs { + orbis::uint hidId; + orbis::uint unk0; + orbis::ptr state; + orbis::uint count; + orbis::uint padding; + orbis::ptr unk5; + }; + + auto args = *reinterpret_cast(argp); + *args.state = rx::bridge.header->kbPadState; + thread->retval[0] = 1; + return{}; + } + default: ORBIS_LOG_FATAL("Unhandled hid ioctl", request); + thread->where(); } return {}; diff --git a/rpcsx-os/iodev/icc_power.cpp b/rpcsx-os/iodev/icc_power.cpp new file mode 100644 index 00000000..14277b08 --- /dev/null +++ b/rpcsx-os/iodev/icc_power.cpp @@ -0,0 +1,68 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" + +struct IccPowerDevice : IoDevice { + std::uint8_t bootphase = 0; + + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; +}; + +static orbis::ErrorCode icc_power_ioctl(orbis::File *file, + std::uint64_t request, void *argp, + orbis::Thread *thread) { + + // 0xc0019901 - bootphase set + // 0xc0099902 - unk + // 0x40019907 - bootphase get + + auto iccPower = file->device.staticCast(); + + switch (request) { + case 0xc0019901: { + iccPower->bootphase = *reinterpret_cast(argp); + ORBIS_LOG_WARNING(__FUNCTION__, request, iccPower->bootphase); + return{}; + } + + case 0xc0099902: { + auto &unk = *reinterpret_cast(argp); + ORBIS_LOG_WARNING(__FUNCTION__, request, unk); + unk = 1; + return{}; + } + + case 0x40019907: + ORBIS_LOG_WARNING(__FUNCTION__, request); + *reinterpret_cast(argp) = iccPower->bootphase; + return{}; + } + + ORBIS_LOG_FATAL("Unhandled icc_power ioctl", request); + thread->where(); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = icc_power_ioctl, +}; + +orbis::ErrorCode IccPowerDevice::open(orbis::Ref *file, + const char *path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread *thread) { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; +} + +IoDevice *createIccPowerCharacterDevice() { + return orbis::knew(); +} diff --git a/rpcsx-os/iodev/lvdctl.cpp b/rpcsx-os/iodev/lvdctl.cpp new file mode 100644 index 00000000..babe9d90 --- /dev/null +++ b/rpcsx-os/iodev/lvdctl.cpp @@ -0,0 +1,33 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" + +struct LvdCtlFile : orbis::File {}; + +static orbis::ErrorCode lvdctl_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + ORBIS_LOG_FATAL("Unhandled lvdctl ioctl", request); + thread->where(); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = lvdctl_ioctl, +}; + +struct LvdCtlDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createLvdCtlCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/mbus.cpp b/rpcsx-os/iodev/mbus.cpp index 37d5324c..0907baa2 100644 --- a/rpcsx-os/iodev/mbus.cpp +++ b/rpcsx-os/iodev/mbus.cpp @@ -1,14 +1,11 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" +#include "mbus.hpp" struct MBusFile : orbis::File {}; -struct MBusDevice : IoDevice { - orbis::ErrorCode open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) override; -}; static orbis::ErrorCode mbus_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { @@ -17,16 +14,52 @@ static orbis::ErrorCode mbus_ioctl(orbis::File *file, std::uint64_t request, return {}; } +static orbis::ErrorCode mbus_read(orbis::File *file, orbis::Uio *uio, + orbis::Thread *thread) { + auto mbus = file->device.staticCast(); + ORBIS_LOG_ERROR(__FUNCTION__); + + MBusEvent event; + { + std::lock_guard lock(mbus->mtx); + + // while (mbus->events.empty()) { + // file->mtx.unlock(); + // mbus->cv.wait(mbusAv->mtx); + // file->mtx.lock(); + // } + + if (mbus->events.empty()) { + return orbis::ErrorCode::BUSY; + } + + event = mbus->events.front(); + mbus->events.pop_front(); + } + + return uio->write(event); +} + static const orbis::FileOps fileOps = { .ioctl = mbus_ioctl, + .read = mbus_read, }; +void MBusDevice::emitEvent(const MBusEvent &event) { + std::lock_guard lock(mtx); + events.push_back(event); + cv.notify_one(mtx); + eventEmitter->emit(orbis::kEvFiltRead); +} + orbis::ErrorCode MBusDevice::open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) { + ORBIS_LOG_FATAL("mbus device open"); auto newFile = orbis::knew(); newFile->ops = &fileOps; newFile->device = this; + newFile->event = eventEmitter; *file = newFile; return {}; diff --git a/rpcsx-os/iodev/mbus.hpp b/rpcsx-os/iodev/mbus.hpp new file mode 100644 index 00000000..b55df767 --- /dev/null +++ b/rpcsx-os/iodev/mbus.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "io-device.hpp" +#include "iodev/MBusEvent.hpp" +#include "orbis/utils/SharedCV.hpp" +#include "orbis/utils/SharedMutex.hpp" + + +struct MBusDevice : IoDevice { + orbis::shared_mutex mtx; + orbis::shared_cv cv; + orbis::kdeque events; + orbis::Ref eventEmitter = + orbis::knew(); + + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override; + + void emitEvent(const MBusEvent &event); +}; diff --git a/rpcsx-os/iodev/mbus_av.cpp b/rpcsx-os/iodev/mbus_av.cpp index 6bc20a4a..c48f677a 100644 --- a/rpcsx-os/iodev/mbus_av.cpp +++ b/rpcsx-os/iodev/mbus_av.cpp @@ -2,6 +2,7 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/note.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/SharedCV.hpp" @@ -12,7 +13,6 @@ struct MBusAVFile : orbis::File {}; static orbis::ErrorCode mbus_av_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { - ORBIS_LOG_FATAL("Unhandled mbus_av ioctl", request); return {}; } @@ -21,7 +21,7 @@ static orbis::ErrorCode mbus_av_read(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { auto mbusAv = file->device.staticCast(); - MBusAVEvent event; + MBusEvent event; { std::lock_guard lock(mbusAv->mtx); @@ -53,15 +53,18 @@ orbis::ErrorCode MBusAVDevice::open(orbis::Ref *file, auto newFile = orbis::knew(); newFile->ops = &fileOps; newFile->device = this; + newFile->event = eventEmitter; *file = newFile; return {}; } -void MBusAVDevice::emitEvent(const MBusAVEvent &event) { +void MBusAVDevice::emitEvent(const MBusEvent &event) { std::lock_guard lock(mtx); events.push_back(event); cv.notify_one(mtx); + + eventEmitter->emit(orbis::kEvFiltRead); } IoDevice *createMBusAVCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/mbus_av.hpp b/rpcsx-os/iodev/mbus_av.hpp index 7be7ca33..f62a3ed1 100644 --- a/rpcsx-os/iodev/mbus_av.hpp +++ b/rpcsx-os/iodev/mbus_av.hpp @@ -1,26 +1,21 @@ #pragma once #include "io-device.hpp" +#include "iodev/MBusEvent.hpp" #include "orbis/utils/SharedCV.hpp" #include "orbis/utils/SharedMutex.hpp" -struct MBusAVEvent { - orbis::uint32_t unk0; - orbis::uint32_t unk1; - orbis::uint64_t unk2; - char unk3[0x20]; -}; - -static_assert(sizeof(MBusAVEvent) == 0x30); struct MBusAVDevice : IoDevice { orbis::shared_mutex mtx; orbis::shared_cv cv; - orbis::kdeque events; + orbis::kdeque events; + orbis::Ref eventEmitter = + orbis::knew(); orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override; - void emitEvent(const MBusAVEvent &event); + void emitEvent(const MBusEvent &event); }; diff --git a/rpcsx-os/iodev/notification.cpp b/rpcsx-os/iodev/notification.cpp index 5300f881..f648641a 100644 --- a/rpcsx-os/iodev/notification.cpp +++ b/rpcsx-os/iodev/notification.cpp @@ -1,6 +1,7 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/SharedMutex.hpp" @@ -22,19 +23,24 @@ struct NotificationDevice : IoDevice { orbis::Thread *thread) override; }; -static orbis::ErrorCode notification_ioctl(orbis::File *file, std::uint64_t request, - void *argp, orbis::Thread *thread) { +static orbis::ErrorCode notification_ioctl(orbis::File *file, + std::uint64_t request, void *argp, + orbis::Thread *thread) { ORBIS_LOG_FATAL("Unhandled notification ioctl", request); return {}; } -static orbis::ErrorCode notification_read(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { +static orbis::ErrorCode notification_read(orbis::File *file, orbis::Uio *uio, + orbis::Thread *thread) { auto dev = dynamic_cast(file->device.get()); - ORBIS_LOG_FATAL(__FUNCTION__, dev->index); while (true) { if (dev->data.empty()) { + if (file->noBlock()) { + return orbis::ErrorCode::WOULDBLOCK; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); } @@ -53,7 +59,8 @@ static orbis::ErrorCode notification_read(orbis::File *file, orbis::Uio *uio, or break; } - std::memmove(dev->data.data(), dev->data.data() + size, dev->data.size() - size); + std::memmove(dev->data.data(), dev->data.data() + size, + dev->data.size() - size); dev->data.resize(dev->data.size() - size); } @@ -62,9 +69,9 @@ static orbis::ErrorCode notification_read(orbis::File *file, orbis::Uio *uio, or return {}; } -static orbis::ErrorCode notification_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { +static orbis::ErrorCode notification_write(orbis::File *file, orbis::Uio *uio, + orbis::Thread *thread) { auto dev = dynamic_cast(file->device.get()); - ORBIS_LOG_FATAL(__FUNCTION__, dev->index); std::lock_guard lock(dev->mutex); @@ -83,15 +90,20 @@ static const orbis::FileOps fileOps = { .write = notification_write, }; -orbis::ErrorCode NotificationDevice::open(orbis::Ref *file, const char *path, - std::uint32_t flags, std::uint32_t mode, - orbis::Thread *thread) { +orbis::ErrorCode NotificationDevice::open(orbis::Ref *file, + const char *path, std::uint32_t flags, + std::uint32_t mode, + orbis::Thread *thread) { auto newFile = orbis::knew(); newFile->ops = &fileOps; newFile->device = this; + newFile->flags = flags; + newFile->mode = mode; *file = newFile; return {}; } -IoDevice *createNotificationCharacterDevice(int index) { return orbis::knew(index); } +IoDevice *createNotificationCharacterDevice(int index) { + return orbis::knew(index); +} diff --git a/rpcsx-os/iodev/scanin.cpp b/rpcsx-os/iodev/scanin.cpp index a5c1e20d..7a5936ed 100644 --- a/rpcsx-os/iodev/scanin.cpp +++ b/rpcsx-os/iodev/scanin.cpp @@ -1,6 +1,7 @@ #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" struct ScaninFile : orbis::File {}; @@ -9,6 +10,7 @@ static orbis::ErrorCode scanin_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { ORBIS_LOG_FATAL("Unhandled scanin ioctl", request); + thread->where(); return {}; } diff --git a/rpcsx-os/iodev/srtc.cpp b/rpcsx-os/iodev/srtc.cpp new file mode 100644 index 00000000..0dd576ec --- /dev/null +++ b/rpcsx-os/iodev/srtc.cpp @@ -0,0 +1,33 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" + +struct SrtcFile : orbis::File {}; + +static orbis::ErrorCode srtc_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + ORBIS_LOG_FATAL("Unhandled srtc ioctl", request); + thread->where(); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = srtc_ioctl, +}; + +struct SrtcDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createSrtcCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/sshot.cpp b/rpcsx-os/iodev/sshot.cpp new file mode 100644 index 00000000..bc7b2d7b --- /dev/null +++ b/rpcsx-os/iodev/sshot.cpp @@ -0,0 +1,34 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" + +struct ScreenShotFile : orbis::File {}; + +static orbis::ErrorCode sshot_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + + ORBIS_LOG_FATAL("Unhandled sshot ioctl", request); + thread->where(); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = sshot_ioctl, +}; + +struct ScreenShotDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createScreenShotCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index 0f01a719..4879cf51 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -19,6 +19,8 @@ using orbis::utils::Ref; +std::uint64_t monoPimpAddress; + static std::vector unself(const std::byte *image, std::size_t size) { struct [[gnu::packed]] Header { std::uint32_t magic; @@ -500,13 +502,15 @@ Ref rx::linker::loadModule(std::span image, result->tlsAlign = phdrs[tlsPhdrIndex].p_align; result->tlsSize = phdrs[tlsPhdrIndex].p_memsz; result->tlsInitSize = phdrs[tlsPhdrIndex].p_filesz; - result->tlsInit = phdrs[tlsPhdrIndex].p_vaddr - ? imageBase - baseAddress + phdrs[tlsPhdrIndex].p_vaddr - : nullptr; + result->tlsInit = + phdrs[tlsPhdrIndex].p_vaddr + ? imageBase - baseAddress + phdrs[tlsPhdrIndex].p_vaddr + : nullptr; } if (gnuEhFramePhdrIndex >= 0 && phdrs[gnuEhFramePhdrIndex].p_vaddr > 0) { - result->ehFrameHdr = imageBase - baseAddress + phdrs[gnuEhFramePhdrIndex].p_vaddr; + result->ehFrameHdr = + imageBase - baseAddress + phdrs[gnuEhFramePhdrIndex].p_vaddr; result->ehFrameHdrSize = phdrs[gnuEhFramePhdrIndex].p_memsz; struct GnuExceptionInfo { @@ -725,10 +729,10 @@ Ref rx::linker::loadModule(std::span image, switch (dyn.d_tag) { case kElfDynamicTypeScePltGot: - result->pltGot = - dyn.d_un.d_ptr - ? reinterpret_cast(imageBase - baseAddress + dyn.d_un.d_ptr) - : nullptr; + result->pltGot = dyn.d_un.d_ptr + ? reinterpret_cast( + imageBase - baseAddress + dyn.d_un.d_ptr) + : nullptr; break; case kElfDynamicTypeSceJmpRel: @@ -781,6 +785,10 @@ Ref rx::linker::loadModule(std::span image, .type = static_cast(type), }; + if (symbol.address) { + symbol.address -= baseAddress; + } + if (sceStrtab != nullptr && sym.st_name != 0) { auto fullName = std::string_view(sceStrtab + sym.st_name); if (auto hashPos = fullName.find('#'); @@ -807,6 +815,10 @@ Ref rx::linker::loadModule(std::span image, symbol.libraryIndex = idToLibraryIndex.at(libaryNid); symbol.moduleIndex = idToModuleIndex.at(moduleNid); symbol.id = *decodeNid(name); + if (name == "5JrIq4tzVIo") { + monoPimpAddress = symbol.address + (std::uint64_t)imageBase; + std::fprintf(stderr, "mono_pimp address = %lx\n", monoPimpAddress); + } } else if (auto nid = decodeNid(fullName)) { symbol.id = *nid; symbol.libraryIndex = -1; @@ -869,8 +881,8 @@ Ref rx::linker::loadModule(std::span image, } } - result->base = imageBase; - result->size = imageSize; + result->base = imageBase - baseAddress; + result->size = imageSize + baseAddress; // std::printf("Needed modules: ["); // for (bool isFirst = true; auto &module : result->neededModules) { // if (isFirst) { @@ -898,9 +910,7 @@ Ref rx::linker::loadModule(std::span image, std::printf("Loaded module '%s' (%lx) from object '%s', address: %p - %p\n", result->moduleName, (unsigned long)result->attributes, - result->soName, result->base, - (char *)result->base + result->size); - + result->soName, imageBase, (char *)imageBase + result->size); for (auto mod : result->neededModules) { std::printf(" needed module '%s' (%lx)\n", mod.name.c_str(), (unsigned long)mod.attr); @@ -969,8 +979,10 @@ Ref rx::linker::loadModuleFile(std::string_view path, image[2] != std::byte{'L'} || image[3] != std::byte{'F'}) { image = unself(image.data(), image.size()); - std::ofstream(std::filesystem::path(path).filename().replace_extension("elf"), std::ios::binary) - .write((const char *)image.data(), image.size()); + // std::ofstream( + // std::filesystem::path(path).filename().replace_extension("elf"), + // std::ios::binary) + // .write((const char *)image.data(), image.size()); } return loadModule(image, thread->tproc); diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index 85f00353..9f1b10f0 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -4,6 +4,7 @@ #include "bridge.hpp" #include "io-device.hpp" #include "io-devices.hpp" +#include "iodev/mbus.hpp" #include "iodev/mbus_av.hpp" #include "linker.hpp" #include "ops.hpp" @@ -41,6 +42,72 @@ static int g_gpuPid; +void runBridge() { + std::thread{[] { + pthread_setname_np(pthread_self(), "Bridge"); + auto bridge = rx::bridge.header; + + std::vector fetchedCommands; + fetchedCommands.reserve(std::size(bridge->cacheCommands)); + + while (true) { + for (auto &command : bridge->cacheCommands) { + std::uint64_t value = command.load(std::memory_order::relaxed); + + if (value != 0) { + fetchedCommands.push_back(value); + command.store(0, std::memory_order::relaxed); + } + } + + if (fetchedCommands.empty()) { + continue; + } + + for (auto command : fetchedCommands) { + auto page = static_cast(command); + auto count = static_cast(command >> 32) + 1; + + auto pageFlags = + bridge->cachePages[page].load(std::memory_order::relaxed); + + auto address = + static_cast(page) * amdgpu::bridge::kHostPageSize; + auto origVmProt = rx::vm::getPageProtection(address); + int prot = 0; + + if (origVmProt & rx::vm::kMapProtCpuRead) { + prot |= PROT_READ; + } + if (origVmProt & rx::vm::kMapProtCpuWrite) { + prot |= PROT_WRITE; + } + if (origVmProt & rx::vm::kMapProtCpuExec) { + prot |= PROT_EXEC; + } + + if (pageFlags & amdgpu::bridge::kPageReadWriteLock) { + prot &= ~(PROT_READ | PROT_WRITE); + } else if (pageFlags & amdgpu::bridge::kPageWriteWatch) { + prot &= ~PROT_WRITE; + } + + // std::fprintf(stderr, "protection %lx-%lx\n", address, + // address + amdgpu::bridge::kHostPageSize * count); + if (::mprotect(reinterpret_cast(address), + amdgpu::bridge::kHostPageSize * count, prot)) { + perror("protection failed"); + std::abort(); + } + } + + fetchedCommands.clear(); + } + }}.detach(); +} + +extern bool allowMonoDebug; + __attribute__((no_stack_protector)) static void handle_signal(int sig, siginfo_t *info, void *ucontext) { if (auto hostFs = _readgsbase_u64()) { @@ -121,7 +188,8 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { } if (orbis::g_currentThread != nullptr) { - orbis::g_currentThread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExit, sig); + orbis::g_currentThread->tproc->event.emit(orbis::kEvFiltProc, + orbis::kNoteExit, sig); } if (g_gpuPid > 0) { @@ -129,6 +197,7 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { // ::kill(g_gpuPid, SIGINT); } + allowMonoDebug = true; if (sig != SIGINT) { char buf[128] = ""; int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n", @@ -172,34 +241,11 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { } void setupSigHandlers() { - stack_t oss{}; - - // if (sigaltstack(nullptr, &oss) < 0 || oss.ss_size == 0) { - auto sigStackSize = std::max( - SIGSTKSZ, utils::alignUp(64 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); - - stack_t ss{}; - ss.ss_sp = malloc(sigStackSize); - if (ss.ss_sp == NULL) { - perror("malloc"); - exit(EXIT_FAILURE); - } - - ss.ss_size = sigStackSize; - ss.ss_flags = 1 << 31; - - std::fprintf(stderr, "installing sp [%p, %p]\n", ss.ss_sp, - (char *)ss.ss_sp + ss.ss_size); - - if (sigaltstack(&ss, NULL) == -1) { - perror("sigaltstack"); - exit(EXIT_FAILURE); - } - // } + rx::thread::setupSignalStack(); struct sigaction act {}; act.sa_sigaction = handle_signal; - act.sa_flags = SA_SIGINFO | SA_ONSTACK; + act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; if (sigaction(SIGSYS, &act, NULL)) { perror("Error sigaction:"); @@ -230,6 +276,11 @@ void setupSigHandlers() { perror("Error sigaction:"); exit(-1); } + + if (sigaction(SIGFPE, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } } struct StackWriter { @@ -330,8 +381,10 @@ static void ps4InitDev() { auto dmem1 = createDmemCharacterDevice(1); orbis::g_context.dmemDevice = dmem1; - auto consoleDev = createConsoleCharacterDevice( - STDIN_FILENO, ::open("tty.txt", O_CREAT | O_TRUNC | O_WRONLY, 0666)); + auto ttyFd = ::open("tty.txt", O_CREAT | O_TRUNC | O_WRONLY, 0666); + auto consoleDev = createConsoleCharacterDevice(STDIN_FILENO, ttyFd); + auto mbus = static_cast(createMBusCharacterDevice()); + auto mbusAv = static_cast(createMBusAVCharacterDevice()); rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); @@ -346,6 +399,13 @@ static void ps4InitDev() { rx::vfs::addDevice("deci_stdin", consoleDev); rx::vfs::addDevice("deci_stdout", consoleDev); rx::vfs::addDevice("deci_stderr", consoleDev); + rx::vfs::addDevice("deci_tty1", consoleDev); + rx::vfs::addDevice("deci_tty2", consoleDev); + rx::vfs::addDevice("deci_tty3", consoleDev); + rx::vfs::addDevice("deci_tty4", consoleDev); + rx::vfs::addDevice("deci_tty5", consoleDev); + rx::vfs::addDevice("deci_tty6", consoleDev); + rx::vfs::addDevice("deci_tty7", consoleDev); rx::vfs::addDevice("stdin", consoleDev); rx::vfs::addDevice("zero", createZeroCharacterDevice()); rx::vfs::addDevice("null", createNullCharacterDevice()); @@ -361,26 +421,33 @@ static void ps4InitDev() { rx::vfs::addDevice("sbl_srv", createSblSrvCharacterDevice()); rx::vfs::addDevice("ajm", createAjmCharacterDevice()); rx::vfs::addDevice("urandom", createUrandomCharacterDevice()); - rx::vfs::addDevice("mbus", createMBusCharacterDevice()); + rx::vfs::addDevice("mbus", mbus); rx::vfs::addDevice("metadbg", createMetaDbgCharacterDevice()); rx::vfs::addDevice("bt", createBtCharacterDevice()); rx::vfs::addDevice("xpt0", createXptCharacterDevice()); - rx::vfs::addDevice("cd0", createXptCharacterDevice()); - rx::vfs::addDevice("da0x0.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x1.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x2.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x3.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x4.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x5.crypt", createHddCharacterDevice()); + rx::vfs::addDevice("cd0", createCdCharacterDevice()); + rx::vfs::addDevice("da0", + createHddCharacterDevice(250ull * 1024 * 1024 * 1024)); + rx::vfs::addDevice("da0x0.crypt", createHddCharacterDevice(0x20000000)); + rx::vfs::addDevice("da0x1.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x2", createHddCharacterDevice(0x1000000)); + rx::vfs::addDevice("da0x2.crypt", createHddCharacterDevice(0x1000000)); + rx::vfs::addDevice("da0x3.crypt", createHddCharacterDevice(0x8000000)); + rx::vfs::addDevice("da0x4.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x4b.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x5.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x5b.crypt", createHddCharacterDevice(0x40000000)); // rx::vfs::addDevice("da0x6x0", createHddCharacterDevice()); // boot log - rx::vfs::addDevice("da0x6x2.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x8", createHddCharacterDevice()); - rx::vfs::addDevice("da0x9.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x12.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x13.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x14.crypt", createHddCharacterDevice()); - rx::vfs::addDevice("da0x15", createHddCharacterDevice()); - rx::vfs::addDevice("da0x15.crypt", createHddCharacterDevice()); + rx::vfs::addDevice("da0x6", createHddCharacterDevice(0x200000000)); + rx::vfs::addDevice("da0x6x2.crypt", createHddCharacterDevice(0x200000000)); + rx::vfs::addDevice("da0x8", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x8.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x9.crypt", createHddCharacterDevice(0x200000000)); + rx::vfs::addDevice("da0x12.crypt", createHddCharacterDevice(0x180000000)); + rx::vfs::addDevice("da0x13.crypt", createHddCharacterDevice(0)); + rx::vfs::addDevice("da0x14.crypt", createHddCharacterDevice(0x40000000)); + rx::vfs::addDevice("da0x15", createHddCharacterDevice(0)); + rx::vfs::addDevice("da0x15.crypt", createHddCharacterDevice(0x400000000)); rx::vfs::addDevice("notification0", createNotificationCharacterDevice(0)); rx::vfs::addDevice("notification1", createNotificationCharacterDevice(1)); rx::vfs::addDevice("notification2", createNotificationCharacterDevice(2)); @@ -392,7 +459,6 @@ static void ps4InitDev() { rx::vfs::addDevice("aout2", createAoutCharacterDevice()); rx::vfs::addDevice("av_control", createAVControlCharacterDevice()); rx::vfs::addDevice("hdmi", createHDMICharacterDevice()); - auto mbusAv = static_cast(createMBusAVCharacterDevice()); rx::vfs::addDevice("mbus_av", mbusAv); rx::vfs::addDevice("scanin", createScaninCharacterDevice()); rx::vfs::addDevice("s3da", createS3DACharacterDevice()); @@ -402,17 +468,35 @@ static void ps4InitDev() { rx::vfs::addDevice("devctl", createDevCtlCharacterDevice()); rx::vfs::addDevice("uvd", createUVDCharacterDevice()); rx::vfs::addDevice("vce", createVCECharacterDevice()); + rx::vfs::addDevice("evlg1", createEvlgCharacterDevice(ttyFd)); + rx::vfs::addDevice("srtc", createSrtcCharacterDevice()); + rx::vfs::addDevice("sshot", createScreenShotCharacterDevice()); + rx::vfs::addDevice("lvdctl", createLvdCtlCharacterDevice()); + rx::vfs::addDevice("lvd0", createHddCharacterDevice(0x100000000)); + rx::vfs::addDevice("icc_power", createIccPowerCharacterDevice()); + + // mbus->emitEvent({ + // .system = 2, + // .eventId = 1, + // .deviceId = 0, + // }); + + // mbus->emitEvent({ + // .system = 9, + // .eventId = 1, + // .deviceId = 100, + // }); + + mbusAv->emitEvent({ + .system = 9, + .eventId = 1, + .deviceId = 100, + }); auto shm = createShmDevice(); rx::vfs::addDevice("shm", shm); orbis::g_context.shmDevice = shm; orbis::g_context.blockpoolDevice = createBlockPoolDevice(); - - mbusAv->emitEvent({ - .unk0 = 9, - .unk1 = 1, - .unk2 = 1, - }); } static void ps4InitFd(orbis::Thread *mainThread) { @@ -515,7 +599,7 @@ ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread, std::uint64_t interpBase = 0; std::uint64_t entryPoint = executableModule->entryPoint; - if (orbis::g_context.sdkVersion == 0 && mainThread->tproc->processParam) { + if (mainThread->tproc->processParam != nullptr) { auto processParam = reinterpret_cast(mainThread->tproc->processParam); @@ -524,7 +608,14 @@ ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread, + sizeof(uint32_t) // magic + sizeof(uint32_t); // entryCount - orbis::g_context.sdkVersion = *(uint32_t *)sdkVersion; + mainThread->tproc->sdkVersion = *(uint32_t *)sdkVersion; + } + + if (orbis::g_context.sdkVersion == 0 && mainThread->tproc->sdkVersion != 0) { + orbis::g_context.sdkVersion = mainThread->tproc->sdkVersion; + } + if (mainThread->tproc->sdkVersion == 0) { + mainThread->tproc->sdkVersion = orbis::g_context.sdkVersion; } if (executableModule->type != rx::linker::kElfTypeExec) { @@ -677,9 +768,10 @@ static void runRpsxGpu() { static orbis::Semaphore *createSemaphore(std::string_view name, uint32_t attrs, uint64_t initCount, uint64_t maxCount) { - auto result = orbis::g_context - .createSemaphore(orbis::kstring(name), attrs, initCount, maxCount) - .first; + auto result = + orbis::g_context + .createSemaphore(orbis::kstring(name), attrs, initCount, maxCount) + .first; std::memcpy(result->name, name.data(), name.size()); result->name[name.size()] = 0; return result; @@ -697,7 +789,7 @@ static void createShm(const char *name, uint32_t flags, uint32_t mode, orbis::Ref shm; auto shmDevice = orbis::g_context.shmDevice.staticCast(); shmDevice->open(&shm, name, flags, mode, nullptr); - shm->ops->truncate(shm.get(), 4096, nullptr); + shm->ops->truncate(shm.get(), size, nullptr); } struct IpmiServer { @@ -866,59 +958,50 @@ struct IpmiServer { bufLoc += size; } + orbis::IpmiSession::SyncResponse response; + response.errorCode = 0; + orbis::ErrorCode result{}; + if (auto it = syncHandlers.find(message->methodId); it != syncHandlers.end()) { auto &handler = it->second; - std::int32_t errorCode = 0; - auto result = handler(errorCode, outData, inData); - - if (outData.empty()) { - session->messageResponses.push_front({ - .errorCode = errorCode, - .data = {}, - }); - } else { - session->messageResponses.push_front({ - .errorCode = errorCode, - .data = orbis::kvector( - outData[0].data(), outData[0].data() + outData[0].size()), - }); + result = handler(response.errorCode, outData, inData); + } else { + std::fprintf( + stderr, + "Unimplemented sync method %s::%x(inBufCount=%x, outBufCount=%x)\n", + session->server->name.c_str(), message->methodId, message->numInData, + message->numOutData); + + // for (auto in : inData) { + // std::fprintf(stderr, "in %zx\n", in.size()); + // } + + // for (auto out : outData) { + // std::fprintf(stderr, "out %zx\n", out.size()); + // } + + for (auto out : outData) { + std::memset(out.data(), 0, out.size()); } - - session->responseCv.notify_one(session->mutex); - return {}; + // TODO: + // response.errorCode = message->numOutData == 0 || + // (message->numOutData == 1 && outData[0].empty()) + // ? 0 + // : -1, } - std::fprintf( - stderr, - "Unimplemented sync method %s::%x(inBufCount=%x, outBufCount=%x)\n", - session->server->name.c_str(), message->methodId, message->numInData, - message->numOutData); - - // for (auto in : inData) { - // std::fprintf(stderr, "in %zx\n", in.size()); - // } - - // for (auto out : outData) { - // std::fprintf(stderr, "out %zx\n", out.size()); - // } + for (auto out : outData) { + response.data.push_back(orbis::kvector( + (std::byte *)out.data(), (std::byte *)out.data() + out.size())); + } std::lock_guard lock(session->mutex); - - session->messageResponses.push_front({ - // TODO: - // .errorCode = message->numOutData == 0 || - // (message->numOutData == 1 && outData[0].empty()) - // ? 0 - // : -1, - .errorCode = 0, - .data = orbis::kvector( - message->numOutData ? outData[0].size() : 0), - }); - + session->syncResponses.push_front(std::move(response)); session->responseCv.notify_one(session->mutex); - return {}; + + return result; } }; @@ -929,7 +1012,8 @@ static IpmiServer &createIpmiServer(orbis::Process *process, const char *name) { auto server = std::make_shared(); server->serverImpl = serverImpl; - std::thread{[server, serverImpl] { + std::thread{[server, serverImpl, name] { + pthread_setname_np(pthread_self(), name); while (true) { orbis::IpmiServer::Packet packet; { @@ -964,8 +1048,9 @@ static IpmiServer &createIpmiServer(orbis::Process *process, const char *name) { conReq.client->session = session; for (auto &message : server->messages) { - conReq.client->messages.push_back(orbis::kvector( - message.data(), message.data() + message.size())); + conReq.client->messageQueues[0].messages.push_back( + orbis::kvector(message.data(), + message.data() + message.size())); } conReq.client->sessionCv.notify_all(conReq.client->mutex); @@ -1420,6 +1505,7 @@ int main(int argc, const char *argv[]) { bool enableAudio = false; bool asRoot = false; bool isSystem = false; + bool isSafeMode = false; int argIndex = 1; while (argIndex < argc) { @@ -1459,6 +1545,14 @@ int main(int argc, const char *argv[]) { if (argv[argIndex] == std::string_view("--system")) { argIndex++; isSystem = true; + asRoot = true; + continue; + } + + if (argv[argIndex] == std::string_view("--safemode")) { + argIndex++; + isSafeMode = true; + asRoot = true; continue; } @@ -1503,80 +1597,20 @@ int main(int argc, const char *argv[]) { auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); // pthread_setname_np(pthread_self(), "10.MAINTHREAD"); - std::thread{[] { - pthread_setname_np(pthread_self(), "Bridge"); - auto bridge = rx::bridge.header; - - std::vector fetchedCommands; - fetchedCommands.reserve(std::size(bridge->cacheCommands)); - - while (true) { - for (auto &command : bridge->cacheCommands) { - std::uint64_t value = command.load(std::memory_order::relaxed); - - if (value != 0) { - fetchedCommands.push_back(value); - command.store(0, std::memory_order::relaxed); - } - } - - if (fetchedCommands.empty()) { - continue; - } - - for (auto command : fetchedCommands) { - auto page = static_cast(command); - auto count = static_cast(command >> 32) + 1; - - auto pageFlags = - bridge->cachePages[page].load(std::memory_order::relaxed); - - auto address = - static_cast(page) * amdgpu::bridge::kHostPageSize; - auto origVmProt = rx::vm::getPageProtection(address); - int prot = 0; - - if (origVmProt & rx::vm::kMapProtCpuRead) { - prot |= PROT_READ; - } - if (origVmProt & rx::vm::kMapProtCpuWrite) { - prot |= PROT_WRITE; - } - if (origVmProt & rx::vm::kMapProtCpuExec) { - prot |= PROT_EXEC; - } - - if (pageFlags & amdgpu::bridge::kPageReadWriteLock) { - prot &= ~(PROT_READ | PROT_WRITE); - } else if (pageFlags & amdgpu::bridge::kPageWriteWatch) { - prot &= ~PROT_WRITE; - } - - // std::fprintf(stderr, "protection %lx-%lx\n", address, - // address + amdgpu::bridge::kHostPageSize * count); - if (::mprotect(reinterpret_cast(address), - amdgpu::bridge::kHostPageSize * count, prot)) { - perror("protection failed"); - std::abort(); - } - } - - fetchedCommands.clear(); - } - }}.detach(); - int status = 0; initProcess->sysent = &orbis::ps4_sysvec; initProcess->onSysEnter = onSysEnter; initProcess->onSysExit = onSysExit; initProcess->ops = &rx::procOpsTable; + initProcess->hostPid = ::getpid(); initProcess->appInfo = { .unk4 = (isSystem ? orbis::slong(0x80000000'00000000) : 0), }; if (isSystem) { - amdgpu::bridge::expGpuPid = 50001; + amdgpu::bridge::expGpuPid = isSafeMode ? 20001 : 60001; + orbis::g_context.safeMode = isSafeMode ? 1 : 0; initProcess->authInfo = { .unk0 = 0x380000000000000f, .caps = @@ -1623,6 +1657,7 @@ int main(int argc, const char *argv[]) { mainThread->tproc = initProcess; mainThread->tid = initProcess->pid + baseId; mainThread->state = orbis::ThreadState::RUNNING; + mainThread->hostTid = ::gettid(); auto executableModule = rx::linker::loadModuleFile(argv[argIndex], mainThread); @@ -1653,6 +1688,47 @@ int main(int argc, const char *argv[]) { auto execEnv = ps4CreateExecEnv(mainThread, executableModule, isSystem); + // data transfer mode + // 0 - normal + // 1 - source + // 2 - ? + orbis::g_context.regMgrInt[0x2110000] = 0; + + orbis::g_context.regMgrInt[0x20b0000] = 1; // prefer X + orbis::g_context.regMgrInt[0x2020000] = 1; // region + + // orbis::g_context.regMgrInt[0x2130000] = 0x1601; + orbis::g_context.regMgrInt[0x2130000] = 0; + orbis::g_context.regMgrInt[0x73800200] = 1; + orbis::g_context.regMgrInt[0x73800300] = 0; + orbis::g_context.regMgrInt[0x73800400] = 0; + orbis::g_context.regMgrInt[0x73800500] = 0; // enable log + + // user settings + orbis::g_context.regMgrInt[0x7800100] = 0; + orbis::g_context.regMgrInt[0x7810100] = 0; + orbis::g_context.regMgrInt[0x7820100] = 0; + orbis::g_context.regMgrInt[0x7830100] = 0; + orbis::g_context.regMgrInt[0x7840100] = 0; + orbis::g_context.regMgrInt[0x7850100] = 0; + orbis::g_context.regMgrInt[0x7860100] = 0; + orbis::g_context.regMgrInt[0x7870100] = 0; + orbis::g_context.regMgrInt[0x7880100] = 0; + orbis::g_context.regMgrInt[0x7890100] = 0; + orbis::g_context.regMgrInt[0x78a0100] = 0; + orbis::g_context.regMgrInt[0x78b0100] = 0; + orbis::g_context.regMgrInt[0x78c0100] = 0; + orbis::g_context.regMgrInt[0x78d0100] = 0; + orbis::g_context.regMgrInt[0x78e0100] = 0; + orbis::g_context.regMgrInt[0x78f0100] = 0; + + orbis::g_context.regMgrInt[0x2040000] = 0; // do not require initial setup + orbis::g_context.regMgrInt[0x2800600] = 0; // IDU version + orbis::g_context.regMgrInt[0x2860100] = 0; // IDU mode + orbis::g_context.regMgrInt[0x2860300] = 0; // Arcade mode + orbis::g_context.regMgrInt[0x7010000] = 0; // auto login + orbis::g_context.regMgrInt[0x9010000] = 0; // video out color effect + if (!isSystem) { createMiniSysCoreObjects(initProcess); createSysAvControlObjects(initProcess); @@ -1662,12 +1738,26 @@ int main(int argc, const char *argv[]) { // ? createIpmiServer(initProcess, "SceCdlgRichProf"); - createIpmiServer(initProcess, "SceRemoteplayIpc"); + createIpmiServer(initProcess, "SceRemoteplayIpc"); createIpmiServer(initProcess, "SceGlsIpc"); + createIpmiServer(initProcess, "SceImeService"); + createIpmiServer(initProcess, "SceErrorDlgServ"); + + createEventFlag("SceNpTusIpc_0000000a", 0x120, 0); + createSemaphore("SceLncSuspendBlock00000000", 0x101, 1, 1); + createSemaphore("SceNpPlusLogger 0", 0x101, 0, 0x7fffffff); + + createSemaphore("SceSaveData0000000000000001", 0x101, 0, 1); + createSemaphore("SceSaveData0000000000000001_0", 0x101, 0, 1); + createShm("SceSaveData0000000000000001_0", 0x202, 0x1b6, 0x40000); + createShm("SceSaveDataI0000000000000001", 0x202, 0x1b6, 43008); + createShm("SceSaveDataI0000000000000001_0", 0x202, 0x1b6, 43008); + createEventFlag("SceSaveDataMemoryRUI00000010", 0x120, 1); initProcess->cwd = "/app0/"; launchDaemon(mainThread, "/system/sys/orbis_audiod.elf", {"/system/sys/orbis_audiod.elf"}, {}); + runBridge(); status = ps4Exec(mainThread, execEnv, std::move(executableModule), ps4Argv, {}); } diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 2ac410f8..7c98fcdc 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -1,5 +1,6 @@ #include "ops.hpp" #include "align.hpp" +#include "amdgpu/bridge/bridge.hpp" #include "backtrace.hpp" #include "io-device.hpp" #include "io-devices.hpp" @@ -39,7 +40,10 @@ using namespace orbis; +extern bool allowMonoDebug; + extern "C" void __register_frame(const void *); +void runBridge(); void setupSigHandlers(); int ps4Exec(orbis::Thread *mainThread, orbis::utils::Ref executableModule, @@ -252,7 +256,7 @@ orbis::SysResult minherit(orbis::Thread *thread, orbis::ptr addr, orbis::SysResult madvise(orbis::Thread *thread, orbis::ptr addr, orbis::size_t len, orbis::sint behav) { - return ErrorCode::INVAL; + return {}; } orbis::SysResult mincore(orbis::Thread *thread, orbis::ptr addr, @@ -402,6 +406,10 @@ orbis::SysResult dynlib_get_obj_member(orbis::Thread *thread, case 8: *addrp = module->moduleParam; return {}; + + default: + ORBIS_LOG_ERROR(__FUNCTION__, index); + thread->where(); } return ErrorCode::INVAL; @@ -521,8 +529,9 @@ orbis::SysResult dynlib_unload_prx(orbis::Thread *thread, return ErrorCode::NOTSUP; } -SysResult thr_create(orbis::Thread *thread, orbis::ptr ctxt, +SysResult thr_create(orbis::Thread *thread, orbis::ptr ctxt, ptr arg, orbis::sint flags) { + ORBIS_LOG_FATAL(__FUNCTION__, ctxt, arg, flags); return ErrorCode::NOTSUP; } SysResult thr_new(orbis::Thread *thread, orbis::ptr param, @@ -551,9 +560,10 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr param, // FIXME: implement scheduler - ORBIS_LOG_NOTICE("Starting child thread", childThread->tid, + ORBIS_LOG_NOTICE("Starting child thread", thread->tid, childThread->tid, childThread->stackStart, _param.rtp, _param.name, _param.spare[0], _param.spare[1]); + if (_param.rtp != 0) { rtprio _rtp; ORBIS_RET_ON_ERROR(uread(_rtp, _param.rtp)); @@ -573,6 +583,7 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr param, context->uc_mcontext.gregs[REG_RIP] = reinterpret_cast(_param.start_func); + childThread->hostTid = ::gettid(); childThread->context = context; childThread->state = orbis::ThreadState::RUNNING; @@ -598,23 +609,38 @@ SysResult thr_exit(orbis::Thread *thread, orbis::ptr state) { } // FIXME: implement exit + pthread_setname_np(pthread_self(), "dead"); while (true) { std::this_thread::sleep_for(std::chrono::seconds(60)); } return ErrorCode::NOTSUP; } SysResult thr_kill(orbis::Thread *thread, orbis::slong id, orbis::sint sig) { - return ErrorCode::NOTSUP; + auto t = (std::lock_guard(thread->tproc->mtx), + thread->tproc->threadsMap.get(id - thread->tproc->pid)); + if (t == nullptr) { + return ErrorCode::SRCH; + } + + ORBIS_LOG_FATAL(__FUNCTION__, id, sig, t->hostTid); + std::lock_guard lock(t->tproc->mtx); + t->signalQueue.push_back(sig); + ::tgkill(t->tproc->hostPid, t->hostTid, SIGUSR1); + return {}; } + SysResult thr_kill2(orbis::Thread *thread, orbis::pid_t pid, orbis::slong id, orbis::sint sig) { + ORBIS_LOG_FATAL(__FUNCTION__, pid, id, sig); return ErrorCode::NOTSUP; } SysResult thr_suspend(orbis::Thread *thread, orbis::ptr timeout) { + ORBIS_LOG_FATAL(__FUNCTION__, timeout); return ErrorCode::NOTSUP; } SysResult thr_wake(orbis::Thread *thread, orbis::slong id) { + ORBIS_LOG_FATAL(__FUNCTION__, id); return ErrorCode::NOTSUP; } SysResult thr_set_name(orbis::Thread *thread, orbis::slong id, @@ -626,7 +652,10 @@ SysResult thr_set_name(orbis::Thread *thread, orbis::slong id, orbis::SysResult unmount(orbis::Thread *thread, orbis::ptr path, orbis::sint flags) { // TODO: support other that nullfs - return rx::vfs::unlink(getAbsolutePath(path, thread), thread); + ORBIS_LOG_WARNING(__FUNCTION__, path); + thread->where(); + rx::vfs::unlink(getAbsolutePath(path, thread), thread); + return {}; } orbis::SysResult nmount(orbis::Thread *thread, orbis::ptr iovp, orbis::uint iovcnt, orbis::sint flags) { @@ -747,6 +776,7 @@ SysResult fork(Thread *thread, slong flags) { process->ops = thread->tproc->ops; process->parentProcess = thread->tproc; process->authInfo = thread->tproc->authInfo; + process->sdkVersion = thread->tproc->sdkVersion; for (auto [id, mod] : thread->tproc->modulesMap) { if (!process->modulesMap.insert(id, mod)) { std::abort(); @@ -769,6 +799,7 @@ SysResult fork(Thread *thread, slong flags) { auto [baseId, newThread] = process->threadsMap.emplace(); newThread->tproc = process; + newThread->hostTid = ::gettid(); newThread->tid = process->pid + baseId; newThread->state = orbis::ThreadState::RUNNING; newThread->context = thread->context; @@ -790,9 +821,15 @@ SysResult fork(Thread *thread, slong flags) { dup2(logFd, 1); dup2(logFd, 2); + + if (childPid == amdgpu::bridge::expGpuPid) { + runBridge(); + } return {}; } +volatile bool debuggerPresent = false; + SysResult execve(Thread *thread, ptr fname, ptr> argv, ptr> envv) { ORBIS_LOG_ERROR(__FUNCTION__, fname); @@ -835,7 +872,21 @@ SysResult execve(Thread *thread, ptr fname, ptr> argv, pthread_setname_np(pthread_self(), name.c_str()); } + if (fname == std::string_view{"/app0/eboot.bin"}) { + // FIXME: remove hack + // _envv.push_back("MONO_LOG_LEVEL=debug"); + _envv.push_back("MONO_GC_PARAMS=nursery-size=128m"); + // _envv.push_back("MONO_GC_DEBUG=2,heap-dump=/app0/mono.dump"); + // _envv.push_back("GC_DONT_GC"); + } + std::printf("pid: %u\n", ::getpid()); + + // if (thread->tid == 60001) { + // while (debuggerPresent == false) { + // std::this_thread::sleep_for(std::chrono::seconds(1)); + // } + // } { orbis::Ref file; auto result = rx::vfs::open(path, kOpenFlagReadOnly, 0, &file, thread); diff --git a/rpcsx-os/orbis-kernel-config/orbis-config.hpp b/rpcsx-os/orbis-kernel-config/orbis-config.hpp index 206999c8..8d672112 100644 --- a/rpcsx-os/orbis-kernel-config/orbis-config.hpp +++ b/rpcsx-os/orbis-kernel-config/orbis-config.hpp @@ -143,6 +143,8 @@ inline uint64_t readRegister(void *context, RegisterId id) { return c->gregs[REG_RSP]; case RegisterId::rflags: return c->gregs[REG_EFL]; + case RegisterId::rip: + return c->gregs[REG_RIP]; } std::fprintf(stderr, "***ERROR*** Unhandled RegisterId %d\n", static_cast(id)); @@ -203,6 +205,9 @@ inline void writeRegister(void *context, RegisterId id, uint64_t value) { case RegisterId::rflags: c->gregs[REG_EFL] = value; return; + case RegisterId::rip: + c->gregs[REG_RIP] = value; + return; } } diff --git a/rpcsx-os/thread.cpp b/rpcsx-os/thread.cpp index 41bdd40d..12543da1 100644 --- a/rpcsx-os/thread.cpp +++ b/rpcsx-os/thread.cpp @@ -3,6 +3,7 @@ #include "orbis/sys/sysentry.hpp" #include "orbis/thread/Process.hpp" #include "orbis/thread/Thread.hpp" +#include "orbis/utils/Logs.hpp" #include #include #include @@ -13,6 +14,12 @@ #include #include +static std::size_t getSigStackSize() { + static auto sigStackSize = std::max( + SIGSTKSZ, ::utils::alignUp(64 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); + return sigStackSize; +} + static auto setContext = [] { struct SetContext : Xbyak::CodeGenerator { SetContext() { @@ -33,6 +40,60 @@ static auto setContext = [] { return setContextStorage.getCode(); }(); +static void copy(orbis::MContext &dst, const mcontext_t &src) { + // dst.onstack = src.gregs[REG_ONSTACK]; + dst.rdi = src.gregs[REG_RDI]; + dst.rsi = src.gregs[REG_RSI]; + dst.rdx = src.gregs[REG_RDX]; + dst.rcx = src.gregs[REG_RCX]; + dst.r8 = src.gregs[REG_R8]; + dst.r9 = src.gregs[REG_R9]; + dst.rax = src.gregs[REG_RAX]; + dst.rbx = src.gregs[REG_RBX]; + dst.rbp = src.gregs[REG_RBP]; + dst.r10 = src.gregs[REG_R10]; + dst.r11 = src.gregs[REG_R11]; + dst.r12 = src.gregs[REG_R12]; + dst.r13 = src.gregs[REG_R13]; + dst.r14 = src.gregs[REG_R14]; + dst.r15 = src.gregs[REG_R15]; + dst.trapno = src.gregs[REG_TRAPNO]; + dst.fs = src.gregs[REG_CSGSFS] & 0xffff; + dst.gs = (src.gregs[REG_CSGSFS] >> 16) & 0xffff; + // dst.addr = src.gregs[REG_ADDR]; + // dst.flags = src.gregs[REG_FLAGS]; + // dst.es = src.gregs[REG_ES]; + // dst.ds = src.gregs[REG_DS]; + dst.err = src.gregs[REG_ERR]; + dst.rip = src.gregs[REG_RIP]; + dst.cs = (src.gregs[REG_CSGSFS] >> 32) & 0xffff; + dst.rflags = src.gregs[REG_EFL]; + dst.rsp = src.gregs[REG_RSP]; + // dst.ss = src.gregs[REG_SS]; + dst.len = sizeof(orbis::MContext); + // dst.fpformat = src.gregs[REG_FPFORMAT]; + // dst.ownedfp = src.gregs[REG_OWNEDFP]; + // dst.lbrfrom = src.gregs[REG_LBRFROM]; + // dst.lbrto = src.gregs[REG_LBRTO]; + // dst.aux1 = src.gregs[REG_AUX1]; + // dst.aux2 = src.gregs[REG_AUX2]; + // dst.fpstate = src.gregs[REG_FPSTATE]; + // dst.fsbase = src.gregs[REG_FSBASE]; + // dst.gsbase = src.gregs[REG_GSBASE]; + // dst.xfpustate = src.gregs[REG_XFPUSTATE]; + // dst.xfpustate_len = src.gregs[REG_XFPUSTATE_LEN]; +} + +static void copy(orbis::Thread *thread, orbis::UContext &dst, + const ucontext_t &src) { + dst = {}; + dst.stack.sp = thread->stackStart; + dst.stack.size = (char *)thread->stackEnd - (char *)thread->stackStart; + dst.stack.align = 0x10000; + dst.sigmask = thread->sigMask; + copy(dst.mcontext, src.uc_mcontext); +} + static __attribute__((no_stack_protector)) void handleSigSys(int sig, siginfo_t *info, void *ucontext) { if (auto hostFs = _readgsbase_u64()) { @@ -43,50 +104,163 @@ handleSigSys(int sig, siginfo_t *info, void *ucontext) { // rx::thread::g_current, 1); auto thread = orbis::g_currentThread; auto prevContext = std::exchange(thread->context, ucontext); + { + std::lock_guard lock(thread->mtx); + copy(thread, thread->sigReturns.emplace_back(), + *reinterpret_cast(ucontext)); + } + if ((std::uint64_t)&thread < 0x100'0000'0000) { + ORBIS_LOG_ERROR("unexpected sigsys signal stack", thread->tid, sig, + (std::uint64_t)&thread); + std::abort(); + } + + auto altStack = malloc(getSigStackSize()); + rx::thread::setupSignalStack(altStack); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigaddset(&set, SIGSYS); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); + orbis::syscall_entry(thread); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + + std::free(altStack); + if (thread == orbis::g_currentThread) { + std::lock_guard lock(thread->mtx); + thread->sigReturns.pop_back(); + } thread = orbis::g_currentThread; thread->context = prevContext; _writefsbase_u64(thread->fsBase); } +__attribute__((no_stack_protector)) static void +handleSigUser(int sig, siginfo_t *info, void *ucontext) { + if (auto hostFs = _readgsbase_u64()) { + _writefsbase_u64(hostFs); + } + + auto context = reinterpret_cast(ucontext); + bool inGuestCode = context->uc_mcontext.gregs[REG_RIP] < 0x100'0000'0000; + auto thread = orbis::g_currentThread; + + if ((std::uint64_t)&context < 0x100'0000'0000) { + ORBIS_LOG_ERROR("unexpected sigusr signal stack", thread->tid, sig, + inGuestCode, (std::uint64_t)&context); + std::abort(); + } + + int guestSignal = -3; + { + std::lock_guard lock(thread->mtx); + if (thread->signalQueue.empty()) { + ORBIS_LOG_ERROR("unexpected user signal", thread->tid, sig, inGuestCode); + return; + } + + guestSignal = thread->signalQueue.front(); + thread->signalQueue.pop_front(); + + copy(thread, thread->sigReturns.emplace_back(), *context); + } + + if (guestSignal == -1) { + auto altStack = malloc(getSigStackSize()); + rx::thread::setupSignalStack(altStack); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigaddset(&set, SIGSYS); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); + + thread->suspended++; + // ORBIS_LOG_ERROR("suspending thread", thread->tid); + while (thread->suspended > 0) { + ::sleep(1); + } + + pthread_sigmask(SIG_BLOCK, &set, NULL); + free(altStack); + + // ORBIS_LOG_ERROR("thread wake", thread->tid); + } + + if (guestSignal == -2) { + // ORBIS_LOG_ERROR("thread resume signal", thread->tid); + + std::lock_guard lock(thread->mtx); + thread->sigReturns.pop_back(); + --thread->suspended; + } + + if (inGuestCode) { + _writefsbase_u64(thread->fsBase); + } +} + void rx::thread::initialize() { struct sigaction act {}; act.sa_sigaction = handleSigSys; act.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigaddset(&act.sa_mask, SIGSYS); + sigaddset(&act.sa_mask, SIGUSR1); + if (sigaction(SIGSYS, &act, NULL)) { perror("Error sigaction:"); exit(-1); } + + act.sa_sigaction = handleSigUser; + + if (sigaction(SIGUSR1, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } } void rx::thread::deinitialize() {} -void rx::thread::setupSignalStack() { - stack_t ss{}; +void *rx::thread::setupSignalStack(void *address) { + stack_t ss{}, oss{}; - auto sigStackSize = std::max( - SIGSTKSZ, ::utils::alignUp(64 * 1024 * 1024, sysconf(_SC_PAGE_SIZE))); - - ss.ss_sp = malloc(sigStackSize); - if (ss.ss_sp == NULL) { - perror("malloc"); + if (address == NULL) { + std::fprintf(stderr, "attempt to set null signal stack, %p - %zx\n", + address, getSigStackSize()); std::exit(EXIT_FAILURE); } - ss.ss_size = sigStackSize; + ss.ss_sp = address; + ss.ss_size = getSigStackSize(); ss.ss_flags = 1 << 31; - if (sigaltstack(&ss, NULL) == -1) { + if (sigaltstack(&ss, &oss) == -1) { perror("sigaltstack"); std::exit(EXIT_FAILURE); } + + return oss.ss_sp; +} + +void *rx::thread::setupSignalStack() { + auto data = malloc(getSigStackSize()); + if (data == nullptr) { + std::fprintf(stderr, "malloc produces null, %zx\n", getSigStackSize()); + std::exit(EXIT_FAILURE); + } + return setupSignalStack(data); } void rx::thread::setupThisThread() { sigset_t unblockSigs{}; sigset_t oldSigmask{}; sigaddset(&unblockSigs, SIGSYS); + sigaddset(&unblockSigs, SIGUSR1); if (pthread_sigmask(SIG_UNBLOCK, &unblockSigs, &oldSigmask)) { perror("pthread_sigmask failed\n"); std::exit(-1); diff --git a/rpcsx-os/thread.hpp b/rpcsx-os/thread.hpp index 2794e8b9..3fb41563 100644 --- a/rpcsx-os/thread.hpp +++ b/rpcsx-os/thread.hpp @@ -5,7 +5,8 @@ namespace rx::thread { void initialize(); void deinitialize(); -void setupSignalStack(); +void *setupSignalStack(); +void *setupSignalStack(void *address); void setupThisThread(); void invoke(orbis::Thread *thread); diff --git a/rpcsx-os/vfs.cpp b/rpcsx-os/vfs.cpp index 502497f5..eba498aa 100644 --- a/rpcsx-os/vfs.cpp +++ b/rpcsx-os/vfs.cpp @@ -9,12 +9,39 @@ #include #include + +static orbis::ErrorCode devfs_stat(orbis::File *file, orbis::Stat *sb, + orbis::Thread *thread) { + *sb = {}; // TODO + return {}; +} + + +static orbis::FileOps devfs_ops = { + .stat = devfs_stat, +}; + struct DevFs : IoDevice { std::map, std::less<>> devices; orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override { + if (path[0] == '\0') { + auto result = orbis::knew(); + for (auto &[name, dev] : devices) { + auto &entry = result->dirEntries.emplace_back(); + entry.fileno = result->dirEntries.size(); + entry.reclen = sizeof(orbis::Dirent); + entry.type = orbis::kDtBlk; + entry.namlen = name.size(); + std::strncpy(entry.name, name.c_str(), sizeof(entry.name)); + } + + result->ops = &devfs_ops; + *file = result; + return{}; + } std::string_view devPath = path; if (auto pos = devPath.find('/'); pos != std::string_view::npos) { auto deviceName = devPath.substr(0, pos); @@ -93,6 +120,20 @@ rx::vfs::get(const std::filesystem::path &guestPath) { std::lock_guard lock(gMountMtx); + if (gDevFs != nullptr) { + std::string_view devPath = "/dev/"; + if (path.starts_with(devPath) || + path == devPath.substr(0, devPath.size() - 1)) { + if (path.size() > devPath.size()) { + path.remove_prefix(devPath.size()); + } else { + path = {}; + } + + return { gDevFs, std::string(path) }; + } + } + for (auto &mount : gMountsMap) { if (!path.starts_with(mount.first)) { if (mount.first.size() - 1 != path.size() || diff --git a/rpcsx-os/vm.cpp b/rpcsx-os/vm.cpp index 0b830852..cf5b21d0 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx-os/vm.cpp @@ -820,11 +820,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, flags &= ~kMapFlagsAlignMask; - bool noOverwrite = addr != 0 && (flags & kMapFlagNoOverwrite) == kMapFlagNoOverwrite; - if (noOverwrite) { - flags |= kMapFlagFixed; - } - flags &= ~kMapFlagNoOverwrite; + bool noOverwrite = (flags & (kMapFlagNoOverwrite | kMapFlagFixed)) == (kMapFlagNoOverwrite | kMapFlagFixed); if (hitAddress & (alignment - 1)) { if (flags & kMapFlagStack) { @@ -982,11 +978,11 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } if (auto thr = orbis::g_currentThread) { - std::fprintf(stderr, "sending mapping %lx-%lx, pid %lx\n", address, - address + len, thr->tproc->pid); - if (!noOverwrite) { - rx::bridge.sendMemoryProtect(thr->tproc->pid, address, len, prot); - } + // std::fprintf(stderr, "sending mapping %lx-%lx, pid %lx\n", address, + // address + len, thr->tproc->pid); + // if (!noOverwrite) { + // rx::bridge.sendMemoryProtect(thr->tproc->pid, address, len, prot); + // } } else { std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + len); } @@ -1168,6 +1164,8 @@ bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, auto alloc = *dmemIt; memoryType = alloc.payload.memoryType; blockFlags = kBlockFlagDirectMemory; + std::fprintf(stderr, "virtual query %p", addr); + std::fprintf(stderr, "memory type: %u\n", memoryType); } // TODO }