[orbis-kernel] impi: implement create server/client/session

This commit is contained in:
DH 2023-11-11 02:55:00 +03:00
parent 37295c16a1
commit 8e376c465e
7 changed files with 408 additions and 64 deletions

View file

@ -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

View file

@ -116,14 +116,22 @@ public:
return {};
}
std::pair<IpmiServer *, bool> createIpmiServer(utils::kstring name) {
std::pair<Ref<IpmiServer>, 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<IpmiServer>(it->first);
if (!inserted) {
return {it->second, ErrorCode::EXIST};
}
return {it->second.get(), inserted};
it->second = knew<IpmiServer>(it->first);
if (it->second == nullptr) {
mIpmiServers.erase(it);
return {nullptr, ErrorCode::NOMEM};
}
return {it->second, {}};
}
Ref<IpmiServer> findIpmiServer(std::string_view name) {

View file

@ -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 <list>
namespace orbis {
struct IpmiSession;
struct IpmiClient;
struct Thread;
struct IpmiServer : RcBase {
struct IpmiPacketInfo {
ptr<void> userData;
uint type;
uint clientKid;
ptr<void> eventHandler;
};
static_assert(sizeof(IpmiPacketInfo) == 0x18);
struct Packet {
IpmiPacketInfo info;
kvector<std::byte> message;
};
struct ConnectionRequest {
Ref<IpmiClient> client;
slong clientTid{};
slong clientPid{};
slong serverTid{};
};
kstring name;
ptr<void> serverImpl;
ptr<void> eventHandler;
ptr<void> userData;
shared_mutex mutex;
shared_cv receiveCv;
sint pid;
kdeque<Packet> packets;
std::list<ConnectionRequest, kallocator<ConnectionRequest>>
connectionRequests;
explicit IpmiServer(kstring name) : name(std::move(name)) {}
};
struct IpmiClient : RcBase {
Ref<IpmiServer> connection;
kstring name;
ptr<void> clientImpl;
ptr<void> userData;
Ref<IpmiSession> session;
shared_mutex mutex;
sint pid;
explicit IpmiClient(kstring name) : name(std::move(name)) {}
};
struct IpmiSession : RcBase {
struct MessageResponse {
sint errorCode;
kvector<std::byte> data;
};
ptr<void> sessionImpl;
ptr<void> userData;
Ref<IpmiClient> client;
Ref<IpmiServer> server;
shared_mutex mutex;
shared_cv responseCv;
kdeque<MessageResponse> 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<void> userData;
orbis::ptr<void> eventHandler;
};
static_assert(sizeof(IpmiCreateServerConfig) == 0x38);
ErrorCode ipmiCreateClient(Thread *thread, void *clientImpl, const char *name,
void *config, Ref<IpmiClient> &result);
ErrorCode ipmiCreateServer(Thread *thread, void *serverImpl, const char *name,
const IpmiCreateServerConfig &config,
Ref<IpmiServer> &result);
ErrorCode ipmiCreateSession(Thread *thread, void *sessionImpl,
ptr<void> userData, Ref<IpmiSession> &result);
SysResult sysIpmiCreateClient(Thread *thread, ptr<uint> result,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiCreateServer(Thread *thread, ptr<uint> result,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiCreateSession(Thread *thread, ptr<uint> result,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiDestroyClient(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiDestroyServer(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiDestroySession(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiServerReceivePacket(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionConnectResult(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSessionRespondSync(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionGetClientPid(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiClientConnect(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiServerGetName(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
} // namespace orbis

View file

@ -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<uint> result,
ptr<void> params, uint64_t paramsz, uint64_t arg6);
ptr<void> 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 */);

View file

@ -61,8 +61,7 @@ struct Process final {
utils::RcIdMap<EventFlag, sint, 4097, 1> evfMap;
utils::RcIdMap<Semaphore, sint, 4097, 1> semMap;
utils::RcIdMap<IpmiClient, sint, 4097, 1> ipmiClientMap;
utils::RcIdMap<IpmiServer, sint, 4097, 1> ipmiServerMap;
utils::RcIdMap<RcBase, sint, 4097, 1> ipmiMap;
utils::RcIdMap<Module, ModuleHandle> modulesMap;
utils::OwningIdMap<Thread, lwpid_t> threadsMap;
utils::RcIdMap<orbis::File, sint> fileDescriptors;

243
orbis-kernel/src/ipmi.cpp Normal file
View file

@ -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<IpmiClient> &result) {
auto client = knew<IpmiClient>(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<IpmiServer> &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<void> userData,
Ref<IpmiSession> &result) {
std::unique_lock ipmiMapLock(thread->tproc->ipmiMap.mutex);
for (auto [kid, obj] : thread->tproc->ipmiMap) {
auto server = dynamic_cast<IpmiServer *>(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<IpmiSession>();
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<uint> result,
ptr<void> params,
uint64_t paramsSz) {
struct IpmiCreateClientParams {
orbis::ptr<void> clientImpl;
orbis::ptr<const char> name;
orbis::ptr<void> config; // FIXME: describe
};
static_assert(sizeof(IpmiCreateClientParams) == 0x18);
if (paramsSz != sizeof(IpmiCreateClientParams)) {
return ErrorCode::INVAL;
}
IpmiCreateClientParams _params;
char _name[25];
Ref<IpmiClient> client;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiCreateClientParams>(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<uint>(result, kid);
}
orbis::SysResult orbis::sysIpmiCreateServer(Thread *thread, ptr<uint> result,
ptr<void> params,
uint64_t paramsSz) {
struct IpmiCreateServerParams {
orbis::ptr<void> serverImpl;
orbis::ptr<const char> name;
orbis::ptr<IpmiCreateServerConfig> config;
};
static_assert(sizeof(IpmiCreateServerParams) == 0x18);
if (paramsSz != sizeof(IpmiCreateServerParams)) {
return ErrorCode::INVAL;
}
IpmiCreateServerParams _params;
IpmiCreateServerConfig _config;
char _name[25];
Ref<IpmiServer> server;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiCreateServerParams>(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<uint>(result, kid);
}
orbis::SysResult orbis::sysIpmiCreateSession(Thread *thread, ptr<uint> result,
ptr<void> params,
uint64_t paramsSz) {
struct IpmiSessionUserData {
uint64_t size;
ptr<void> data;
};
static_assert(sizeof(IpmiSessionUserData) == 0x10);
struct IpmiCreateSessionParams {
ptr<void> sessionImpl;
ptr<IpmiSessionUserData> userData;
};
static_assert(sizeof(IpmiCreateSessionParams) == 0x10);
if (paramsSz != sizeof(IpmiCreateSessionParams)) {
return ErrorCode::INVAL;
}
IpmiCreateSessionParams _params;
IpmiSessionUserData _userData;
Ref<IpmiSession> session;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiCreateSessionParams>(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<uint>(result, kid);
}
orbis::SysResult orbis::sysIpmiDestroyClient(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiDestroyServer(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiDestroySession(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiSessionConnectResult(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult
orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz) {
return ErrorCode::NOSYS;
}

View file

@ -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<void> arg0;
orbis::ptr<char> name;
orbis::ptr<void> arg2;
};
static_assert(sizeof(IpmiCreateClientParams) == 0x18);
struct IpmiBufferInfo {
orbis::ptr<void> data;
orbis::uint64_t size;
};
struct IpmiDataInfo {
orbis::ptr<void> data;
orbis::uint64_t size;
};
struct IpmiSyncCallParams {
orbis::uint32_t method;
orbis::uint32_t dataCount;
orbis::uint64_t flags; // ?
orbis::ptr<IpmiDataInfo> pData;
orbis::ptr<IpmiBufferInfo> pBuffers;
orbis::ptr<orbis::sint> pResult;
orbis::uint32_t resultCount;
};
struct IpmiCreateServerParams {
orbis::uint64_t arg0;
orbis::ptr<char> name;
orbis::uint64_t arg2;
};
struct IpmiClientConnectParams {
orbis::ptr<char> arg0;
orbis::ptr<char> name;
orbis::ptr<char> arg2;
orbis::ptr<char> arg3;
};
static_assert(sizeof(IpmiSyncCallParams) == 0x30);
orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid,
ptr<uint> result, ptr<void> 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;