mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
1405 lines
41 KiB
C++
1405 lines
41 KiB
C++
#include "ipmi.hpp"
|
|
#include "KernelContext.hpp"
|
|
#include "thread/Process.hpp"
|
|
#include "thread/Thread.hpp"
|
|
#include "utils/Logs.hpp"
|
|
#include <chrono>
|
|
#include <span>
|
|
|
|
orbis::ErrorCode orbis::ipmiCreateClient(Process *proc, void *clientImpl,
|
|
const char *name,
|
|
const IpmiCreateClientConfig &config,
|
|
rx::Ref<IpmiClient> &result) {
|
|
auto client = knew<IpmiClient>(name);
|
|
if (client == nullptr) {
|
|
return ErrorCode::NOMEM;
|
|
}
|
|
|
|
client->clientImpl = clientImpl;
|
|
client->name = name;
|
|
client->process = proc;
|
|
client->userData = config.userData;
|
|
client->eventFlags.resize(32);
|
|
client->messageQueues.resize(32);
|
|
result = client;
|
|
return {};
|
|
}
|
|
|
|
orbis::ErrorCode orbis::ipmiCreateServer(Process *proc, void *serverImpl,
|
|
const char *name,
|
|
const IpmiCreateServerConfig &config,
|
|
rx::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 = proc->pid;
|
|
result = server;
|
|
return {};
|
|
}
|
|
|
|
orbis::ErrorCode orbis::ipmiCreateSession(Thread *thread, void *sessionImpl,
|
|
ptr<void> userData,
|
|
rx::Ref<IpmiSession> &result) {
|
|
std::unique_lock ipmiMapLock(g_context->ipmiMap.mutex);
|
|
|
|
for (auto [kid, obj] : g_context->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 ||
|
|
conReq.client->name != server->name) {
|
|
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;
|
|
conReq.client->sessionCv.notify_one(conReq.client->mutex);
|
|
|
|
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) {
|
|
if (paramsSz != sizeof(IpmiCreateClientParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiCreateClientParams _params;
|
|
IpmiCreateClientConfig _config;
|
|
char _name[25];
|
|
rx::Ref<IpmiClient> client;
|
|
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiCreateClientParams>(params)));
|
|
ORBIS_RET_ON_ERROR(uread(_config, _params.config));
|
|
ORBIS_RET_ON_ERROR(ureadString(_name, sizeof(_name), _params.name));
|
|
ORBIS_RET_ON_ERROR(ipmiCreateClient(thread->tproc, _params.clientImpl, _name,
|
|
_config, client));
|
|
|
|
auto kid = g_context->ipmiMap.insert(std::move(client));
|
|
|
|
if (kid == -1) {
|
|
return ErrorCode::MFILE;
|
|
}
|
|
|
|
ORBIS_LOG_ERROR(__FUNCTION__, kid, _name);
|
|
return uwrite<uint>(result, kid);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiCreateServer(Thread *thread, ptr<uint> result,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiCreateServerParams {
|
|
ptr<void> serverImpl;
|
|
ptr<const char> name;
|
|
ptr<IpmiCreateServerConfig> config;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiCreateServerParams) == 0x18);
|
|
|
|
if (paramsSz != sizeof(IpmiCreateServerParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiCreateServerParams _params;
|
|
IpmiCreateServerConfig _config;
|
|
char _name[25];
|
|
rx::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->tproc, _params.serverImpl, _name,
|
|
_config, server));
|
|
auto kid = g_context->ipmiMap.insert(std::move(server));
|
|
|
|
if (kid == -1) {
|
|
return ErrorCode::MFILE;
|
|
}
|
|
|
|
ORBIS_LOG_ERROR(__FUNCTION__, kid, _name);
|
|
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;
|
|
rx::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 = g_context->ipmiMap.insert(std::move(session));
|
|
|
|
if (kid == -1) {
|
|
return ErrorCode::MFILE;
|
|
}
|
|
|
|
ORBIS_LOG_ERROR(__FUNCTION__, kid);
|
|
return uwrite<uint>(result, kid);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiDestroyClient(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
ORBIS_LOG_TODO(__FUNCTION__);
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
orbis::SysResult orbis::sysIpmiDestroyServer(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
ORBIS_LOG_TODO(__FUNCTION__);
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
orbis::SysResult orbis::sysIpmiDestroySession(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
ORBIS_LOG_TODO(__FUNCTION__);
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiServerReceivePacketParams {
|
|
ptr<void> buffer;
|
|
uint64_t bufferSize;
|
|
ptr<IpmiServer::IpmiPacketInfo> receivePacketInfo;
|
|
ptr<uint> unk;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiServerReceivePacketParams)) {
|
|
return orbis::ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiServerReceivePacketParams _params;
|
|
|
|
ORBIS_RET_ON_ERROR(
|
|
uread(_params, ptr<IpmiServerReceivePacketParams>(params)));
|
|
|
|
auto server = g_context->ipmiMap.get(kid).cast<IpmiServer>();
|
|
|
|
if (server == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiServer::Packet _packet;
|
|
|
|
{
|
|
std::lock_guard lock(server->mutex);
|
|
while (server->packets.empty()) {
|
|
orbis::scoped_unblock unblock;
|
|
server->receiveCv.wait(server->mutex);
|
|
}
|
|
|
|
_packet = std::move(server->packets.front());
|
|
server->packets.pop_front();
|
|
}
|
|
|
|
if (_packet.info.type == 0x1) {
|
|
// on connection packet
|
|
|
|
for (auto &conn : server->connectionRequests) {
|
|
if (conn.clientTid == _packet.info.inputSize) {
|
|
conn.serverTid = thread->tid;
|
|
_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);
|
|
}
|
|
|
|
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<std::byte>)_params.buffer,
|
|
_packet.message.data(), _packet.message.size()));
|
|
_params.bufferSize = _packet.message.size();
|
|
_packet.info.eventHandler = server->eventHandler;
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.receivePacketInfo, _packet.info));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwrite(ptr<IpmiServerReceivePacketParams>(params), _params));
|
|
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
orbis::SysResult orbis::sysIpmiSendConnectResult(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
if (paramsSz != sizeof(sint)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
ORBIS_LOG_NOTICE(__FUNCTION__, kid);
|
|
|
|
auto ipmiObject = g_context->ipmiMap.get(kid);
|
|
if (ipmiObject == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
rx::Ref<IpmiClient> client;
|
|
if (auto result = ipmiObject.cast<IpmiSession>()) {
|
|
client = result->client;
|
|
} else if (auto result = ipmiObject.cast<IpmiClient>()) {
|
|
client = result;
|
|
} else if (auto result = ipmiObject.cast<IpmiServer>()) {
|
|
for (auto &request : result->connectionRequests) {
|
|
if (request.serverTid == thread->tid) {
|
|
client = request.client;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (client == nullptr) {
|
|
ORBIS_LOG_FATAL(__FUNCTION__);
|
|
std::abort();
|
|
}
|
|
|
|
sint status;
|
|
ORBIS_RET_ON_ERROR(uread(status, ptr<sint>(params)));
|
|
|
|
ORBIS_LOG_NOTICE(__FUNCTION__, kid, status);
|
|
std::lock_guard lock(client->mutex);
|
|
client->connectionStatus = status;
|
|
client->connectCv.notify_all(client->mutex);
|
|
client->sessionCv.notify_all(client->mutex);
|
|
return uwrite(result, 0u);
|
|
}
|
|
orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiRespondParams {
|
|
sint errorCode;
|
|
uint32_t bufferCount;
|
|
ptr<IpmiBufferInfo> buffers;
|
|
uint32_t flags;
|
|
uint32_t padding;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiRespondParams) == 0x18);
|
|
if (paramsSz != sizeof(IpmiRespondParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiRespondParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiRespondParams>(params)));
|
|
|
|
kvector<kvector<std::byte>> buffers;
|
|
|
|
// 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));
|
|
|
|
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);
|
|
|
|
std::uint32_t clientTid;
|
|
{
|
|
std::lock_guard serverLock(session->server->mutex);
|
|
clientTid = session->server->tidToClientTid.at(thread->tid);
|
|
}
|
|
|
|
ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode);
|
|
|
|
if (_params.errorCode != 0) {
|
|
ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode);
|
|
thread->where();
|
|
}
|
|
|
|
session->syncResponses.push_front({
|
|
.errorCode = _params.errorCode,
|
|
.callerTid = clientTid,
|
|
.data = std::move(buffers),
|
|
});
|
|
|
|
session->responseCv.notify_all(session->mutex);
|
|
return uwrite(result, 0u);
|
|
}
|
|
orbis::SysResult orbis::sysIpmiClientInvokeAsyncMethod(Thread *thread,
|
|
ptr<uint> result,
|
|
uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiAsyncCallParams {
|
|
uint32_t method;
|
|
uint32_t evfIndex;
|
|
uint64_t evfValue;
|
|
uint32_t numInData;
|
|
uint32_t padding1;
|
|
ptr<IpmiDataInfo> pInData;
|
|
ptr<sint> pResult;
|
|
uint32_t flags;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiAsyncCallParams) == 0x30);
|
|
|
|
if (paramsSz != sizeof(IpmiAsyncCallParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiAsyncCallParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, (ptr<IpmiAsyncCallParams>)params));
|
|
|
|
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<std::byte> 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<char *>(msg + 1);
|
|
|
|
for (auto &data : std::span(_params.pInData, _params.numInData)) {
|
|
*std::bit_cast<uint32_t *>(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.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<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiAsyncRespondParams {
|
|
uint method;
|
|
uint pid;
|
|
sint result;
|
|
uint32_t numOutData;
|
|
ptr<IpmiDataInfo> pOutData;
|
|
uint32_t unk2; // == 1
|
|
};
|
|
|
|
static_assert(sizeof(IpmiAsyncRespondParams) == 0x20);
|
|
|
|
if (paramsSz != sizeof(IpmiAsyncRespondParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
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<IpmiAsyncRespondParams>)params));
|
|
|
|
kvector<kvector<std::byte>> 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),
|
|
});
|
|
}
|
|
|
|
client->asyncResponseCv.notify_all(client->mutex);
|
|
return uwrite(result, 0u);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientTryGetResult(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiTryGetResultParams {
|
|
uint32_t method;
|
|
uint32_t unk;
|
|
ptr<sint> pResult;
|
|
uint32_t numOutData;
|
|
uint32_t padding;
|
|
ptr<IpmiBufferInfo> pOutData;
|
|
uint64_t padding2;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiTryGetResultParams) == 0x28);
|
|
|
|
if (paramsSz != sizeof(IpmiTryGetResultParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiTryGetResultParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, (ptr<IpmiTryGetResultParams>)params));
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
orbis::scoped_unblock unblock;
|
|
client->asyncResponseCv.wait(client->mutex);
|
|
}
|
|
|
|
// return uwrite(result, 0x80020000 + static_cast<int>(ErrorCode::AGAIN));
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct SceIpmiClientGetArgs {
|
|
uint32_t queueIndex;
|
|
uint32_t padding;
|
|
ptr<std::byte> message;
|
|
ptr<uint64_t> pSize;
|
|
uint64_t maxSize;
|
|
ptr<uint> pTimeout;
|
|
};
|
|
|
|
static_assert(sizeof(SceIpmiClientGetArgs) == 0x28);
|
|
|
|
if (paramsSz != sizeof(SceIpmiClientGetArgs)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
SceIpmiClientGetArgs _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientGetArgs>(params)));
|
|
|
|
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_RET_ON_ERROR(uread(timeout, _params.pTimeout));
|
|
timeoutPoint = clock::now() + std::chrono::microseconds(timeout);
|
|
}
|
|
|
|
if (queue.messages.empty()) {
|
|
if (timeoutPoint != clock::time_point::max()) {
|
|
while (true) {
|
|
auto now = clock::now();
|
|
if (now >= timeoutPoint) {
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pTimeout, 0u));
|
|
return uwrite<uint>(
|
|
result, 0x80020000 + static_cast<int>(ErrorCode::TIMEDOUT));
|
|
}
|
|
|
|
auto waitTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
timeoutPoint - now);
|
|
|
|
{
|
|
orbis::scoped_unblock unblock;
|
|
queue.messageCv.wait(client->mutex, waitTime.count());
|
|
}
|
|
|
|
if (!queue.messages.empty()) {
|
|
now = clock::now();
|
|
|
|
if (now >= timeoutPoint) {
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pTimeout, 0u));
|
|
} else {
|
|
std::uint32_t restTime =
|
|
std::chrono::duration_cast<std::chrono::microseconds>(
|
|
timeoutPoint - now)
|
|
.count();
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pTimeout, restTime));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (queue.messages.empty()) {
|
|
orbis::scoped_unblock unblock;
|
|
queue.messageCv.wait(client->mutex);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto &message = queue.messages.front();
|
|
|
|
if (_params.maxSize < message.size()) {
|
|
ORBIS_LOG_ERROR(__FUNCTION__, "too small buffer");
|
|
return uwrite<uint>(result,
|
|
0x80020000 + static_cast<int>(ErrorCode::INVAL));
|
|
}
|
|
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pSize, message.size()));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwriteRaw(_params.message, message.data(), message.size()));
|
|
queue.messages.pop_front();
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientTryGetMessage(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct SceIpmiClientTryGetArgs {
|
|
uint32_t queueIndex;
|
|
uint32_t padding;
|
|
ptr<std::byte> message;
|
|
ptr<uint64_t> pSize;
|
|
uint64_t maxSize;
|
|
};
|
|
|
|
static_assert(sizeof(SceIpmiClientTryGetArgs) == 0x20);
|
|
|
|
if (paramsSz != sizeof(SceIpmiClientTryGetArgs)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
SceIpmiClientTryGetArgs _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientTryGetArgs>(params)));
|
|
|
|
std::lock_guard lock(client->mutex);
|
|
|
|
if (_params.queueIndex >= client->messageQueues.size()) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto &queue = client->messageQueues[_params.queueIndex];
|
|
|
|
if (queue.messages.empty()) {
|
|
return uwrite<uint>(result,
|
|
0x80020000 + static_cast<int>(ErrorCode::AGAIN));
|
|
}
|
|
|
|
auto &message = queue.messages.front();
|
|
|
|
if (_params.maxSize < message.size()) {
|
|
ORBIS_LOG_ERROR(__FUNCTION__, "too small buffer");
|
|
return uwrite<uint>(result,
|
|
0x80020000 + static_cast<int>(ErrorCode::INVAL));
|
|
}
|
|
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pSize, message.size()));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwriteRaw(_params.message, message.data(), message.size()));
|
|
queue.messages.pop_front();
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiSessionTrySendMessage(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct SceIpmiClientTrySendArgs {
|
|
uint32_t queueIndex;
|
|
uint32_t padding;
|
|
ptr<std::byte> message;
|
|
uint64_t size;
|
|
};
|
|
|
|
static_assert(sizeof(SceIpmiClientTrySendArgs) == 0x18);
|
|
|
|
if (paramsSz != sizeof(SceIpmiClientTrySendArgs)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
SceIpmiClientTrySendArgs _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientTrySendArgs>(params)));
|
|
|
|
std::lock_guard lock(session->mutex);
|
|
|
|
if (session->client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = session->client;
|
|
std::lock_guard lockClient(client->mutex);
|
|
|
|
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));
|
|
queue.messageCv.notify_all(client->mutex);
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientDisconnect(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct SceIpmiClientDisconnectArgs {
|
|
ptr<sint> status;
|
|
};
|
|
|
|
if (paramsSz != sizeof(SceIpmiClientDisconnectArgs)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
SceIpmiClientDisconnectArgs _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<SceIpmiClientDisconnectArgs>(params)));
|
|
|
|
ORBIS_LOG_ERROR(__FUNCTION__, client->name, _params.status);
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.status, 0));
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiSessionGetClientPid(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiGetClientPidParams {
|
|
ptr<uint32_t> pid;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiGetClientPidParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiGetClientPidParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiGetClientPidParams>(params)));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwrite<uint32_t>(_params.pid, session->client->process->pid));
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult
|
|
orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result, uint kid,
|
|
ptr<void> params, uint64_t paramsSz) {
|
|
if (paramsSz != sizeof(IpmiSyncCallParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiSyncCallParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, (ptr<IpmiSyncCallParams>)params));
|
|
|
|
if (_params.flags > 1) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
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 headerSize = sizeof(IpmiSyncMessageHeader) + inSize +
|
|
_params.numInData * sizeof(uint32_t);
|
|
auto size = headerSize + _params.numOutData * sizeof(uint);
|
|
|
|
kvector<std::byte> message(size);
|
|
auto msg = new (message.data()) IpmiSyncMessageHeader;
|
|
msg->sessionImpl = session->sessionImpl;
|
|
msg->pid = thread->tproc->pid;
|
|
msg->methodId = _params.method;
|
|
msg->numInData = _params.numInData;
|
|
msg->numOutData = _params.numOutData;
|
|
|
|
auto bufLoc = std::bit_cast<char *>(msg + 1);
|
|
|
|
for (auto &data : std::span(_params.pInData, _params.numInData)) {
|
|
*std::bit_cast<uint32_t *>(bufLoc) = data.size;
|
|
bufLoc += sizeof(uint32_t);
|
|
ORBIS_RET_ON_ERROR(ureadRaw(bufLoc, data.data, data.size));
|
|
bufLoc += data.size;
|
|
}
|
|
|
|
for (auto &data : std::span(_params.pOutData, _params.numOutData)) {
|
|
*std::bit_cast<uint32_t *>(bufLoc) = data.capacity;
|
|
bufLoc += sizeof(uint32_t);
|
|
}
|
|
|
|
uint type = 0x41;
|
|
|
|
if ((_params.flags & 1) == 0) {
|
|
type |= 0x10;
|
|
}
|
|
|
|
if (server->pid == thread->tproc->pid) {
|
|
type |= 0x8000;
|
|
}
|
|
|
|
server->packets.push_back(
|
|
{{.inputSize = headerSize, .type = type, .clientKid = kid},
|
|
thread->tid,
|
|
session,
|
|
std::move(message)});
|
|
server->receiveCv.notify_one(server->mutex);
|
|
}
|
|
|
|
IpmiSession::SyncResponse response;
|
|
|
|
while (true) {
|
|
{
|
|
orbis::scoped_unblock unblock;
|
|
session->responseCv.wait(session->mutex);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pResult, response.errorCode));
|
|
|
|
if (response.data.size() != _params.numOutData) {
|
|
ORBIS_LOG_ERROR(__FUNCTION__, "responses amount 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;
|
|
}
|
|
|
|
// ORBIS_LOG_ERROR(__FUNCTION__, server->name, 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));
|
|
}
|
|
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
if (paramsSz != sizeof(IpmiClientConnectParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
if (client->session != nullptr) {
|
|
return ErrorCode::EXIST;
|
|
}
|
|
|
|
IpmiClientConnectParams _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiClientConnectParams>(params)));
|
|
|
|
auto server = g_context->findIpmiServer(client->name);
|
|
|
|
if (server == nullptr) {
|
|
return SysResult::notAnError(ErrorCode::NOENT);
|
|
}
|
|
|
|
std::lock_guard clientLock(client->mutex);
|
|
|
|
decltype(server->connectionRequests)::iterator requestIt;
|
|
|
|
{
|
|
std::lock_guard serverLock(server->mutex);
|
|
|
|
for (auto &connReq : server->connectionRequests) {
|
|
if (connReq.client == client) {
|
|
return ErrorCode::EXIST;
|
|
}
|
|
}
|
|
|
|
server->connectionRequests.push_front({
|
|
.client = client,
|
|
.clientTid = thread->tid,
|
|
.clientPid = thread->tproc->pid,
|
|
});
|
|
|
|
requestIt = server->connectionRequests.begin();
|
|
|
|
struct QueueStats {
|
|
uint maxOutstanding;
|
|
uint unk;
|
|
ulong inDataSizeHardLimit;
|
|
ulong outDataSizeHardLimit;
|
|
};
|
|
|
|
struct ConnectMessageHeader {
|
|
uint32_t clientPid;
|
|
uint32_t clientKid;
|
|
QueueStats sync;
|
|
QueueStats async;
|
|
uint numEventFlag;
|
|
uint unk1;
|
|
uint numMsgQueue;
|
|
uint unk2;
|
|
ulong msgQueueSize[32];
|
|
ulong memorySize;
|
|
};
|
|
|
|
static_assert(sizeof(ConnectMessageHeader) == 0x150);
|
|
|
|
kvector<std::byte> message{
|
|
sizeof(ConnectMessageHeader) + sizeof(uint) +
|
|
std::max<std::size_t>(_params.userDataLen, 0x10)};
|
|
auto header = new (message.data()) ConnectMessageHeader{};
|
|
header->clientPid = thread->tproc->pid;
|
|
header->clientKid = kid;
|
|
|
|
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<char *>(header + 1);
|
|
*std::bit_cast<uint *>(bufLoc) = _params.userDataLen;
|
|
ORBIS_RET_ON_ERROR(ureadRaw(bufLoc + sizeof(uint), _params.userData,
|
|
_params.userDataLen));
|
|
}
|
|
|
|
server->packets.push_back({{
|
|
.inputSize = static_cast<ulong>(thread->tid),
|
|
.type = 1,
|
|
.clientKid = kid,
|
|
},
|
|
0,
|
|
nullptr,
|
|
std::move(message)});
|
|
server->receiveCv.notify_one(server->mutex);
|
|
}
|
|
|
|
while (client->session == nullptr && !client->connectionStatus) {
|
|
orbis::scoped_unblock unblock;
|
|
client->sessionCv.wait(client->mutex);
|
|
}
|
|
|
|
while (!client->connectionStatus) {
|
|
orbis::scoped_unblock unblock;
|
|
client->connectCv.wait(client->mutex);
|
|
}
|
|
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.status, *client->connectionStatus));
|
|
|
|
{
|
|
std::lock_guard serverLock(server->mutex);
|
|
server->connectionRequests.erase(requestIt);
|
|
}
|
|
|
|
return uwrite(result, 0u);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiSessionGetClientAppId(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiGetUserDataParam {
|
|
ptr<uint> data;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiGetUserDataParam)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiGetUserDataParam _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiGetUserDataParam>(params)));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwrite(_params.data, session->client->process->appInfo.appId));
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiSessionGetUserData(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiGetUserDataParam {
|
|
ptr<ptr<void>> data;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiGetUserDataParam)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiGetUserDataParam _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiGetUserDataParam>(params)));
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.data, session->userData));
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiGetServerNameParams {
|
|
ptr<char> name;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiGetServerNameParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto server = g_context->ipmiMap.get(kid).cast<IpmiServer>();
|
|
|
|
if (server == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiGetServerNameParams _param;
|
|
ORBIS_RET_ON_ERROR(uread(_param, ptr<IpmiGetServerNameParams>(params)));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwriteRaw(_param.name, server->name.c_str(), server->name.size() + 1));
|
|
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientGetName(Thread *thread, ptr<uint> result,
|
|
uint kid, ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiGetClientNameParams {
|
|
ptr<char> name;
|
|
};
|
|
|
|
if (paramsSz != sizeof(IpmiGetClientNameParams)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiGetClientNameParams _param;
|
|
ORBIS_RET_ON_ERROR(uread(_param, ptr<IpmiGetClientNameParams>(params)));
|
|
ORBIS_RET_ON_ERROR(
|
|
uwriteRaw(_param.name, client->name.c_str(), client->name.size() + 1));
|
|
|
|
return uwrite<uint>(result, 0);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiWaitEventFlagParam {
|
|
uint32_t index;
|
|
uint32_t padding0;
|
|
uint64_t patternSet;
|
|
uint32_t mode;
|
|
uint32_t padding1;
|
|
ptr<uint64_t> pPatternSet;
|
|
ptr<uint32_t> pTimeout;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiWaitEventFlagParam) == 0x28);
|
|
|
|
if (paramsSz != sizeof(IpmiWaitEventFlagParam)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiWaitEventFlagParam _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiWaitEventFlagParam>(params)));
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
if (client->eventFlags.size() <= _params.index) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
std::uint32_t resultTimeout{};
|
|
|
|
if (_params.pTimeout != nullptr) {
|
|
ORBIS_RET_ON_ERROR(uread(resultTimeout, _params.pTimeout));
|
|
}
|
|
|
|
auto &evf = client->eventFlags[_params.index];
|
|
ErrorCode waitResult;
|
|
|
|
{
|
|
orbis::scoped_unblock unblock;
|
|
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));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiClientPollEventFlag(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiPollEventFlagParam {
|
|
uint32_t index;
|
|
uint32_t padding0;
|
|
uint64_t patternSet;
|
|
uint32_t mode;
|
|
uint32_t padding1;
|
|
ptr<uint64_t> pPatternSet;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiPollEventFlagParam) == 0x20);
|
|
|
|
if (paramsSz != sizeof(IpmiPollEventFlagParam)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiPollEventFlagParam _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiPollEventFlagParam>(params)));
|
|
|
|
auto client = g_context->ipmiMap.get(kid).cast<IpmiClient>();
|
|
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
if (client->eventFlags.size() <= _params.index) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
uint64_t patternSet;
|
|
ORBIS_RET_ON_ERROR(uread(patternSet, _params.pPatternSet));
|
|
auto &evf = client->eventFlags[_params.index];
|
|
auto waitResult = evf.tryWait(thread, _params.mode, patternSet);
|
|
|
|
ORBIS_RET_ON_ERROR(uread(patternSet, _params.pPatternSet));
|
|
ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, thread->evfResultPattern));
|
|
ORBIS_RET_ON_ERROR(uwrite(result, 0u));
|
|
return SysResult::notAnError(waitResult);
|
|
}
|
|
|
|
orbis::SysResult orbis::sysIpmiSessionSetEventFlag(Thread *thread,
|
|
ptr<uint> result, uint kid,
|
|
ptr<void> params,
|
|
uint64_t paramsSz) {
|
|
struct IpmiSetEventFlagParam {
|
|
uint32_t index;
|
|
uint32_t padding;
|
|
uint64_t patternSet;
|
|
};
|
|
|
|
static_assert(sizeof(IpmiSetEventFlagParam) == 0x10);
|
|
|
|
if (paramsSz != sizeof(IpmiSetEventFlagParam)) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
IpmiSetEventFlagParam _params;
|
|
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiSetEventFlagParam>(params)));
|
|
|
|
auto session = g_context->ipmiMap.get(kid).cast<IpmiSession>();
|
|
|
|
if (session == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto client = session->client;
|
|
if (client == nullptr) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
if (client->eventFlags.size() <= _params.index) {
|
|
return ErrorCode::INVAL;
|
|
}
|
|
|
|
auto &evf = client->eventFlags[_params.index];
|
|
evf.set(_params.patternSet);
|
|
return uwrite<uint>(result, 0);
|
|
}
|