2017-11-02 15:11:55 +01:00
|
|
|
/*
|
|
|
|
main.c
|
|
|
|
(De)initialization stuff. It's also here where sessions are being accepted.
|
|
|
|
|
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 "PXI.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include "MyThread.h"
|
|
|
|
#include "receiver.h"
|
|
|
|
#include "sender.h"
|
|
|
|
|
|
|
|
Handle PXISyncInterrupt = 0, PXITransferMutex = 0;
|
|
|
|
Handle terminationRequestedEvent = 0;
|
|
|
|
bool shouldTerminate = false;
|
|
|
|
SessionManager sessionManager = {0};
|
|
|
|
|
|
|
|
const char *serviceNames[10] =
|
|
|
|
{
|
|
|
|
"pxi:mc",
|
|
|
|
|
|
|
|
"PxiFS0",
|
|
|
|
"PxiFS1",
|
|
|
|
"PxiFSB",
|
|
|
|
"PxiFSR",
|
|
|
|
|
|
|
|
"PxiPM",
|
|
|
|
|
|
|
|
"pxi:dev", //in the official PXI module maxSessions(pxi:dev) == 2. It doesn't matter anyways, since srvSysRegisterService is always called with 1
|
|
|
|
"pxi:am9",
|
|
|
|
"pxi:ps9",
|
|
|
|
|
|
|
|
"pxi:srv11",
|
|
|
|
};
|
|
|
|
|
|
|
|
const u32 nbStaticBuffersByService[10] = {0, 2, 2, 2, 2, 1, 4, 4, 4, 0};
|
|
|
|
|
|
|
|
u32 ALIGN(0x1000) staticBuffers[NB_STATIC_BUFFERS][0x400] = {{0}};
|
|
|
|
|
|
|
|
static inline void initPXI(void)
|
|
|
|
{
|
|
|
|
Result res;
|
|
|
|
|
|
|
|
Handle handles[2] = {0};
|
|
|
|
|
|
|
|
PXIReset();
|
|
|
|
|
|
|
|
if(PXISyncInterrupt != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
|
|
|
|
assertSuccess(svcCreateEvent(&PXISyncInterrupt, RESET_ONESHOT));
|
|
|
|
|
|
|
|
if(PXITransferMutex != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B
|
|
|
|
assertSuccess(svcCreateMutex(&PXITransferMutex, false));
|
|
|
|
|
|
|
|
assertSuccess(svcCreateEvent(&handles[0], RESET_ONESHOT)); //receive FIFO not empty
|
|
|
|
assertSuccess(svcCreateEvent(&handles[1], RESET_ONESHOT)); //send FIFO empty
|
|
|
|
assertSuccess(bindPXIInterrupts(&PXISyncInterrupt, &handles[0], &handles[1]));
|
|
|
|
|
|
|
|
s32 handleIndex;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
while(!PXIIsSendFIFOFull()) PXISendWord(0);
|
|
|
|
|
|
|
|
res = assertSuccess(svcWaitSynchronization(handles[0], 0LL));
|
|
|
|
if(R_DESCRIPTION(res) == RD_TIMEOUT)
|
|
|
|
assertSuccess(svcWaitSynchronizationN(&handleIndex, handles, 2, false, -1LL));
|
|
|
|
else
|
|
|
|
handleIndex = 0;
|
|
|
|
} while(handleIndex != 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unbindPXIInterrupts(NULL, &handles[0], &handles[1]);
|
|
|
|
|
|
|
|
PXISendByte(1);
|
|
|
|
while(PXIReceiveByte() < 1);
|
|
|
|
|
|
|
|
while (!PXIIsReceiveFIFOEmpty())
|
|
|
|
PXIReceiveWord();
|
|
|
|
|
|
|
|
PXISendByte(2);
|
|
|
|
while(PXIReceiveByte() < 2);
|
|
|
|
|
|
|
|
svcCloseHandle(handles[0]);
|
|
|
|
svcCloseHandle(handles[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void exitPXI(void)
|
|
|
|
{
|
|
|
|
unbindPXIInterrupts(&PXISyncInterrupt, NULL, NULL);
|
|
|
|
svcCloseHandle(PXITransferMutex);
|
|
|
|
svcCloseHandle(PXISyncInterrupt);
|
|
|
|
PXIReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
static u8 ALIGN(8) receiverStack[THREAD_STACK_SIZE];
|
|
|
|
static u8 ALIGN(8) senderStack[THREAD_STACK_SIZE];
|
|
|
|
static u8 ALIGN(8) PXISRV11HandlerStack[THREAD_STACK_SIZE];
|
|
|
|
|
|
|
|
// this is called before main
|
|
|
|
void __appInit()
|
|
|
|
{
|
|
|
|
assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY));
|
|
|
|
|
|
|
|
assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT));
|
|
|
|
assertSuccess(svcCreateSemaphore(&sessionManager.replySemaphore, 0, 9));
|
|
|
|
assertSuccess(svcCreateEvent(&sessionManager.PXISRV11CommandReceivedEvent, RESET_ONESHOT));
|
|
|
|
assertSuccess(svcCreateEvent(&sessionManager.PXISRV11ReplySentEvent, RESET_ONESHOT));
|
|
|
|
initPXI();
|
|
|
|
|
|
|
|
for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
|
|
|
|
{
|
|
|
|
res = srvInit();
|
|
|
|
if(R_FAILED(res) && res != (Result)0xD88007FA)
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is called after main exits
|
|
|
|
void __appExit()
|
|
|
|
{
|
|
|
|
srvExit();
|
|
|
|
exitPXI();
|
|
|
|
|
|
|
|
svcCloseHandle(terminationRequestedEvent);
|
|
|
|
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
|
|
|
|
svcCloseHandle(sessionManager.replySemaphore);
|
|
|
|
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
|
|
|
|
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// stubs for non-needed pre-main functions
|
|
|
|
void __system_initSyscalls(){}
|
|
|
|
|
|
|
|
|
|
|
|
Result __sync_init(void);
|
|
|
|
Result __sync_fini(void);
|
|
|
|
|
|
|
|
void __ctru_exit()
|
|
|
|
{
|
2018-05-23 03:16:32 +02:00
|
|
|
void __libc_fini_array(void);
|
|
|
|
|
|
|
|
__libc_fini_array();
|
|
|
|
__appExit();
|
|
|
|
__sync_fini();
|
|
|
|
svcExitProcess();
|
2017-11-02 15:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void initSystem()
|
|
|
|
{
|
2018-05-23 03:16:32 +02:00
|
|
|
void __libc_init_array(void);
|
|
|
|
|
|
|
|
__sync_init();
|
|
|
|
__system_initSyscalls();
|
|
|
|
__appInit();
|
|
|
|
__libc_init_array();
|
2017-11-02 15:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
Handle handles[10] = {0}; //notification handle + service handles
|
|
|
|
MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
|
|
|
|
|
|
|
|
for(u32 i = 0; i < 9; i++)
|
|
|
|
assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1));
|
|
|
|
|
|
|
|
assertSuccess(MyThread_Create(&receiverThread, receiver, receiverStack, THREAD_STACK_SIZE, 0x2D, -2));
|
|
|
|
assertSuccess(MyThread_Create(&senderThread, sender, senderStack, THREAD_STACK_SIZE, 0x2D, -2));
|
|
|
|
assertSuccess(MyThread_Create(&PXISRV11HandlerThread, PXISRV11Handler, PXISRV11HandlerStack, THREAD_STACK_SIZE, 0x2D, -2));
|
|
|
|
|
|
|
|
assertSuccess(srvEnableNotification(&handles[0]));
|
|
|
|
|
|
|
|
while(!shouldTerminate)
|
|
|
|
{
|
|
|
|
s32 index = 0;
|
|
|
|
assertSuccess(svcWaitSynchronizationN(&index, handles, 10, false, -1LL));
|
|
|
|
|
|
|
|
if(index == 0)
|
|
|
|
{
|
|
|
|
u32 notificationId;
|
|
|
|
assertSuccess(srvReceiveNotification(¬ificationId));
|
|
|
|
if(notificationId == 0x100) shouldTerminate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Handle session = 0;
|
|
|
|
SessionData *data = &sessionManager.sessionData[index - 1];
|
|
|
|
assertSuccess(svcAcceptSession(&session, handles[index]));
|
|
|
|
|
|
|
|
RecursiveLock_Lock(&sessionManager.senderLock);
|
|
|
|
if(data->handle != 0)
|
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
|
|
|
|
data->handle = session;
|
|
|
|
assertSuccess(svcSignalEvent(sessionManager.sendAllBuffersToArm9Event));
|
|
|
|
|
|
|
|
RecursiveLock_Unlock(&sessionManager.senderLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 PXIMC_OnPXITerminate = 0x10000; //TODO: see if this is correct
|
|
|
|
sessionManager.sessionData[0].state = STATE_SENT_TO_ARM9;
|
|
|
|
sendPXICmdbuf(NULL, 0, &PXIMC_OnPXITerminate);
|
|
|
|
|
|
|
|
assertSuccess(MyThread_Join(&receiverThread, -1LL));
|
|
|
|
assertSuccess(MyThread_Join(&senderThread, -1LL));
|
|
|
|
assertSuccess(MyThread_Join(&PXISRV11HandlerThread, -1LL));
|
|
|
|
|
|
|
|
for(u32 i = 0; i < 10; i++)
|
|
|
|
svcCloseHandle(handles[i]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|