2017-11-02 15:11:55 +01:00
|
|
|
/*
|
|
|
|
sender.c
|
|
|
|
Handles commands from arm11 processes, then sends them to Process9, and replies to arm11 processes the replies received from Process9 (=> receiver.c).
|
|
|
|
(except for PXISRV11)
|
|
|
|
|
2020-04-25 14:26:21 +02:00
|
|
|
(c) TuxSH, 2016-2020
|
2017-11-02 15:11:55 +01:00
|
|
|
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
|
|
|
*/
|
|
|
|
|
2018-05-24 00:55:38 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2017-11-02 15:11:55 +01:00
|
|
|
#include "sender.h"
|
|
|
|
#include "PXI.h"
|
|
|
|
|
|
|
|
Result sendPXICmdbuf(Handle *additionalHandle, u32 serviceId, u32 *buffer)
|
|
|
|
{
|
|
|
|
|
|
|
|
Result res = 0;
|
|
|
|
|
|
|
|
if(additionalHandle != NULL)
|
|
|
|
{
|
|
|
|
s32 index = 1;
|
|
|
|
bool cancelled = false;
|
|
|
|
Handle handles[2] = {PXITransferMutex, *additionalHandle};
|
|
|
|
|
|
|
|
res = assertSuccess(svcWaitSynchronization(PXITransferMutex, 0LL));
|
|
|
|
if(R_DESCRIPTION(res) == RD_TIMEOUT)
|
|
|
|
{
|
|
|
|
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
|
|
|
|
cancelled = index == 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cancelled = false;
|
|
|
|
|
|
|
|
if(cancelled)
|
|
|
|
return 0xD92043FB; // cancel requested
|
|
|
|
}
|
|
|
|
else
|
|
|
|
assertSuccess(svcWaitSynchronization(PXITransferMutex, -1LL));
|
|
|
|
|
|
|
|
PXISendWord(serviceId & 0xFF);
|
|
|
|
PXITriggerSync9IRQ(); //notify arm9
|
|
|
|
PXISendBuffer(buffer, (buffer[0] & 0x3F) + ((buffer[0] & 0xFC0) >> 6) + 1);
|
|
|
|
|
|
|
|
svcReleaseMutex(PXITransferMutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void updateTLSForStaticBuffers(void)
|
|
|
|
{
|
|
|
|
u32 *staticBufs = getThreadStaticBuffers();
|
|
|
|
u32 val = sessionManager.currentlyProvidedStaticBuffers;
|
|
|
|
for(u32 i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
s32 pos = getLSBPosition(val);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
staticBufs[2 * i] = IPC_Desc_StaticBuffer(0x1000, 0);
|
|
|
|
staticBufs[2 * i + 1] = (u32)&staticBuffers[pos];
|
|
|
|
val &= ~(1 << pos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
staticBufs[2 * i] = IPC_Desc_StaticBuffer(0, 0);
|
|
|
|
staticBufs[2 * i + 1] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void acquireStaticBuffers(void)
|
|
|
|
{
|
|
|
|
u32 freeStaticBuffersOrig = sessionManager.freeStaticBuffers;
|
|
|
|
sessionManager.freeStaticBuffers = clearMSBs(sessionManager.freeStaticBuffers, 4);
|
|
|
|
sessionManager.currentlyProvidedStaticBuffers = ~sessionManager.freeStaticBuffers & freeStaticBuffersOrig;
|
|
|
|
updateTLSForStaticBuffers();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void releaseStaticBuffers(u32 *src, u32 nb)
|
|
|
|
{
|
|
|
|
u32 val = clearMSBs(*src, nb);
|
|
|
|
sessionManager.freeStaticBuffers |= ~val & *src;
|
|
|
|
*src = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sender(void)
|
|
|
|
{
|
|
|
|
Handle handles[12] = {terminationRequestedEvent, sessionManager.sendAllBuffersToArm9Event, sessionManager.replySemaphore};
|
|
|
|
Handle replyTarget = 0;
|
|
|
|
Result res = 0;
|
|
|
|
s32 index;
|
|
|
|
|
|
|
|
u32 *cmdbuf = getThreadCommandBuffer();
|
|
|
|
|
|
|
|
u32 nbIdleSessions = 0;
|
|
|
|
u32 posToServiceId[9] = {0};
|
|
|
|
RecursiveLock_Lock(&sessionManager.senderLock);
|
|
|
|
|
|
|
|
//Setting static buffers is needed for IPC translation types 2 and 3 (otherwise ReplyAndReceive will dereference NULL)
|
|
|
|
sessionManager.freeStaticBuffers = (1 << NB_STATIC_BUFFERS) - 1;
|
|
|
|
acquireStaticBuffers();
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if(replyTarget == 0) //send to arm9
|
|
|
|
{
|
|
|
|
for(u32 i = 0; i < 9; i++)
|
|
|
|
{
|
|
|
|
SessionData *data = &sessionManager.sessionData[i];
|
|
|
|
if(data->handle == 0 || data->state != STATE_RECEIVED_FROM_ARM11)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(sessionManager.sendingDisabled)
|
|
|
|
{
|
|
|
|
if (sessionManager.pendingArm9Commands != 0 || sessionManager.latest_PXI_MC5_val == 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
sessionManager.pendingArm9Commands++;
|
|
|
|
|
|
|
|
RecursiveLock_Lock(&data->lock);
|
|
|
|
data->state = STATE_SENT_TO_ARM9;
|
|
|
|
res = sendPXICmdbuf(&terminationRequestedEvent, i, data->buffer);
|
|
|
|
RecursiveLock_Unlock(&data->lock);
|
|
|
|
|
|
|
|
if(R_FAILED(res))
|
|
|
|
goto terminate;
|
|
|
|
|
|
|
|
}
|
|
|
|
cmdbuf[0] = 0xFFFF0000; //Kernel11
|
|
|
|
}
|
|
|
|
|
|
|
|
nbIdleSessions = 0;
|
|
|
|
for(u32 i = 0; i < 9; i++)
|
|
|
|
{
|
|
|
|
if(sessionManager.sessionData[i].handle != 0 && sessionManager.sessionData[i].state == STATE_IDLE)
|
|
|
|
{
|
|
|
|
handles[3 + nbIdleSessions] = sessionManager.sessionData[i].handle;
|
|
|
|
posToServiceId[nbIdleSessions++] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RecursiveLock_Unlock(&sessionManager.senderLock);
|
|
|
|
res = svcReplyAndReceive(&index, handles, 3 + nbIdleSessions, replyTarget);
|
|
|
|
RecursiveLock_Lock(&sessionManager.senderLock);
|
|
|
|
|
|
|
|
if((u32)res == 0xC920181A) //session closed by remote
|
|
|
|
{
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
if(index == -1)
|
|
|
|
for(i = 0; i < 9 && replyTarget != sessionManager.sessionData[i].handle; i++);
|
|
|
|
|
|
|
|
else
|
|
|
|
i = posToServiceId[index - 3];
|
|
|
|
|
|
|
|
if(i >= 9) svcBreak(USERBREAK_PANIC);
|
|
|
|
|
|
|
|
svcCloseHandle(sessionManager.sessionData[i].handle);
|
|
|
|
sessionManager.sessionData[i].handle = replyTarget = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(R_FAILED(res) || (u32)index >= 3 + nbIdleSessions)
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
|
|
|
|
switch(index)
|
|
|
|
{
|
|
|
|
case 0: //terminaton requested
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
replyTarget = 0;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 2: //arm9 reply
|
|
|
|
{
|
|
|
|
u32 sessionId = 0;
|
|
|
|
for(sessionId = 0; sessionId < 9 && sessionManager.sessionData[sessionId].state != STATE_RECEIVED_FROM_ARM9; sessionId++);
|
|
|
|
if(sessionId == 9) svcBreak(USERBREAK_PANIC);
|
|
|
|
SessionData *data = &sessionManager.sessionData[sessionId];
|
|
|
|
|
|
|
|
RecursiveLock_Lock(&data->lock);
|
|
|
|
if(data->state != STATE_RECEIVED_FROM_ARM9) svcBreak(USERBREAK_PANIC);
|
|
|
|
if(sessionManager.latest_PXI_MC5_val == 2)
|
|
|
|
{
|
|
|
|
if(sessionManager.pendingArm9Commands != 0) svcBreak(USERBREAK_PANIC);
|
|
|
|
sessionManager.sendingDisabled = false;
|
|
|
|
}
|
|
|
|
else if(sessionManager.latest_PXI_MC5_val == 0)
|
|
|
|
(sessionManager.pendingArm9Commands)--;
|
|
|
|
|
|
|
|
u32 bufSize = 4 * ((data->buffer[0] & 0x3F) + ((data->buffer[0] & 0xFC0) >> 6) + 1);
|
|
|
|
if(bufSize > 0x100) svcBreak(USERBREAK_PANIC);
|
|
|
|
memcpy(cmdbuf, data->buffer, bufSize);
|
|
|
|
|
|
|
|
releaseStaticBuffers(&data->usedStaticBuffers, 4);
|
|
|
|
|
|
|
|
data->state = STATE_IDLE;
|
|
|
|
replyTarget = data->handle;
|
|
|
|
|
|
|
|
RecursiveLock_Unlock(&data->lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: //arm11 command received
|
|
|
|
{
|
|
|
|
u32 serviceId = posToServiceId[index - 3];
|
|
|
|
SessionData *data = &sessionManager.sessionData[serviceId];
|
|
|
|
RecursiveLock_Lock(&data->lock);
|
|
|
|
|
|
|
|
if(data->state != STATE_IDLE) svcBreak(USERBREAK_PANIC);
|
|
|
|
|
|
|
|
if(!(serviceId == 0 && (cmdbuf[0] >> 16) == 5)) //if not pxi:mc 5
|
|
|
|
sessionManager.latest_PXI_MC5_val = 0;
|
|
|
|
else if((u8)(cmdbuf[1]) != 0)
|
|
|
|
{
|
|
|
|
sessionManager.latest_PXI_MC5_val = 1;
|
|
|
|
if(sessionManager.sendingDisabled) svcBreak(USERBREAK_PANIC);
|
|
|
|
sessionManager.sendingDisabled = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sessionManager.latest_PXI_MC5_val = 2;
|
|
|
|
if(!sessionManager.sendingDisabled) svcBreak(USERBREAK_PANIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 bufSize = 4 * ((cmdbuf[0] & 0x3F) + ((cmdbuf[0] & 0xFC0) >> 6) + 1);
|
|
|
|
if(bufSize > 0x100) svcBreak(USERBREAK_PANIC);
|
|
|
|
memcpy(data->buffer, cmdbuf, bufSize);
|
|
|
|
|
|
|
|
data->state = STATE_RECEIVED_FROM_ARM11;
|
|
|
|
replyTarget = 0;
|
|
|
|
|
|
|
|
releaseStaticBuffers(&sessionManager.currentlyProvidedStaticBuffers, 4 - nbStaticBuffersByService[serviceId]);
|
|
|
|
data->usedStaticBuffers = sessionManager.currentlyProvidedStaticBuffers;
|
|
|
|
acquireStaticBuffers();
|
|
|
|
|
|
|
|
RecursiveLock_Unlock(&data->lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while(index != 0);
|
|
|
|
|
|
|
|
terminate:
|
|
|
|
for(u32 i = 0; i < 9; i++)
|
|
|
|
{
|
|
|
|
if(sessionManager.sessionData[i].handle != 0)
|
|
|
|
svcCloseHandle(sessionManager.sessionData[i].handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
RecursiveLock_Unlock(&sessionManager.senderLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PXISRV11Handler(void)
|
|
|
|
{
|
|
|
|
// Assumption: only 1 request is sent to this service at a time
|
|
|
|
Handle handles[] = {sessionManager.PXISRV11CommandReceivedEvent, terminationRequestedEvent};
|
|
|
|
SessionData *data = &sessionManager.sessionData[9];
|
|
|
|
|
|
|
|
data->state = STATE_SENT_TO_ARM9;
|
|
|
|
assertSuccess(svcSignalEvent(sessionManager.PXISRV11ReplySentEvent));
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
s32 index;
|
|
|
|
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
|
|
|
|
|
|
|
|
if(index == 1) return;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RecursiveLock_Lock(&data->lock);
|
|
|
|
|
|
|
|
if(data->state != STATE_RECEIVED_FROM_ARM9)
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
|
|
|
|
data->state = STATE_IDLE;
|
|
|
|
|
|
|
|
if(data->buffer[0] >> 16 != 1)
|
|
|
|
{
|
|
|
|
data->buffer[0] = 0x40;
|
|
|
|
data->buffer[1] = 0xD900182F; //unimplemented/invalid command
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data->buffer[0] = 0x10040;
|
|
|
|
data->buffer[1] = srvPublishToSubscriber(data->buffer[1], 1);
|
|
|
|
|
|
|
|
data->state = STATE_RECEIVED_FROM_ARM11;
|
|
|
|
if(data->buffer[1] == 0xD8606408)
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
assertSuccess(sendPXICmdbuf(&terminationRequestedEvent, 9, data->buffer));
|
|
|
|
data->state = STATE_SENT_TO_ARM9;
|
|
|
|
assertSuccess(svcSignalEvent(sessionManager.PXISRV11ReplySentEvent));
|
|
|
|
RecursiveLock_Unlock(&data->lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|