diff --git a/orbis-kernel/include/orbis/event.hpp b/orbis-kernel/include/orbis/event.hpp index 686e89802..aa75a99db 100644 --- a/orbis-kernel/include/orbis/event.hpp +++ b/orbis-kernel/include/orbis/event.hpp @@ -1,117 +1,12 @@ #pragma once - #include "file.hpp" -#include "orbis-config.hpp" +#include "note.hpp" #include "utils/SharedCV.hpp" -#include "utils/SharedMutex.hpp" #include -#include -#include namespace orbis { -static constexpr auto kEvFiltRead = -1; -static constexpr auto kEvFiltWrite = -2; -static constexpr auto kEvFiltAio = -3; -static constexpr auto kEvFiltVnode = -4; -static constexpr auto kEvFiltProc = -5; -static constexpr auto kEvFiltSignal = -6; -static constexpr auto kEvFiltTimer = -7; -static constexpr auto kEvFiltFs = -9; -static constexpr auto kEvFiltLio = -10; -static constexpr auto kEvFiltUser = -11; -static constexpr auto kEvFiltPolling = -12; -static constexpr auto kEvFiltDisplay = -13; -static constexpr auto kEvFiltGraphicsCore = -14; -static constexpr auto kEvFiltHrTimer = -15; -static constexpr auto kEvFiltUvdTrap = -16; -static constexpr auto kEvFiltVceTrap = -17; -static constexpr auto kEvFiltSdmaTrap = -18; -static constexpr auto kEvFiltRegEv = -19; -static constexpr auto kEvFiltGpuException = -20; -static constexpr auto kEvFiltGpuSystemException = -21; -static constexpr auto kEvFiltGpuDbgGcEv = -22; -static constexpr auto kEvFiltSysCount = 22; - -// actions -static constexpr auto kEvAdd = 0x0001; -static constexpr auto kEvDelete = 0x0002; -static constexpr auto kEvEnable = 0x0004; -static constexpr auto kEvDisable = 0x0008; - -// flags -static constexpr auto kEvOneshot = 0x0010; -static constexpr auto kEvClear = 0x0020; -static constexpr auto kEvReceipt = 0x0040; -static constexpr auto kEvDispatch = 0x0080; -static constexpr auto kEvSysFlags = 0xf000; -static constexpr auto kEvFlag1 = 0x2000; - -static constexpr auto kEvEof = 0x8000; -static constexpr auto kEvError = 0x4000; - -// kEvFiltUser -static constexpr auto kNoteFFNop = 0x00000000; -static constexpr auto kNoteFFAnd = 0x40000000; -static constexpr auto kNoteFFOr = 0x80000000; -static constexpr auto kNoteFFCopy = 0xc0000000; -static constexpr auto kNoteFFCtrlMask = 0xc0000000; -static constexpr auto kNoteFFlagsMask = 0x00ffffff; -static constexpr auto kNoteTrigger = 0x01000000; - -// kEvFiltProc -static constexpr auto kNoteExit = 0x80000000; -static constexpr auto kNoteFork = 0x40000000; -static constexpr auto kNoteExec = 0x20000000; - -struct KEvent { - uintptr_t ident; - sshort filter; - ushort flags; - uint fflags; - intptr_t data; - ptr udata; -}; - -struct KQueue; - -struct KNote { - shared_mutex mutex; - Ref queue; - KEvent event{}; - bool enabled = true; - bool triggered = false; - void *linked = nullptr; // TODO: use Ref<> - - ~KNote(); -}; - struct KQueue : orbis::File { shared_cv cv; std::list> notes; }; - -struct EventEmitter { - shared_mutex mutex; - std::set, kallocator> notes; - - void emit(uint noteId, intptr_t data = 0) { - std::lock_guard lock(mutex); - - for (auto note : notes) { - if ((note->event.fflags & noteId) == 0) { - continue; - } - - std::lock_guard lock(note->mutex); - - if (note->triggered) { - continue; - } - - note->triggered = true; - note->event.data = data; - note->queue->cv.notify_all(note->queue->mtx); - } - } -}; } // namespace orbis diff --git a/orbis-kernel/include/orbis/file.hpp b/orbis-kernel/include/orbis/file.hpp index ef19226ff..364dd7380 100644 --- a/orbis-kernel/include/orbis/file.hpp +++ b/orbis-kernel/include/orbis/file.hpp @@ -2,6 +2,7 @@ #include "KernelAllocator.hpp" #include "error/ErrorCode.hpp" +#include "note.hpp" #include "stat.hpp" #include "utils/Rc.hpp" #include "utils/SharedMutex.hpp" @@ -44,6 +45,7 @@ struct FileOps { struct File : RcBase { shared_mutex mtx; + EventEmitter event; const FileOps *ops = nullptr; Ref device; std::uint64_t nextOff = 0; diff --git a/orbis-kernel/include/orbis/ipmi.hpp b/orbis-kernel/include/orbis/ipmi.hpp index e4facec71..f0225e3af 100644 --- a/orbis-kernel/include/orbis/ipmi.hpp +++ b/orbis-kernel/include/orbis/ipmi.hpp @@ -78,7 +78,7 @@ struct IpmiSession : RcBase { EventFlag evf{0, 0}; shared_cv connectCv; bool expectedOutput = false; // TODO: verify - bool connected = false; // TODO: implement more states + bool connected = false; // TODO: implement more states sint connectionStatus{0}; }; @@ -121,9 +121,8 @@ SysResult sysIpmiDestroySession(Thread *thread, ptr result, uint kid, SysResult sysIpmiServerReceivePacket(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); -SysResult sysIpmiSendConnectResult(Thread *thread, ptr result, - uint kid, ptr params, - uint64_t paramsSz); +SysResult sysIpmiSendConnectResult(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); SysResult sysIpmiSessionRespondSync(Thread *thread, ptr result, uint kid, ptr params, uint64_t paramsSz); SysResult sysIpmiSessionGetClientPid(Thread *thread, ptr result, uint kid, @@ -137,4 +136,13 @@ 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 sysIpmiClientPollEventFlag(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); +SysResult sysIpmiSessionWaitEventFlag(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); +SysResult sysIpmiSessionSetEventFlag(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); + } // namespace orbis diff --git a/orbis-kernel/include/orbis/note.hpp b/orbis-kernel/include/orbis/note.hpp new file mode 100644 index 000000000..ea3dc1b1d --- /dev/null +++ b/orbis-kernel/include/orbis/note.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include "KernelAllocator.hpp" +#include "orbis-config.hpp" +#include "utils/SharedMutex.hpp" +#include +#include + +namespace orbis { + +static constexpr auto kEvFiltRead = -1; +static constexpr auto kEvFiltWrite = -2; +static constexpr auto kEvFiltAio = -3; +static constexpr auto kEvFiltVnode = -4; +static constexpr auto kEvFiltProc = -5; +static constexpr auto kEvFiltSignal = -6; +static constexpr auto kEvFiltTimer = -7; +static constexpr auto kEvFiltFs = -9; +static constexpr auto kEvFiltLio = -10; +static constexpr auto kEvFiltUser = -11; +static constexpr auto kEvFiltPolling = -12; +static constexpr auto kEvFiltDisplay = -13; +static constexpr auto kEvFiltGraphicsCore = -14; +static constexpr auto kEvFiltHrTimer = -15; +static constexpr auto kEvFiltUvdTrap = -16; +static constexpr auto kEvFiltVceTrap = -17; +static constexpr auto kEvFiltSdmaTrap = -18; +static constexpr auto kEvFiltRegEv = -19; +static constexpr auto kEvFiltGpuException = -20; +static constexpr auto kEvFiltGpuSystemException = -21; +static constexpr auto kEvFiltGpuDbgGcEv = -22; +static constexpr auto kEvFiltSysCount = 22; + +// actions +static constexpr auto kEvAdd = 0x0001; +static constexpr auto kEvDelete = 0x0002; +static constexpr auto kEvEnable = 0x0004; +static constexpr auto kEvDisable = 0x0008; + +// flags +static constexpr auto kEvOneshot = 0x0010; +static constexpr auto kEvClear = 0x0020; +static constexpr auto kEvReceipt = 0x0040; +static constexpr auto kEvDispatch = 0x0080; +static constexpr auto kEvSysFlags = 0xf000; +static constexpr auto kEvFlag1 = 0x2000; + +static constexpr auto kEvEof = 0x8000; +static constexpr auto kEvError = 0x4000; + +// kEvFiltUser +static constexpr auto kNoteFFNop = 0x00000000; +static constexpr auto kNoteFFAnd = 0x40000000; +static constexpr auto kNoteFFOr = 0x80000000; +static constexpr auto kNoteFFCopy = 0xc0000000; +static constexpr auto kNoteFFCtrlMask = 0xc0000000; +static constexpr auto kNoteFFlagsMask = 0x00ffffff; +static constexpr auto kNoteTrigger = 0x01000000; + +// kEvFiltProc +static constexpr auto kNoteExit = 0x80000000; +static constexpr auto kNoteFork = 0x40000000; +static constexpr auto kNoteExec = 0x20000000; + +struct KEvent { + uintptr_t ident; + sshort filter; + ushort flags; + uint fflags; + intptr_t data; + ptr udata; +}; + +struct KQueue; +struct KNote { + shared_mutex mutex; + Ref queue; + KEvent event{}; + bool enabled = true; + bool triggered = false; + void *linked = nullptr; // TODO: use Ref<> + + ~KNote(); +}; + +struct EventEmitter { + shared_mutex mutex; + std::set, kallocator> notes; + + void emit(uint filter, uint fflags = 0, intptr_t data = 0); +}; +} // namespace orbis diff --git a/orbis-kernel/include/orbis/pipe.hpp b/orbis-kernel/include/orbis/pipe.hpp index edb832938..8dc9e637c 100644 --- a/orbis-kernel/include/orbis/pipe.hpp +++ b/orbis-kernel/include/orbis/pipe.hpp @@ -3,9 +3,12 @@ #include "KernelAllocator.hpp" #include "file.hpp" #include "utils/Rc.hpp" +#include "utils/SharedCV.hpp" +#include "utils/SharedMutex.hpp" namespace orbis { struct Pipe final : File { + shared_cv cv; kvector data; }; diff --git a/orbis-kernel/src/event.cpp b/orbis-kernel/src/event.cpp index d528b2653..d68631bcf 100644 --- a/orbis-kernel/src/event.cpp +++ b/orbis-kernel/src/event.cpp @@ -13,3 +13,26 @@ orbis::KNote::~KNote() { proc->event.notes.erase(this); } } + +void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) { + std::lock_guard lock(mutex); + + for (auto note : notes) { + if (note->event.filter != filter) { + continue; + } + if (fflags != 0 && ((note->event.fflags & fflags) == 0)) { + continue; + } + + std::lock_guard lock(note->mutex); + + if (note->triggered) { + continue; + } + + note->triggered = true; + note->event.data = data; + note->queue->cv.notify_all(note->queue->mtx); + } +} diff --git a/orbis-kernel/src/ipmi.cpp b/orbis-kernel/src/ipmi.cpp index b81c5f284..49498b6e3 100644 --- a/orbis-kernel/src/ipmi.cpp +++ b/orbis-kernel/src/ipmi.cpp @@ -704,3 +704,73 @@ orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr result, return uwrite(result, 0); } + +orbis::SysResult orbis::sysIpmiClientPollEventFlag(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct IpmiPollEventFlagParam { + uint64_t index; + uint64_t patternSet; + uint64_t mode; + ptr pPatternSet; + }; + + static_assert(sizeof(IpmiPollEventFlagParam) == 0x20); + + if (paramsSz != sizeof(IpmiPollEventFlagParam)) { + return ErrorCode::INVAL; + } + + IpmiPollEventFlagParam _params; + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + + auto client = thread->tproc->ipmiMap.get(kid).cast(); + + if (client == nullptr) { + return ErrorCode::INVAL; + } + + ORBIS_LOG_TODO(__FUNCTION__, client->name, _params.index, _params.patternSet, _params.mode, _params.pPatternSet); + ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, 0u)); + // client->evf.set(_params.a); + return ErrorCode::BUSY; +} + +orbis::SysResult orbis::sysIpmiSessionWaitEventFlag(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + ORBIS_LOG_TODO(__FUNCTION__, paramsSz); + thread->where(); + return uwrite(result, 0); +} + +orbis::SysResult orbis::sysIpmiSessionSetEventFlag(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + struct IpmiSetEventFlagParam { + uint64_t patternSet; + uint64_t index; + }; + + static_assert(sizeof(IpmiSetEventFlagParam) == 0x10); + + if (paramsSz != sizeof(IpmiSetEventFlagParam)) { + return ErrorCode::INVAL; + } + + IpmiSetEventFlagParam _params; + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + + auto session = thread->tproc->ipmiMap.get(kid).cast(); + + if (session == nullptr) { + return ErrorCode::INVAL; + } + + ORBIS_LOG_TODO(__FUNCTION__, session->client->name, _params.patternSet, _params.index); + session->evf.set(_params.patternSet); + return uwrite(result, 0); +} diff --git a/orbis-kernel/src/pipe.cpp b/orbis-kernel/src/pipe.cpp index de325df9f..83b7367b1 100644 --- a/orbis-kernel/src/pipe.cpp +++ b/orbis-kernel/src/pipe.cpp @@ -3,17 +3,13 @@ #include "file.hpp" #include "uio.hpp" #include -#include static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { auto pipe = static_cast(file); while (true) { if (pipe->data.empty()) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - if (pipe->data.empty()) { + pipe->cv.wait(file->mtx); continue; } @@ -33,6 +29,8 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio, break; } + + file->event.emit(orbis::kEvFiltWrite); return {}; } @@ -45,6 +43,9 @@ static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio, pipe->data.resize(offset + vec.len); std::memcpy(pipe->data.data(), vec.base, vec.len); } + + file->event.emit(orbis::kEvFiltRead); + pipe->cv.notify_one(file->mtx); uio->resid = 0; return {}; } diff --git a/orbis-kernel/src/sys/sys_event.cpp b/orbis-kernel/src/sys/sys_event.cpp index d630ba918..e88e7ba6b 100644 --- a/orbis-kernel/src/sys/sys_event.cpp +++ b/orbis-kernel/src/sys/sys_event.cpp @@ -34,7 +34,7 @@ orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr name, } namespace orbis { -static SysResult keventChange(KQueue *kq, KEvent &change) { +static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { auto nodeIt = kq->notes.end(); for (auto it = kq->notes.begin(); it != kq->notes.end(); ++it) { if (it->event.ident == change.ident && it->event.filter == change.filter) { @@ -73,6 +73,22 @@ static SysResult keventChange(KQueue *kq, KEvent &change) { std::unique_lock lock(process->event.mutex); process->event.notes.insert(&*nodeIt); nodeIt->linked = process; + } else if (change.filter == kEvFiltRead || + change.filter == kEvFiltWrite) { + auto fd = thread->tproc->fileDescriptors.get(change.ident); + + if (fd == nullptr) { + return ErrorCode::BADF; + } + + std::unique_lock lock(fd->event.mutex); + + if (change.filter == kEvFiltWrite) { + nodeIt->triggered = true; + kq->cv.notify_all(kq->mtx); + } + + fd->event.notes.insert(&*nodeIt); } } } @@ -121,7 +137,7 @@ static SysResult keventChange(KQueue *kq, KEvent &change) { kq->cv.notify_all(kq->mtx); } } else if (change.filter == kEvFiltGraphicsCore || - change.filter == kEvFiltDisplay) { + change.filter == kEvFiltDisplay || change.filter == kEvFiltRegEv) { nodeIt->triggered = true; kq->cv.notify_all(kq->mtx); } @@ -163,7 +179,8 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, ORBIS_LOG_TODO(__FUNCTION__, change.ident, change.filter, change.flags, change.fflags, change.data, change.udata); - if (auto result = keventChange(kq.get(), change); result.value() != 0) { + if (auto result = keventChange(kq.get(), change, thread); + result.value() != 0) { return result; } } @@ -208,10 +225,15 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd, } auto ¬e = *it; + std::lock_guard lock(note.mutex); if (note.enabled && note.triggered) { result.push_back(note.event); + if (note.event.flags & kEvDispatch) { + note.enabled = false; + } + if (note.event.flags & kEvOneshot) { it = kq->notes.erase(it); continue; diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index 831fba678..fe9de8a53 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -1107,6 +1107,10 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, return sysIpmiSessionGetUserData(thread, result, kid, params, paramsSz); case 0x46a: return sysIpmiServerGetName(thread, result, kid, params, paramsSz); + case 0x491: + return sysIpmiClientPollEventFlag(thread, result, kid, params, paramsSz); + case 0x493: + return sysIpmiSessionSetEventFlag(thread, result, kid, params, paramsSz); } ORBIS_LOG_TODO(__FUNCTION__, thread->tid, op, kid, result, params, paramsSz); diff --git a/orbis-kernel/src/sys/sys_uipc.cpp b/orbis-kernel/src/sys/sys_uipc.cpp index 59fe81d74..3f616da8d 100644 --- a/orbis-kernel/src/sys/sys_uipc.cpp +++ b/orbis-kernel/src/sys/sys_uipc.cpp @@ -1,5 +1,6 @@ #include "pipe.hpp" #include "sys/sysproto.hpp" +#include "uio.hpp" #include "utils/Logs.hpp" #include #include @@ -68,7 +69,26 @@ orbis::SysResult orbis::sys_recvfrom(Thread *thread, sint s, caddr_t buf, size_t len, sint flags, ptr from, ptr fromlenaddr) { - return ErrorCode::NOSYS; + auto pipe = thread->tproc->fileDescriptors.get(s).cast(); + if (pipe == nullptr) { + return ErrorCode::INVAL; + } + + std::lock_guard lock(pipe->mtx); + IoVec io = { + .base = buf, + .len = len, + }; + Uio uio{ + .iov = &io, + .iovcnt = 1, + .segflg = UioSeg::UserSpace, + .rw = UioRw::Read, + .td = thread, + }; + pipe->ops->read(pipe.get(), &uio, thread); + thread->retval[0] = uio.offset; + return {}; } orbis::SysResult orbis::sys_recvmsg(Thread *thread, sint s, ptr msg, sint flags) { diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 806fbf384..c3edd9cee 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -641,7 +641,7 @@ orbis::SysResult nmount(orbis::Thread *thread, orbis::ptr iovp, orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) { std::printf("Requested exit with status %d\n", status); - thread->tproc->event.emit(orbis::kNoteExit, status); + thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExit, status); std::exit(status); } @@ -706,7 +706,7 @@ SysResult fork(Thread *thread, slong flags) { kfree(flag, sizeof(*flag)); - thread->tproc->event.emit(orbis::kNoteFork, childPid); + thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteFork, childPid); thread->retval[0] = childPid; thread->retval[1] = 0; return {}; @@ -828,7 +828,7 @@ SysResult execve(Thread *thread, ptr fname, ptr> argv, thread->tproc->processParam = executableModule->processParam; thread->tproc->processParamSize = executableModule->processParamSize; - thread->tproc->event.emit(orbis::kNoteExec); + thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec); ORBIS_LOG_ERROR(__FUNCTION__, "done"); std::thread([&] {