From 8e376c465e602f56ce3047347bd189e2aabe8ef4 Mon Sep 17 00:00:00 2001 From: DH Date: Sat, 11 Nov 2023 02:55:00 +0300 Subject: [PATCH] [orbis-kernel] impi: implement create server/client/session --- orbis-kernel/CMakeLists.txt | 1 + orbis-kernel/include/orbis/KernelContext.hpp | 16 +- orbis-kernel/include/orbis/ipmi.hpp | 116 ++++++++- orbis-kernel/include/orbis/sys/sysproto.hpp | 2 +- orbis-kernel/include/orbis/thread/Process.hpp | 3 +- orbis-kernel/src/ipmi.cpp | 243 ++++++++++++++++++ orbis-kernel/src/sys/sys_sce.cpp | 91 +++---- 7 files changed, 408 insertions(+), 64 deletions(-) create mode 100644 orbis-kernel/src/ipmi.cpp diff --git a/orbis-kernel/CMakeLists.txt b/orbis-kernel/CMakeLists.txt index 72183968a..d494b7e51 100644 --- a/orbis-kernel/CMakeLists.txt +++ b/orbis-kernel/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(obj.orbis-kernel OBJECT src/pipe.cpp src/sysvec.cpp src/evf.cpp + src/ipmi.cpp src/KernelContext.cpp src/umtx.cpp src/sys/sys_acct.cpp diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 15bfeb980..a6e55e9d0 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -116,14 +116,22 @@ public: return {}; } - std::pair createIpmiServer(utils::kstring name) { + std::pair, ErrorCode> createIpmiServer(utils::kstring name) { std::lock_guard lock(m_sem_mtx); auto [it, inserted] = mIpmiServers.try_emplace(std::move(name), nullptr); - if (inserted) { - it->second = knew(it->first); + + if (!inserted) { + return {it->second, ErrorCode::EXIST}; } - return {it->second.get(), inserted}; + it->second = knew(it->first); + + if (it->second == nullptr) { + mIpmiServers.erase(it); + return {nullptr, ErrorCode::NOMEM}; + } + + return {it->second, {}}; } Ref findIpmiServer(std::string_view name) { diff --git a/orbis-kernel/include/orbis/ipmi.hpp b/orbis-kernel/include/orbis/ipmi.hpp index 7f3aeddda..631f4dae1 100644 --- a/orbis-kernel/include/orbis/ipmi.hpp +++ b/orbis-kernel/include/orbis/ipmi.hpp @@ -1,19 +1,133 @@ #pragma once #include "KernelAllocator.hpp" +#include "evf.hpp" +#include "orbis-config.hpp" +#include "orbis/utils/SharedCV.hpp" +#include "orbis/utils/SharedMutex.hpp" #include "utils/Rc.hpp" +#include namespace orbis { +struct IpmiSession; +struct IpmiClient; +struct Thread; + struct IpmiServer : RcBase { + struct IpmiPacketInfo { + ptr userData; + uint type; + uint clientKid; + ptr eventHandler; + }; + + static_assert(sizeof(IpmiPacketInfo) == 0x18); + + struct Packet { + IpmiPacketInfo info; + kvector message; + }; + + struct ConnectionRequest { + Ref client; + slong clientTid{}; + slong clientPid{}; + slong serverTid{}; + }; + kstring name; + ptr serverImpl; + ptr eventHandler; + ptr userData; + shared_mutex mutex; + shared_cv receiveCv; + sint pid; + kdeque packets; + std::list> + connectionRequests; explicit IpmiServer(kstring name) : name(std::move(name)) {} }; struct IpmiClient : RcBase { - Ref connection; kstring name; + ptr clientImpl; + ptr userData; + Ref session; + shared_mutex mutex; + sint pid; explicit IpmiClient(kstring name) : name(std::move(name)) {} }; + +struct IpmiSession : RcBase { + struct MessageResponse { + sint errorCode; + kvector data; + }; + + ptr sessionImpl; + ptr userData; + Ref client; + Ref server; + shared_mutex mutex; + shared_cv responseCv; + kdeque messageResponses; + EventFlag evf{0, 0}; + bool connection = false; // TODO: implement more states +}; + +struct IpmiCreateServerConfig { + orbis::uint64_t size; + orbis::uint32_t unk1; + orbis::uint32_t unk2; + orbis::uint32_t unk3; + orbis::uint32_t unk4; + orbis::uint32_t enableMultipleServerThreads; + orbis::uint32_t unk5; + orbis::uint64_t unk6; + orbis::ptr userData; + orbis::ptr eventHandler; +}; + +static_assert(sizeof(IpmiCreateServerConfig) == 0x38); + +ErrorCode ipmiCreateClient(Thread *thread, void *clientImpl, const char *name, + void *config, Ref &result); +ErrorCode ipmiCreateServer(Thread *thread, void *serverImpl, const char *name, + const IpmiCreateServerConfig &config, + Ref &result); +ErrorCode ipmiCreateSession(Thread *thread, void *sessionImpl, + ptr userData, Ref &result); + +SysResult sysIpmiCreateClient(Thread *thread, ptr result, + ptr params, uint64_t paramsSz); +SysResult sysIpmiCreateServer(Thread *thread, ptr result, + ptr params, uint64_t paramsSz); +SysResult sysIpmiCreateSession(Thread *thread, ptr result, + ptr params, uint64_t paramsSz); + +SysResult sysIpmiDestroyClient(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); +SysResult sysIpmiDestroyServer(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); +SysResult sysIpmiDestroySession(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); + +SysResult sysIpmiServerReceivePacket(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); +SysResult sysIpmiSessionConnectResult(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, + ptr params, uint64_t paramsSz); +SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz); +SysResult sysIpmiClientConnect(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); +SysResult sysIpmiServerGetName(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz); } // namespace orbis diff --git a/orbis-kernel/include/orbis/sys/sysproto.hpp b/orbis-kernel/include/orbis/sys/sysproto.hpp index da110fa47..0a4eaf669 100644 --- a/orbis-kernel/include/orbis/sys/sysproto.hpp +++ b/orbis-kernel/include/orbis/sys/sysproto.hpp @@ -723,7 +723,7 @@ SysResult sys_test_debug_rwmem(Thread *thread /* TODO */); SysResult sys_free_stack(Thread *thread /* TODO */); SysResult sys_suspend_system(Thread *thread /* TODO */); SysResult sys_ipmimgr_call(Thread *thread, uint op, uint kid, ptr result, - ptr params, uint64_t paramsz, uint64_t arg6); + ptr params, uint64_t paramsz); SysResult sys_get_gpo(Thread *thread /* TODO */); SysResult sys_get_vm_map_timestamp(Thread *thread /* TODO */); SysResult sys_opmc_set_hw(Thread *thread /* TODO */); diff --git a/orbis-kernel/include/orbis/thread/Process.hpp b/orbis-kernel/include/orbis/thread/Process.hpp index cf983804b..2f76581c4 100644 --- a/orbis-kernel/include/orbis/thread/Process.hpp +++ b/orbis-kernel/include/orbis/thread/Process.hpp @@ -61,8 +61,7 @@ struct Process final { utils::RcIdMap evfMap; utils::RcIdMap semMap; - utils::RcIdMap ipmiClientMap; - utils::RcIdMap ipmiServerMap; + utils::RcIdMap ipmiMap; utils::RcIdMap modulesMap; utils::OwningIdMap threadsMap; utils::RcIdMap fileDescriptors; diff --git a/orbis-kernel/src/ipmi.cpp b/orbis-kernel/src/ipmi.cpp new file mode 100644 index 000000000..c7215d1cb --- /dev/null +++ b/orbis-kernel/src/ipmi.cpp @@ -0,0 +1,243 @@ +#include "ipmi.hpp" +#include "KernelContext.hpp" +#include "thread/Process.hpp" + +orbis::ErrorCode orbis::ipmiCreateClient(Thread *thread, void *clientImpl, + const char *name, void *config, + Ref &result) { + auto client = knew(name); + if (client == nullptr) { + return ErrorCode::NOMEM; + } + + client->clientImpl = clientImpl; + client->name = name; + client->pid = thread->tproc->pid; + result = client; + return {}; +} + +orbis::ErrorCode orbis::ipmiCreateServer(Thread *thread, void *serverImpl, + const char *name, + const IpmiCreateServerConfig &config, + Ref &result) { + auto [server, errorCode] = g_context.createIpmiServer(name); + ORBIS_RET_ON_ERROR(errorCode); + + server->serverImpl = serverImpl; + server->userData = config.userData; + server->eventHandler = config.eventHandler; + server->pid = thread->tproc->pid; + result = server; + return {}; +} + +orbis::ErrorCode orbis::ipmiCreateSession(Thread *thread, void *sessionImpl, + ptr userData, + Ref &result) { + std::unique_lock ipmiMapLock(thread->tproc->ipmiMap.mutex); + + for (auto [kid, obj] : thread->tproc->ipmiMap) { + auto server = dynamic_cast(obj); + if (server == nullptr) { + continue; + } + + std::lock_guard serverLock(server->mutex); + for (auto &conReq : server->connectionRequests) { + if (conReq.serverTid != thread->tid || + conReq.client->session != nullptr) { + continue; + } + + std::lock_guard clientLock(conReq.client->mutex); + if (conReq.client->session != nullptr) { + continue; + } + + auto session = knew(); + if (session == nullptr) { + return ErrorCode::NOMEM; + } + + result = session; + session->sessionImpl = sessionImpl; + session->userData = userData; + session->client = conReq.client; + session->server = server; + conReq.client->session = session; + + return {}; + } + } + + ORBIS_LOG_ERROR(__FUNCTION__, ": connection request not found"); + return ErrorCode::INVAL; +} + +orbis::SysResult orbis::sysIpmiCreateClient(Thread *thread, ptr result, + ptr params, + uint64_t paramsSz) { + struct IpmiCreateClientParams { + orbis::ptr clientImpl; + orbis::ptr name; + orbis::ptr config; // FIXME: describe + }; + + static_assert(sizeof(IpmiCreateClientParams) == 0x18); + + if (paramsSz != sizeof(IpmiCreateClientParams)) { + return ErrorCode::INVAL; + } + + IpmiCreateClientParams _params; + char _name[25]; + Ref client; + + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + ORBIS_RET_ON_ERROR(ureadString(_name, sizeof(_name), _params.name)); + ORBIS_RET_ON_ERROR( + ipmiCreateClient(thread, _params.clientImpl, _name, nullptr, client)); + + auto kid = thread->tproc->ipmiMap.insert(std::move(client)); + + if (kid == -1) { + return ErrorCode::MFILE; + } + + return uwrite(result, kid); +} + +orbis::SysResult orbis::sysIpmiCreateServer(Thread *thread, ptr result, + ptr params, + uint64_t paramsSz) { + struct IpmiCreateServerParams { + orbis::ptr serverImpl; + orbis::ptr name; + orbis::ptr config; + }; + + static_assert(sizeof(IpmiCreateServerParams) == 0x18); + + if (paramsSz != sizeof(IpmiCreateServerParams)) { + return ErrorCode::INVAL; + } + + IpmiCreateServerParams _params; + IpmiCreateServerConfig _config; + char _name[25]; + Ref server; + + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + ORBIS_RET_ON_ERROR(uread(_config, _params.config)); + ORBIS_RET_ON_ERROR(ureadString(_name, sizeof(_name), _params.name)); + ORBIS_RET_ON_ERROR( + ipmiCreateServer(thread, _params.serverImpl, _name, _config, server)); + auto kid = thread->tproc->ipmiMap.insert(std::move(server)); + + if (kid == -1) { + return ErrorCode::MFILE; + } + + return uwrite(result, kid); +} + +orbis::SysResult orbis::sysIpmiCreateSession(Thread *thread, ptr result, + ptr params, + uint64_t paramsSz) { + struct IpmiSessionUserData { + uint64_t size; + ptr data; + }; + + static_assert(sizeof(IpmiSessionUserData) == 0x10); + + struct IpmiCreateSessionParams { + ptr sessionImpl; + ptr userData; + }; + + static_assert(sizeof(IpmiCreateSessionParams) == 0x10); + + if (paramsSz != sizeof(IpmiCreateSessionParams)) { + return ErrorCode::INVAL; + } + + IpmiCreateSessionParams _params; + IpmiSessionUserData _userData; + Ref session; + + ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); + ORBIS_RET_ON_ERROR(uread(_userData, _params.userData)); + + if (_userData.size != sizeof(IpmiSessionUserData)) { + return ErrorCode::INVAL; + } + + ORBIS_RET_ON_ERROR( + ipmiCreateSession(thread, _params.sessionImpl, _userData.data, session)); + + auto kid = thread->tproc->ipmiMap.insert(std::move(session)); + + if (kid == -1) { + return ErrorCode::MFILE; + } + + return uwrite(result, kid); +} + +orbis::SysResult orbis::sysIpmiDestroyClient(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiDestroyServer(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiDestroySession(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} + +orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiSessionConnectResult(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread, + ptr result, uint kid, + ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult +orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr result, uint kid, + ptr params, uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} +orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr result, + uint kid, ptr params, + uint64_t paramsSz) { + return ErrorCode::NOSYS; +} diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index 2d050d3b9..5761aa952 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -2,6 +2,7 @@ #include "KernelContext.hpp" #include "error.hpp" #include "evf.hpp" +#include "ipmi.hpp" #include "module/ModuleInfo.hpp" #include "module/ModuleInfoEx.hpp" #include "orbis/AudioOut.hpp" @@ -1023,64 +1024,42 @@ orbis::SysResult orbis::sys_suspend_system(Thread *thread /* TODO */) { return ErrorCode::NOSYS; } -enum ImpiOpcode { - kImpiCreateServer = 0, - kImpiDestroyServer = 1, - kIpmiCreateClient = 2, - kImpiDestroyClient = 3, - kImpiCreateSession = 4, - kImpiDestroySession = 5, -}; - -struct IpmiCreateClientParams { - orbis::ptr arg0; - orbis::ptr name; - orbis::ptr arg2; -}; - -static_assert(sizeof(IpmiCreateClientParams) == 0x18); - -struct IpmiBufferInfo { - orbis::ptr data; - orbis::uint64_t size; -}; -struct IpmiDataInfo { - orbis::ptr data; - orbis::uint64_t size; -}; - -struct IpmiSyncCallParams { - orbis::uint32_t method; - orbis::uint32_t dataCount; - orbis::uint64_t flags; // ? - orbis::ptr pData; - orbis::ptr pBuffers; - orbis::ptr pResult; - orbis::uint32_t resultCount; -}; - -struct IpmiCreateServerParams { - orbis::uint64_t arg0; - orbis::ptr name; - orbis::uint64_t arg2; -}; - -struct IpmiClientConnectParams { - orbis::ptr arg0; - orbis::ptr name; - orbis::ptr arg2; - orbis::ptr arg3; -}; - -static_assert(sizeof(IpmiSyncCallParams) == 0x30); - orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, ptr result, ptr params, - uint64_t paramsSz, uint64_t arg6) { - ORBIS_LOG_TODO("sys_ipmimgr_call", thread->tid, op, kid, result, params, - paramsSz, arg6); - thread->where(); - return ErrorCode::NOSYS; + uint64_t paramsSz) { + ORBIS_LOG_TODO(__FUNCTION__, thread->tid, op, kid, result, params, paramsSz); + switch (op) { + case 0: + return sysIpmiCreateServer(thread, result, params, paramsSz); + case 1: + return sysIpmiDestroyServer(thread, result, kid, params, paramsSz); + case 2: + return sysIpmiCreateClient(thread, result, params, paramsSz); + case 3: + return sysIpmiDestroyClient(thread, result, kid, params, paramsSz); + case 4: + return sysIpmiCreateSession(thread, result, params, paramsSz); + case 5: + return sysIpmiDestroySession(thread, result, kid, params, paramsSz); + case 0x10: // trace + return uwrite(result, 0u); + case 0x201: + return sysIpmiServerReceivePacket(thread, result, kid, params, paramsSz); + case 0x212: + return sysIpmiSessionConnectResult(thread, result, kid, params, paramsSz); + case 0x232: + return sysIpmiSessionRespondSync(thread, result, kid, params, paramsSz); + case 0x302: + return sysIpmiSessionGetClientPid(thread, result, kid, params, paramsSz); + case 0x320: + return sysIpmiClientInvokeSyncMethod(thread, result, kid, params, paramsSz); + case 0x400: + return sysIpmiClientConnect(thread, result, kid, params, paramsSz); + case 0x46a: + return sysIpmiServerGetName(thread, result, kid, params, paramsSz); + } + + return ErrorCode::INVAL; } orbis::SysResult orbis::sys_get_gpo(Thread *thread /* TODO */) { return ErrorCode::NOSYS;