mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-29 14:59:26 -04:00
213 lines
6.4 KiB
C++
213 lines
6.4 KiB
C++
#include "iosu_nn_service.h"
|
|
#include "../kernel/iosu_kernel.h"
|
|
#include "util/helpers/helpers.h"
|
|
|
|
using namespace iosu::kernel;
|
|
|
|
namespace iosu
|
|
{
|
|
namespace nn
|
|
{
|
|
/* IPCSimpleService */
|
|
void IPCSimpleService::Start()
|
|
{
|
|
if (m_isRunning.exchange(true))
|
|
return;
|
|
m_threadInitialized = false;
|
|
m_requestStop = false;
|
|
m_serviceThread = std::thread(&IPCSimpleService::ServiceThread, this);
|
|
while (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
StartService();
|
|
}
|
|
|
|
void IPCSimpleService::Stop()
|
|
{
|
|
if (!m_isRunning.exchange(false))
|
|
return;
|
|
m_requestStop = true;
|
|
StopService();
|
|
if(m_timerId != IOSInvalidTimerId)
|
|
IOS_DestroyTimer(m_timerId);
|
|
m_timerId = IOSInvalidTimerId;
|
|
IOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread
|
|
m_serviceThread.join();
|
|
}
|
|
|
|
void IPCSimpleService::ServiceThread()
|
|
{
|
|
if(!GetThreadName().empty())
|
|
SetThreadName(GetThreadName().c_str());
|
|
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
|
|
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
|
|
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);
|
|
cemu_assert(!IOS_ResultIsError(r));
|
|
m_threadInitialized = true;
|
|
while (true)
|
|
{
|
|
IOSMessage msg;
|
|
r = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);
|
|
cemu_assert(!IOS_ResultIsError(r));
|
|
if (msg == 0)
|
|
{
|
|
cemu_assert_debug(m_requestStop);
|
|
break;
|
|
}
|
|
else if(msg == 1)
|
|
{
|
|
TimerUpdate();
|
|
continue;
|
|
}
|
|
IPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();
|
|
if (cmd->cmdId == IPCCommandId::IOS_OPEN)
|
|
{
|
|
void* clientObject = CreateClientObject();
|
|
if(clientObject == nullptr)
|
|
{
|
|
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Maximum handle count reached or handle rejected", m_devicePath);
|
|
IOS_ResourceReply(cmd, IOS_ERROR_MAXIMUM_REACHED);
|
|
continue;
|
|
}
|
|
IOSDevHandle newHandle = GetFreeHandle();
|
|
m_clientObjects[newHandle] = clientObject;
|
|
IOS_ResourceReply(cmd, (IOS_ERROR)newHandle);
|
|
continue;
|
|
}
|
|
else if (cmd->cmdId == IPCCommandId::IOS_CLOSE)
|
|
{
|
|
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
|
|
if (clientObject)
|
|
DestroyClientObject(clientObject);
|
|
IOS_ResourceReply(cmd, IOS_ERROR_OK);
|
|
continue;
|
|
}
|
|
else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)
|
|
{
|
|
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
|
|
if (!clientObject)
|
|
{
|
|
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Invalid IPC handle", m_devicePath);
|
|
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
|
|
continue;
|
|
}
|
|
uint32 requestId = cmd->args[0];
|
|
uint32 numIn = cmd->args[1];
|
|
uint32 numOut = cmd->args[2];
|
|
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();
|
|
IPCIoctlVector* vecIn = vec + 0; // the ordering of vecIn/vecOut differs from IPCService
|
|
IPCIoctlVector* vecOut = vec + numIn;
|
|
m_delayResponse = false;
|
|
m_activeCmd = cmd;
|
|
uint32 result = ServiceCall(clientObject, requestId, vecIn, numIn, vecOut, numOut);
|
|
if (!m_delayResponse)
|
|
IOS_ResourceReply(cmd, (IOS_ERROR)result);
|
|
m_activeCmd = nullptr;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Unsupported IPC cmdId {}", m_devicePath, (uint32)cmd->cmdId.value());
|
|
cemu_assert_unimplemented();
|
|
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
|
|
}
|
|
}
|
|
IOS_DestroyMessageQueue(m_msgQueueId);
|
|
m_threadInitialized = false;
|
|
}
|
|
|
|
void IPCSimpleService::SetTimerUpdate(uint32 milliseconds)
|
|
{
|
|
if(m_timerId != IOSInvalidTimerId)
|
|
IOS_DestroyTimer(m_timerId);
|
|
m_timerId = IOS_CreateTimer(milliseconds * 1000, milliseconds * 1000, m_msgQueueId, 1);
|
|
}
|
|
|
|
IPCCommandBody* IPCSimpleService::ServiceCallDelayCurrentResponse()
|
|
{
|
|
cemu_assert_debug(m_activeCmd);
|
|
m_delayResponse = true;
|
|
return m_activeCmd;
|
|
}
|
|
|
|
void IPCSimpleService::ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r)
|
|
{
|
|
IOS_ResourceReply(response, (IOS_ERROR)r);
|
|
}
|
|
|
|
/* IPCService */
|
|
void IPCService::Start()
|
|
{
|
|
if (m_isRunning.exchange(true))
|
|
return;
|
|
m_threadInitialized = false;
|
|
m_requestStop = false;
|
|
m_serviceThread = std::thread(&IPCService::ServiceThread, this);
|
|
while (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
}
|
|
|
|
void IPCService::Stop()
|
|
{
|
|
if (!m_isRunning.exchange(false))
|
|
return;
|
|
m_requestStop = true;
|
|
IOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread
|
|
m_serviceThread.join();
|
|
}
|
|
|
|
void IPCService::ServiceThread()
|
|
{
|
|
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
|
|
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
|
|
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);
|
|
cemu_assert(!IOS_ResultIsError(r));
|
|
m_threadInitialized = true;
|
|
while (true)
|
|
{
|
|
IOSMessage msg;
|
|
IOS_ERROR r = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);
|
|
cemu_assert(!IOS_ResultIsError(r));
|
|
if (msg == 0)
|
|
{
|
|
cemu_assert_debug(m_requestStop);
|
|
break;
|
|
}
|
|
IPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();
|
|
if (cmd->cmdId == IPCCommandId::IOS_OPEN)
|
|
{
|
|
IOS_ResourceReply(cmd, (IOS_ERROR)CreateClientHandle());
|
|
continue;
|
|
}
|
|
else if (cmd->cmdId == IPCCommandId::IOS_CLOSE)
|
|
{
|
|
CloseClientHandle((IOSDevHandle)(uint32)cmd->devHandle);
|
|
IOS_ResourceReply(cmd, IOS_ERROR_OK);
|
|
continue;
|
|
}
|
|
else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)
|
|
{
|
|
uint32 requestId = cmd->args[0];
|
|
uint32 numIn = cmd->args[1];
|
|
uint32 numOut = cmd->args[2];
|
|
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();
|
|
IPCIoctlVector* vecIn = vec + numIn;
|
|
IPCIoctlVector* vecOut = vec + 0;
|
|
|
|
cemu_assert(vecIn->size >= 80 && !vecIn->basePhys.IsNull());
|
|
|
|
IPCServiceRequest* serviceRequest = MEMPTR<IPCServiceRequest>(vecIn->basePhys).GetPtr();
|
|
IPCServiceResponse* serviceResponse = MEMPTR<IPCServiceResponse>(vecOut->basePhys).GetPtr();
|
|
|
|
serviceResponse->nnResultCode = (uint32)ServiceCall(serviceRequest->serviceId, nullptr, nullptr);
|
|
IOS_ResourceReply(cmd, IOS_ERROR_OK);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
cemuLog_log(LogType::Force, "{}: Unsupported cmdId", m_devicePath);
|
|
cemu_assert_unimplemented();
|
|
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
|
|
}
|
|
}
|
|
m_threadInitialized = false;
|
|
}
|
|
};
|
|
};
|