Integrate 3ds_pxi and 3ds_sm
This commit is contained in:
21
sysmodules/pxi/LICENSE
Normal file
21
sysmodules/pxi/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 TuxSH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
52
sysmodules/pxi/Makefile
Normal file
52
sysmodules/pxi/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
CC := arm-none-eabi-gcc
|
||||
AS := arm-none-eabi-as
|
||||
LD := arm-none-eabi-ld
|
||||
OC := arm-none-eabi-objcopy
|
||||
|
||||
name := pxi
|
||||
|
||||
dir_source := source
|
||||
dir_build := build
|
||||
dir_out := ../../$(dir_build)
|
||||
|
||||
LIBS := -lctru
|
||||
LIBDIRS := $(CTRULIB)
|
||||
LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
|
||||
|
||||
ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -g -ffast-math -mword-relocations \
|
||||
-ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
|
||||
LDFLAGS := -specs=3dsx.specs -Wl,--gc-sections $(ARCH)
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.c))
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).cxi
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).cxi: $(dir_build)/$(name).elf
|
||||
@makerom -f ncch -rsf $(name).rsf -nocodepadding -o $@ -elf $<
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
||||
|
||||
$(dir_build)/memory.o : CFLAGS += -O3
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
15
sysmodules/pxi/README.md
Normal file
15
sysmodules/pxi/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 3ds_pxi
|
||||
Open source replacement of the ARM11 PXI system module.
|
||||
This is licensed under the MIT license.
|
||||
|
||||
# Usage
|
||||
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
|
||||
|
||||
# Credits
|
||||
This list is not complete at all:
|
||||
|
||||
* @Subv, for the process patch that used to be used in Luma3DS which I modified to assist me in PXI sysmodule reverse-engineering
|
||||
* @yifanlu, for the work his own work on loader
|
||||
* @Mrrraou, for intensive testing back in June/July 2016
|
||||
* @jackron, for makerom support and help
|
||||
* Many #Cakey and #3dsdev folks I haven't mentioned here, etc.
|
||||
123
sysmodules/pxi/pxi.rsf
Normal file
123
sysmodules/pxi/pxi.rsf
Normal file
@@ -0,0 +1,123 @@
|
||||
BasicInfo:
|
||||
Title : pxi
|
||||
CompanyCode : "00"
|
||||
ProductCode : lennybuilder
|
||||
ContentType : Application
|
||||
Logo : None
|
||||
|
||||
TitleInfo:
|
||||
UniqueId : 0x14
|
||||
Category : Base
|
||||
Version : 2
|
||||
|
||||
Option:
|
||||
UseOnSD : false
|
||||
FreeProductCode : true # Removes limitations on ProductCode
|
||||
MediaFootPadding : false # If true CCI files are created with padding
|
||||
EnableCrypt : false # Enables encryption for NCCH and CIA
|
||||
EnableCompress : true # Compresses exefs code
|
||||
|
||||
AccessControlInfo:
|
||||
IdealProcessor : 1
|
||||
AffinityMask : 3
|
||||
|
||||
Priority : 13
|
||||
|
||||
DisableDebug : false
|
||||
EnableForceDebug : false
|
||||
CanWriteSharedPage : false
|
||||
CanUsePrivilegedPriority : false
|
||||
CanUseNonAlphabetAndNumber : false
|
||||
PermitMainFunctionArgument : false
|
||||
CanShareDeviceMemory : false
|
||||
RunnableOnSleep : true
|
||||
SpecialMemoryArrange : false
|
||||
ResourceLimitCategory : Other
|
||||
|
||||
CoreVersion : 2
|
||||
DescVersion : 2
|
||||
|
||||
MemoryType : Base # Application / System / Base
|
||||
HandleTableSize: 0
|
||||
IORegisterMapping:
|
||||
- 1ec63000
|
||||
SystemCallAccess:
|
||||
AcceptSession: 74
|
||||
ArbitrateAddress: 34
|
||||
Break: 60
|
||||
BindInterrupt: 80
|
||||
CancelTimer: 28
|
||||
ClearEvent: 25
|
||||
ClearTimer: 29
|
||||
CloseHandle: 35
|
||||
ConnectToPort: 45
|
||||
ControlMemory: 1
|
||||
CreateAddressArbiter: 33
|
||||
CreateEvent: 23
|
||||
CreateMemoryBlock: 30
|
||||
CreateMutex: 19
|
||||
CreatePort: 71
|
||||
CreateSemaphore: 21
|
||||
CreateSessionToPort: 72
|
||||
CreateThread: 8
|
||||
CreateTimer: 26
|
||||
DuplicateHandle: 39
|
||||
ExitProcess: 3
|
||||
ExitThread: 9
|
||||
FlushProcessDataCache: 84
|
||||
GetCurrentProcessorNumber: 17
|
||||
GetDmaState: 87
|
||||
GetHandleInfo: 41
|
||||
GetProcessId: 53
|
||||
GetProcessIdealProcessor: 6
|
||||
GetProcessIdOfThread: 54
|
||||
GetProcessInfo: 43
|
||||
GetResourceLimit: 56
|
||||
GetResourceLimitCurrentValues: 58
|
||||
GetResourceLimitLimitValues: 57
|
||||
GetSystemInfo: 42
|
||||
GetSystemTick: 40
|
||||
GetThreadContext: 59
|
||||
GetThreadId: 55
|
||||
GetThreadIdealProcessor: 15
|
||||
GetThreadInfo: 44
|
||||
GetThreadPriority: 11
|
||||
InvalidateProcessDataCache: 82
|
||||
MapMemoryBlock: 31
|
||||
OutputDebugString: 61
|
||||
QueryMemory: 2
|
||||
ReleaseMutex: 20
|
||||
ReleaseSemaphore: 22
|
||||
ReplyAndReceive1: 75
|
||||
ReplyAndReceive2: 76
|
||||
ReplyAndReceive3: 77
|
||||
ReplyAndReceive4: 78
|
||||
ReplyAndReceive: 79
|
||||
SendSyncRequest1: 46
|
||||
SendSyncRequest2: 47
|
||||
SendSyncRequest3: 48
|
||||
SendSyncRequest4: 49
|
||||
SendSyncRequest: 50
|
||||
SetThreadPriority: 12
|
||||
SetTimer: 27
|
||||
SignalEvent: 24
|
||||
SleepThread: 10
|
||||
StartInterProcessDma: 85
|
||||
StopDma: 86
|
||||
StoreProcessDataCache: 83
|
||||
UnmapMemoryBlock: 32
|
||||
UnbindInterrupt: 81
|
||||
WaitSynchronization1: 36
|
||||
WaitSynchronizationN: 37
|
||||
InterruptNumbers:
|
||||
- 0x50
|
||||
- 0x51
|
||||
- 0x52
|
||||
- 0x53
|
||||
ServiceAccessControl:
|
||||
FileSystemAccess:
|
||||
|
||||
SystemControlInfo:
|
||||
SaveDataSize: 0KB # It doesn't use any save data.
|
||||
RemasterVersion: 0
|
||||
StackSize: 0x1000
|
||||
42
sysmodules/pxi/source/MyThread.c
Normal file
42
sysmodules/pxi/source/MyThread.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
MyThread.c:
|
||||
Small threading library, based off ctrulib.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "MyThread.h"
|
||||
#include "memory.h"
|
||||
|
||||
static void _thread_begin(void* arg)
|
||||
{
|
||||
MyThread *t = (MyThread *)arg;
|
||||
t->ep();
|
||||
MyThread_Exit();
|
||||
}
|
||||
|
||||
Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity)
|
||||
{
|
||||
t->ep = entrypoint;
|
||||
t->stacktop = (u8 *)stack + stackSize;
|
||||
|
||||
return svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, affinity);
|
||||
}
|
||||
|
||||
Result MyThread_Join(MyThread *thread, s64 timeout_ns)
|
||||
{
|
||||
if (thread == NULL) return 0;
|
||||
Result res = svcWaitSynchronization(thread->handle, timeout_ns);
|
||||
if(R_FAILED(res)) return res;
|
||||
|
||||
svcCloseHandle(thread->handle);
|
||||
thread->handle = (Handle)0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void MyThread_Exit(void)
|
||||
{
|
||||
svcExitThread();
|
||||
}
|
||||
28
sysmodules/pxi/source/MyThread.h
Normal file
28
sysmodules/pxi/source/MyThread.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
MyThread.h:
|
||||
Small threading library, based off ctrulib.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/synchronization.h>
|
||||
|
||||
#define THREAD_STACK_SIZE 0x1000
|
||||
|
||||
typedef struct MyThread
|
||||
{
|
||||
Handle handle;
|
||||
void (*ep)(void);
|
||||
bool finished;
|
||||
void* stacktop;
|
||||
} MyThread;
|
||||
|
||||
Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity);
|
||||
Result MyThread_Join(MyThread *thread, s64 timeout_ns);
|
||||
void MyThread_Exit(void);
|
||||
139
sysmodules/pxi/source/PXI.c
Normal file
139
sysmodules/pxi/source/PXI.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
PXI.c:
|
||||
PXI I/O functions.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "PXI.h"
|
||||
|
||||
void PXIReset(void)
|
||||
{
|
||||
REG_PXI_SYNC = 0;
|
||||
REG_PXI_CNT = CNT_CLEAR_SEND_FIFO;
|
||||
|
||||
for(u32 i = 0; i < 16; i += 2)
|
||||
{
|
||||
REG_PXI_RECV;
|
||||
REG_PXI_RECV;
|
||||
}
|
||||
|
||||
REG_PXI_CNT = 0;
|
||||
REG_PXI_CNT = CNT_ENABLE_FIFOs | CNT_ACKNOWLEDGE_FIFO_ERROR | CNT_CLEAR_SEND_FIFO;
|
||||
}
|
||||
|
||||
void PXITriggerSync9IRQ(void)
|
||||
{
|
||||
REG_PXI_INTERRUPT_CNT |= SYNC_TRIGGER_SYNC9_IRQ;
|
||||
}
|
||||
|
||||
bool PXIIsSendFIFOFull(void)
|
||||
{
|
||||
return (REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS) != 0;
|
||||
}
|
||||
|
||||
void PXISendByte(u8 byte)
|
||||
{
|
||||
REG_PXI_BYTE_SENT_TO_REMOTE = byte;
|
||||
}
|
||||
|
||||
void PXISendWord(u32 word)
|
||||
{
|
||||
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
|
||||
REG_PXI_SEND = word;
|
||||
}
|
||||
|
||||
void PXISendBuffer(const u32 *buffer, u32 nbWords)
|
||||
{
|
||||
for(; nbWords > 0; nbWords--)
|
||||
{
|
||||
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
|
||||
REG_PXI_SEND = *buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
bool PXIIsReceiveFIFOEmpty(void)
|
||||
{
|
||||
return (REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS) != 0;
|
||||
}
|
||||
|
||||
u8 PXIReceiveByte(void)
|
||||
{
|
||||
return REG_PXI_BYTE_RECEIVED_FROM_REMOTE;
|
||||
}
|
||||
|
||||
u32 PXIReceiveWord(void)
|
||||
{
|
||||
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
|
||||
return REG_PXI_RECV;
|
||||
}
|
||||
|
||||
void PXIReceiveBuffer(u32 *buffer, u32 nbWords)
|
||||
{
|
||||
for(; nbWords > 0; nbWords--)
|
||||
{
|
||||
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
|
||||
*buffer++ = REG_PXI_RECV;
|
||||
}
|
||||
}
|
||||
|
||||
Result bindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
|
||||
{
|
||||
Result res = 0;
|
||||
u32 mask = CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||||
if(receiveFIFONotEmptyInterrupt != NULL)
|
||||
{
|
||||
res = svcBindInterrupt(0x53, *receiveFIFONotEmptyInterrupt, 0, false);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||||
return res;
|
||||
}
|
||||
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
|
||||
}
|
||||
|
||||
if(sendFIFOEmptyInterrupt != NULL)
|
||||
{
|
||||
res = svcBindInterrupt(0x52, *sendFIFOEmptyInterrupt, 0, false);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||||
return res;
|
||||
}
|
||||
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||||
}
|
||||
|
||||
if(syncInterrupt != NULL)
|
||||
{
|
||||
res = svcBindInterrupt(0x50, *syncInterrupt, 0, false);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||||
return res;
|
||||
}
|
||||
REG_PXI_INTERRUPT_CNT |= SYNC_ENABLE_SYNC11_IRQ;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void unbindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
|
||||
{
|
||||
if(receiveFIFONotEmptyInterrupt != NULL)
|
||||
{
|
||||
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||||
svcUnbindInterrupt(0x53, *receiveFIFONotEmptyInterrupt);
|
||||
}
|
||||
|
||||
if(sendFIFOEmptyInterrupt != NULL)
|
||||
{
|
||||
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
|
||||
svcUnbindInterrupt(0x52, *sendFIFOEmptyInterrupt);
|
||||
}
|
||||
if(syncInterrupt != NULL)
|
||||
{
|
||||
REG_PXI_INTERRUPT_CNT &= ~SYNC_ENABLE_SYNC11_IRQ;
|
||||
svcUnbindInterrupt(0x50, *syncInterrupt);
|
||||
}
|
||||
}
|
||||
47
sysmodules/pxi/source/PXI.h
Normal file
47
sysmodules/pxi/source/PXI.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
PXI.h:
|
||||
PXI I/O functions.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#define PXI_REGS_BASE 0x1EC63000
|
||||
#define REG_PXI_SYNC *(vu32 *)(PXI_REGS_BASE + 0)
|
||||
#define REG_PXI_BYTE_RECEIVED_FROM_REMOTE *(vu8 *)(PXI_REGS_BASE)
|
||||
#define REG_PXI_BYTE_SENT_TO_REMOTE *(vu8 *)(PXI_REGS_BASE + 1)
|
||||
#define REG_PXI_INTERRUPT_CNT *(vu8 *)(PXI_REGS_BASE + 3)
|
||||
#define SYNC_TRIGGER_SYNC9_IRQ (1U << 6)
|
||||
#define SYNC_ENABLE_SYNC11_IRQ (1U << 7)
|
||||
|
||||
#define REG_PXI_CNT *(vu16 *)(PXI_REGS_BASE + 4)
|
||||
#define CNT_SEND_FIFO_FULL_STATUS (1U << 1)
|
||||
#define CNT_ENABLE_SEND_FIFO_EMPTY_IRQ (1U << 2)
|
||||
#define CNT_CLEAR_SEND_FIFO (1U << 3)
|
||||
#define CNT_RECEIVE_FIFO_EMPTY_STATUS (1U << 8)
|
||||
#define CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ (1U << 10)
|
||||
#define CNT_ACKNOWLEDGE_FIFO_ERROR (1U << 14)
|
||||
#define CNT_ENABLE_FIFOs (1U << 15)
|
||||
|
||||
#define REG_PXI_SEND *(vu32 *)(PXI_REGS_BASE + 8)
|
||||
#define REG_PXI_RECV *(vu32 *)(PXI_REGS_BASE + 12)
|
||||
|
||||
void PXIReset(void);
|
||||
void PXITriggerSync9IRQ(void);
|
||||
|
||||
bool PXIIsSendFIFOFull(void);
|
||||
void PXISendByte(u8 byte);
|
||||
void PXISendWord(u32 word);
|
||||
void PXISendBuffer(const u32 *buffer, u32 nbWords);
|
||||
|
||||
bool PXIIsReceiveFIFOEmpty(void);
|
||||
u8 PXIReceiveByte(void);
|
||||
u32 PXIReceiveWord(void);
|
||||
void PXIReceiveBuffer(u32 *buffer, u32 nbWords);
|
||||
|
||||
Result bindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt);
|
||||
void unbindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt);
|
||||
94
sysmodules/pxi/source/common.h
Normal file
94
sysmodules/pxi/source/common.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
common.h:
|
||||
Common types and global variables.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
typedef enum SessionState
|
||||
{
|
||||
STATE_IDLE = 0,
|
||||
STATE_RECEIVED_FROM_ARM11 = 1,
|
||||
STATE_SENT_TO_ARM9 = 2,
|
||||
STATE_RECEIVED_FROM_ARM9 = 3
|
||||
} SessionState;
|
||||
|
||||
typedef struct SessionData
|
||||
{
|
||||
SessionState state;
|
||||
u32 buffer[0x100/4];
|
||||
|
||||
Handle handle;
|
||||
u32 usedStaticBuffers;
|
||||
|
||||
RecursiveLock lock;
|
||||
} SessionData;
|
||||
|
||||
#define NB_STATIC_BUFFERS 21
|
||||
|
||||
typedef struct SessionManager
|
||||
{
|
||||
Handle sendAllBuffersToArm9Event, replySemaphore, PXISRV11CommandReceivedEvent, PXISRV11ReplySentEvent;
|
||||
u32 latest_PXI_MC5_val, pendingArm9Commands;
|
||||
u32 receivedServiceId;
|
||||
RecursiveLock senderLock;
|
||||
bool sendingDisabled;
|
||||
SessionData sessionData[10];
|
||||
|
||||
u32 currentlyProvidedStaticBuffers, freeStaticBuffers;
|
||||
} SessionManager;
|
||||
|
||||
//Page alignment is mandatory there
|
||||
extern u32 ALIGN(0x1000) staticBuffers[NB_STATIC_BUFFERS][0x1000/4];
|
||||
|
||||
extern Handle PXISyncInterrupt, PXITransferMutex;
|
||||
extern Handle terminationRequestedEvent;
|
||||
extern bool shouldTerminate;
|
||||
extern SessionManager sessionManager;
|
||||
|
||||
extern const u32 nbStaticBuffersByService[10];
|
||||
|
||||
static inline Result assertSuccess(Result res)
|
||||
{
|
||||
if(R_FAILED(res)) svcBreak(USERBREAK_PANIC);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline s32 getMSBPosition(u32 val)
|
||||
{
|
||||
return 31 - (s32) __builtin_clz(val);
|
||||
}
|
||||
|
||||
static inline s32 getLSBPosition(u32 val)
|
||||
{
|
||||
return __builtin_ffs(val) - 1;
|
||||
}
|
||||
|
||||
static inline u32 clearMSBs(u32 val, u32 nb)
|
||||
{
|
||||
for(u32 i = 0; i < nb; i++)
|
||||
{
|
||||
s32 pos = getMSBPosition(val);
|
||||
if(pos == -1) break;
|
||||
val &= ~(1 << pos);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32 countNbBitsSet(u32 val)
|
||||
{
|
||||
u32 nb = 0;
|
||||
while(val != 0)
|
||||
{
|
||||
val = clearMSBs(val, 1);
|
||||
nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
211
sysmodules/pxi/source/main.c
Normal file
211
sysmodules/pxi/source/main.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
main.c
|
||||
(De)initialization stuff. It's also here where sessions are being accepted.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "PXI.h"
|
||||
#include "common.h"
|
||||
#include "MyThread.h"
|
||||
#include "receiver.h"
|
||||
#include "sender.h"
|
||||
#include "memory.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()
|
||||
{
|
||||
__appExit();
|
||||
__sync_fini();
|
||||
svcExitProcess();
|
||||
}
|
||||
|
||||
void initSystem()
|
||||
{
|
||||
__sync_init();
|
||||
__system_initSyscalls();
|
||||
__appInit();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
19
sysmodules/pxi/source/memory.c
Normal file
19
sysmodules/pxi/source/memory.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
memory.c:
|
||||
Memory functions
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
//Adpated from CakesFW
|
||||
void memcpy(void *dest, const void *src, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
const u8 *srcc = (const u8 *)src;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
destc[i] = srcc[i];
|
||||
}
|
||||
13
sysmodules/pxi/source/memory.h
Normal file
13
sysmodules/pxi/source/memory.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
memory.h:
|
||||
Memory functions
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
||||
69
sysmodules/pxi/source/receiver.c
Normal file
69
sysmodules/pxi/source/receiver.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
receiver.c:
|
||||
Fetches replies coming from Process9, writing them in the appropriate buffer.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "receiver.h"
|
||||
#include "PXI.h"
|
||||
#include "memory.h"
|
||||
|
||||
static inline void receiveFromArm9(void)
|
||||
{
|
||||
u32 serviceId = PXIReceiveWord();
|
||||
|
||||
//The offcical implementation can return 0xD90043FA
|
||||
if(((serviceId >= 10)) || (sessionManager.sessionData[serviceId].state != STATE_SENT_TO_ARM9))
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
|
||||
sessionManager.receivedServiceId = serviceId;
|
||||
RecursiveLock_Lock(&sessionManager.sessionData[serviceId].lock);
|
||||
u32 replyHeader = PXIReceiveWord();
|
||||
u32 replySizeWords = (replyHeader & 0x3F) + ((replyHeader & 0xFC0) >> 6) + 1;
|
||||
|
||||
if(replySizeWords > 0x40) svcBreak(USERBREAK_PANIC);
|
||||
|
||||
u32 *buf = sessionManager.sessionData[serviceId].buffer;
|
||||
|
||||
buf[0] = replyHeader;
|
||||
PXIReceiveBuffer(buf + 1, replySizeWords - 1);
|
||||
sessionManager.sessionData[serviceId].state = STATE_RECEIVED_FROM_ARM9;
|
||||
RecursiveLock_Unlock(&sessionManager.sessionData[serviceId].lock);
|
||||
|
||||
if(serviceId == 0 && shouldTerminate)
|
||||
{
|
||||
assertSuccess(svcSignalEvent(terminationRequestedEvent));
|
||||
return;
|
||||
}
|
||||
|
||||
if(serviceId != 9)
|
||||
{
|
||||
s32 count;
|
||||
assertSuccess(svcReleaseSemaphore(&count, sessionManager.replySemaphore, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
assertSuccess(svcSignalEvent(sessionManager.PXISRV11CommandReceivedEvent));
|
||||
assertSuccess(svcWaitSynchronization(sessionManager.PXISRV11ReplySentEvent, -1LL));
|
||||
if( (sessionManager.sessionData[serviceId].state != STATE_SENT_TO_ARM9))
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
}
|
||||
}
|
||||
|
||||
void receiver(void)
|
||||
{
|
||||
Handle handles[] = {PXISyncInterrupt, terminationRequestedEvent};
|
||||
|
||||
assertSuccess(svcWaitSynchronization(sessionManager.PXISRV11ReplySentEvent, -1LL));
|
||||
while(true)
|
||||
{
|
||||
s32 index;
|
||||
assertSuccess(svcWaitSynchronizationN(&index, handles, 2, false, -1LL));
|
||||
|
||||
if(index == 1) return;
|
||||
while(!PXIIsReceiveFIFOEmpty())
|
||||
receiveFromArm9();
|
||||
}
|
||||
}
|
||||
13
sysmodules/pxi/source/receiver.h
Normal file
13
sysmodules/pxi/source/receiver.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
receiver.h:
|
||||
Fetches replies coming from Process9, writing them in the appropriate buffer.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void receiver(void);
|
||||
300
sysmodules/pxi/source/sender.c
Normal file
300
sysmodules/pxi/source/sender.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
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)
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include "sender.h"
|
||||
#include "PXI.h"
|
||||
#include "memory.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
sysmodules/pxi/source/sender.h
Normal file
15
sysmodules/pxi/source/sender.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
sender.h
|
||||
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).
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
Result sendPXICmdbuf(Handle *additionalHandle, u32 serviceId, u32 *buffer);
|
||||
void sender(void);
|
||||
void PXISRV11Handler(void);
|
||||
Reference in New Issue
Block a user