mirror of
https://github.com/wiiu-env/MochaPayload.git
synced 2024-12-22 22:21:52 +01:00
Add DK_PCHAR support to /dev/iosuhax
This commit is contained in:
parent
939b1837e4
commit
68c60ac2d7
@ -108,7 +108,7 @@ void instant_patches_setup(void) {
|
||||
|
||||
// Place the environment path at the end of our .text section.
|
||||
for (int i = 0; i < 0x100; i += 4) {
|
||||
*(volatile u32 *) (0x05119F00 - 0x05100000 + 0x13D80000 + i) = *(volatile u32 *) (0x0017FEF0 + i);
|
||||
*(volatile u32 *) (0x0511FF00 - 0x05100000 + 0x13D80000 + i) = *(volatile u32 *) (0x0017FEF0 + i);
|
||||
}
|
||||
|
||||
// force check USB storage on load
|
||||
@ -134,7 +134,7 @@ void instant_patches_setup(void) {
|
||||
|
||||
map_info.paddr = 0x05116000 - 0x05100000 + 0x13D80000;
|
||||
map_info.vaddr = 0x05116000;
|
||||
map_info.size = 0x4000;
|
||||
map_info.size = 0xA000;
|
||||
map_info.domain = 1; // MCP
|
||||
map_info.type = 3; // 0 = undefined, 1 = kernel only, 2 = read only, 3 = read write
|
||||
map_info.cached = 0xFFFFFFFF;
|
||||
|
@ -22,7 +22,6 @@
|
||||
* distribution.
|
||||
***************************************************************************/
|
||||
#include "ios_mcp_patches.h"
|
||||
#include "../../ios_mcp/ios_mcp.bin.h"
|
||||
#include "../../ios_mcp/ios_mcp_syms.h"
|
||||
#include "elf_patcher.h"
|
||||
#include "types.h"
|
||||
@ -41,7 +40,7 @@ void mcp_run_patches(u32 ios_elf_start) {
|
||||
section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start);
|
||||
// We can't use "_text_end" here because we need to copy the full 0x4000 to preserve the envrionmen path which
|
||||
// is at the end of the .text section.
|
||||
section_write(ios_elf_start, _text_start, (void *) mcp_get_phys_code_base(), 0x4000);
|
||||
section_write(ios_elf_start, _text_start, (void *) mcp_get_phys_code_base(), 0xA000);
|
||||
|
||||
u32 patch_count = (u32) (((u8 *) mcp_patches_table_end) - ((u8 *) mcp_patches_table)) / sizeof(patch_table_t);
|
||||
patch_table_entries(ios_elf_start, mcp_patches_table, patch_count);
|
||||
|
66
source/ios_mcp/imports.ld
Normal file
66
source/ios_mcp/imports.ld
Normal file
@ -0,0 +1,66 @@
|
||||
PROVIDE(printf = 0x0503dcc0);
|
||||
/* PROVIDE(printf = 0x05055438); */
|
||||
PROVIDE(memcmp = 0x05054d6c);
|
||||
PROVIDE(memcpy = 0x05054e54);
|
||||
PROVIDE(memset = 0x05054ef0);
|
||||
PROVIDE(vsnprintf = 0x05055c40);
|
||||
/*PROVIDE(snprintf = 0x05055c8c);*/
|
||||
PROVIDE(strncpy = 0x05055db4);
|
||||
PROVIDE(strnlen = 0x05055e94);
|
||||
PROVIDE(strncmp = 0x05055e10);
|
||||
PROVIDE(usleep = 0x050564e4);
|
||||
|
||||
PROVIDE(bspWrite = 0x0503d460);
|
||||
PROVIDE(bspRead = 0x0503d550);
|
||||
|
||||
PROVIDE(UCWriteSysConfig = 0x05044a8c);
|
||||
PROVIDE(UCReadSysConfig = 0x05044d5c);
|
||||
PROVIDE(UCClose = 0x05045024);
|
||||
PROVIDE(UCOpen = 0x05045028);
|
||||
|
||||
PROVIDE(IOS_CreateThread = 0x050567ec);
|
||||
PROVIDE(IOS_JoinThread = 0x050567f4);
|
||||
PROVIDE(IOS_CancelThread = 0x050567fc);
|
||||
PROVIDE(IOS_StartThread = 0x05056824);
|
||||
PROVIDE(IOS_GetThreadPriority = 0x0505683c);
|
||||
|
||||
PROVIDE(IOS_CreateMessageQueue = 0x0505684c);
|
||||
PROVIDE(IOS_DestroyMessageQueue = 0x05056854);
|
||||
PROVIDE(IOS_ReceiveMessage = 0x0505686c);
|
||||
|
||||
PROVIDE(IOS_CreateTimer = 0x05056884);
|
||||
PROVIDE(IOS_RestartTimer = 0x0505688c);
|
||||
PROVIDE(IOS_StopTimer = 0x05056894);
|
||||
PROVIDE(IOS_DestroyTimer = 0x0505689c);
|
||||
|
||||
PROVIDE(IOS_CheckDebugMode = 0x050568ec);
|
||||
PROVIDE(IOS_ReadOTP = 0x050568fc);
|
||||
|
||||
PROVIDE(IOS_HeapAlloc = 0x05056924);
|
||||
PROVIDE(IOS_HeapAllocAligned = 0x0505692c);
|
||||
PROVIDE(IOS_HeapFree = 0x05056934);
|
||||
|
||||
PROVIDE(IOS_Open = 0x05056984);
|
||||
PROVIDE(IOS_Close = 0x0505698c);
|
||||
PROVIDE(IOS_Ioctl = 0x050569ac);
|
||||
PROVIDE(IOS_Ioctlv = 0x050569b4);
|
||||
PROVIDE(IOS_IoctlvAsync = 0x050569ec);
|
||||
|
||||
PROVIDE(IOS_InvalidateDCache = 0x05056a74);
|
||||
PROVIDE(IOS_FlushDCache = 0x05056a7c);
|
||||
|
||||
PROVIDE(IOS_CreateSemaphore = 0x05056aa4);
|
||||
PROVIDE(IOS_WaitSemaphore = 0x05056aac);
|
||||
PROVIDE(IOS_SignalSemaphore = 0x05056ab4);
|
||||
PROVIDE(IOS_DestroySempahore = 0x05056abc);
|
||||
|
||||
PROVIDE(IOS_VirtToPhys = 0x05056a9c);
|
||||
|
||||
PROVIDE(IOS_CheckIOPAddressRange = 0x05056ad4);
|
||||
|
||||
PROVIDE(IOS_Shutdown = 0x05056b7c);
|
||||
PROVIDE(IOS_Syscall0x81 = 0x05056bf4);
|
||||
|
||||
PROVIDE(ppcHeartBeatThreadId = 0x05070458);
|
||||
PROVIDE(currentColdbootOS = 0x050b8174);
|
||||
PROVIDE(currentColdbootTitle = 0x050b817c);
|
@ -1,5 +1,7 @@
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
INCLUDE "imports.ld"
|
||||
|
||||
PROVIDE(snprintf = 0x05059010);
|
||||
|
||||
SECTIONS
|
||||
@ -22,6 +24,6 @@ SECTIONS
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT((SIZEOF(.text)) < 0x3F00, "text section is too big");
|
||||
ASSERT((SIZEOF(.text)) < 0x9F00, "text section is too big");
|
||||
ASSERT((SIZEOF(.bss)) < 0x3000, "bss section is too big");
|
||||
|
||||
|
370
source/ios_mcp/source/dk.c
Normal file
370
source/ios_mcp/source/dk.c
Normal file
@ -0,0 +1,370 @@
|
||||
#include "dk.h"
|
||||
#include "imports.h"
|
||||
#include "smd.h"
|
||||
#include "socket.h"
|
||||
#include "svc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//#define DEBUG_LOGGING
|
||||
|
||||
#define DK_PORT 3000
|
||||
#define DK_THREAD_INTERVAL 600
|
||||
|
||||
#define DK_SMD_IDX_READ 0
|
||||
#define DK_SMD_IDX_WRITE 1
|
||||
|
||||
static u8 threadStack[0x500] __attribute__((aligned(0x20)));
|
||||
static int threadRunning = 0;
|
||||
static int threadId = 0;
|
||||
static int servfd = 0;
|
||||
|
||||
static int setupServer(int port) {
|
||||
if (socketInit() < 0) {
|
||||
printf("DK: failed to init socketlib\n");
|
||||
smdIopClose(DK_SMD_IDX_READ);
|
||||
smdIopClose(DK_SMD_IDX_WRITE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("DK: socket init\n");
|
||||
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
printf("DK: failed to create socket\n");
|
||||
smdIopClose(DK_SMD_IDX_READ);
|
||||
smdIopClose(DK_SMD_IDX_WRITE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("DK: socket created\n");
|
||||
|
||||
int reuse = 1;
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
|
||||
printf("DK warning: failed to set SO_REUSEADDR\n");
|
||||
}
|
||||
|
||||
struct sockaddr_in servaddr;
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
servaddr.sin_port = port;
|
||||
if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) {
|
||||
printf("DK: failed to bind socket\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
printf("DK: socket bound\n");
|
||||
|
||||
return sockfd;
|
||||
|
||||
quit:;
|
||||
closesocket(sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int handleServer(int connfd) {
|
||||
int nonblock = 1;
|
||||
if (setsockopt(connfd, SOL_SOCKET, SO_NONBLOCK, &nonblock, sizeof(nonblock)) < 0) {
|
||||
printf("DK: failed to make connection non-blocking\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sack = 1;
|
||||
if (setsockopt(connfd, SOL_SOCKET, SO_TCPSACK, &sack, sizeof(sack)) < 0) {
|
||||
printf("DK: failed to set SO_TCPSACK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nodelay = 1;
|
||||
if (setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) {
|
||||
printf("DK: failed to set TCP_NODELAY\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create a message queue and timer
|
||||
uint32_t messageBuf;
|
||||
int queueId = IOS_CreateMessageQueue(&messageBuf, 1);
|
||||
if (queueId < 0) {
|
||||
printf("DK: failed to create message queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int timerId = IOS_CreateTimer(0, 0, queueId, 0xdeafcafe);
|
||||
if (timerId < 0) {
|
||||
printf("DK: failed to create timer\n");
|
||||
IOS_DestroyMessageQueue(queueId);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (threadRunning) {
|
||||
// restart timer
|
||||
if (IOS_RestartTimer(timerId, DK_THREAD_INTERVAL, 0)) {
|
||||
printf("DK: failed to restart timer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// wait until the timer sends a message
|
||||
uint32_t message;
|
||||
if (IOS_ReceiveMessage(queueId, &message, 0) < 0) {
|
||||
printf("DK: failed to receive message\n");
|
||||
break;
|
||||
}
|
||||
|
||||
SmdInterfaceState readState;
|
||||
if (smdIopGetInterfaceState(DK_SMD_IDX_READ, NULL, &readState) != 0) {
|
||||
printf("DK: Failed to get interface state, closing...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
SmdInterfaceState writeState;
|
||||
if (smdIopGetInterfaceState(DK_SMD_IDX_WRITE, NULL, &writeState) != 0) {
|
||||
printf("DK: Failed to get interface state, closing...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (readState != SMD_INTERFACE_STATE_OPENED || writeState != SMD_INTERFACE_STATE_OPENED) {
|
||||
printf("DK: Closing interfaces\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// process up to 100 writes before waiting
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
SmdReceiveData receiveData;
|
||||
if (smdIopReceive(DK_SMD_IDX_WRITE, &receiveData) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOGGING
|
||||
printf("DK: received write vector\n");
|
||||
#endif
|
||||
|
||||
if (receiveData.type != SMD_ELEMENT_TYPE_VECTOR) {
|
||||
printf("DK Warn: Received smd type %ld on write queue\n", receiveData.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (receiveData.vector->id != DK_PCHAR_COMMAND_WRITE) {
|
||||
printf("DK Warn: Received command %lx on write queue\n", receiveData.vector->id);
|
||||
smdIopSendVector(DK_SMD_IDX_WRITE, receiveData.vector);
|
||||
continue;
|
||||
}
|
||||
|
||||
DKPCHARResult *result = receiveData.vector->vecs[0].ptr;
|
||||
DKPCHARResponse *response = receiveData.vector->vecs[2].ptr;
|
||||
|
||||
response->buf = receiveData.vector->vecs[1].ptr;
|
||||
|
||||
// send data
|
||||
int32_t error = 0;
|
||||
uint32_t to_send = receiveData.vector->vecs[1].size;
|
||||
|
||||
#ifdef DEBUG_LOGGING
|
||||
printf("DK: sending %lu bytes\n", to_send);
|
||||
#endif
|
||||
|
||||
uint32_t offset = 0;
|
||||
while (to_send > 0) {
|
||||
int res = send(connfd, receiveData.vector->vecs[1].ptr + offset, to_send, 0);
|
||||
if (res < 0) {
|
||||
error = res;
|
||||
break;
|
||||
}
|
||||
|
||||
to_send -= res;
|
||||
offset += res;
|
||||
}
|
||||
|
||||
result->error = error;
|
||||
smdIopSendVector(DK_SMD_IDX_WRITE, receiveData.vector);
|
||||
}
|
||||
|
||||
// read pending data, if we have any
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
char buf[500];
|
||||
int32_t res = recv(connfd, buf, sizeof(buf), 0);
|
||||
if (res == -0xafffa /*EWOULDBLOCK*/) {
|
||||
// no more data to receive
|
||||
break;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
printf("DK: recv returned %lx\n", res);
|
||||
break;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
printf("DK: client disconnected\n");
|
||||
IOS_DestroyTimer(timerId);
|
||||
IOS_DestroyMessageQueue(queueId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOGGING
|
||||
printf("DK: recv: %ld\n", res);
|
||||
#endif
|
||||
|
||||
SmdReceiveData receiveData;
|
||||
if (smdIopReceive(DK_SMD_IDX_READ, &receiveData) != 0) {
|
||||
printf("DK Warn: no vector in read queue, dropping packet\n");
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOGGING
|
||||
printf("DK: received read vector\n");
|
||||
#endif
|
||||
|
||||
if (receiveData.type != SMD_ELEMENT_TYPE_VECTOR) {
|
||||
printf("DK Warn: Received smd type %ld on read queue\n", receiveData.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (receiveData.vector->id != DK_PCHAR_COMMAND_READ) {
|
||||
printf("DK Warn: Received command %lx on read queue\n", receiveData.vector->id);
|
||||
smdIopSendVector(DK_SMD_IDX_READ, receiveData.vector);
|
||||
continue;
|
||||
}
|
||||
|
||||
DKPCHARResult *result = receiveData.vector->vecs[0].ptr;
|
||||
DKPCHARResponse *response = receiveData.vector->vecs[2].ptr;
|
||||
|
||||
response->buf = receiveData.vector->vecs[1].ptr;
|
||||
|
||||
if (receiveData.vector->vecs[1].size < (uint32_t) res) {
|
||||
printf("DK: Warning truncating received data\n");
|
||||
res = receiveData.vector->vecs[1].size;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
memcpy(receiveData.vector->vecs[1].ptr, buf, res);
|
||||
result->error = 0;
|
||||
result->param0 = res;
|
||||
} else {
|
||||
result->error = res;
|
||||
}
|
||||
|
||||
smdIopSendVector(DK_SMD_IDX_READ, receiveData.vector);
|
||||
}
|
||||
}
|
||||
|
||||
IOS_DestroyTimer(timerId);
|
||||
IOS_DestroyMessageQueue(queueId);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dkThread(void *arg) {
|
||||
printf("DK: thread started\n");
|
||||
threadRunning = 1;
|
||||
|
||||
servfd = setupServer(DK_PORT);
|
||||
if (servfd < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (threadRunning) {
|
||||
if (listen(servfd, 1) != 0) {
|
||||
printf("DK: failed listening for connections\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf("DK: listening for connections on port %d\n", DK_PORT);
|
||||
|
||||
struct sockaddr_in clientaddr;
|
||||
socklen_t len = sizeof(clientaddr);
|
||||
int connfd = accept(servfd, (struct sockaddr *) &clientaddr, &len);
|
||||
if (connfd < 0) {
|
||||
printf("DK: failed to accept connection\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *addr = (uint8_t *) &clientaddr.sin_addr.s_addr;
|
||||
printf("DK: Connected to %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3]);
|
||||
|
||||
if (handleServer(connfd) < 0) {
|
||||
closesocket(connfd);
|
||||
break;
|
||||
}
|
||||
|
||||
closesocket(connfd);
|
||||
}
|
||||
|
||||
exit:;
|
||||
printf("DK: exited thread\n");
|
||||
if (servfd >= 0) {
|
||||
closesocket(servfd);
|
||||
servfd = -1;
|
||||
}
|
||||
|
||||
// close smd
|
||||
smdIopClose(DK_SMD_IDX_READ);
|
||||
smdIopClose(DK_SMD_IDX_WRITE);
|
||||
|
||||
threadRunning = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dkPCHARDeactivateSmd() {
|
||||
// close server socket and tell thread to stop
|
||||
if (servfd >= 0) {
|
||||
closesocket(servfd);
|
||||
servfd = -1;
|
||||
}
|
||||
|
||||
threadRunning = 0;
|
||||
|
||||
// wait for thread to return
|
||||
IOS_JoinThread(threadId, NULL);
|
||||
}
|
||||
|
||||
int dkPCHARActivateSmd(IOSVec *vecs) {
|
||||
int32_t ret = 0;
|
||||
DKPCHARResult *result = (DKPCHARResult *) vecs[0].ptr;
|
||||
DKPCHARActivateParams *params = (DKPCHARActivateParams *) vecs[1].ptr;
|
||||
|
||||
printf("PCHAR Activate (%lx) for %s: SMDs %s %s\n", params->command, params->path, params->smdReadName, params->smdWriteName);
|
||||
|
||||
// Prevent starting another thread while the old one is still running
|
||||
if (threadRunning) {
|
||||
printf("DK: thread is already running, stopping...\n");
|
||||
dkPCHARDeactivateSmd();
|
||||
}
|
||||
|
||||
ret = smdIopInit(DK_SMD_IDX_WRITE, (SmdControlTable *) vecs[2].ptr, params->smdWriteName, 0);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = smdIopInit(DK_SMD_IDX_READ, (SmdControlTable *) vecs[3].ptr, params->smdReadName, 0);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = smdIopOpen(DK_SMD_IDX_WRITE);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = smdIopOpen(DK_SMD_IDX_READ);
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
threadId = svcCreateThread(dkThread, 0, (u32 *) (threadStack + sizeof(threadStack)), sizeof(threadStack), 0x77, 0);
|
||||
if (threadId < 0) {
|
||||
ret = threadId;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (svcStartThread(threadId) < 0) {
|
||||
printf("DK: failed to start thread\n");
|
||||
ret = -11;
|
||||
}
|
||||
|
||||
done:;
|
||||
printf("PCHAR Activate %lx\n", ret);
|
||||
result->error = ret;
|
||||
return ret;
|
||||
}
|
47
source/ios_mcp/source/dk.h
Normal file
47
source/ios_mcp/source/dk.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "ipc_types.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PACKED
|
||||
#define PACKED __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef CHECK_SIZE
|
||||
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, #type " must be " #size " bytes")
|
||||
#endif
|
||||
|
||||
enum DKPCHARCommand {
|
||||
DK_PCHAR_COMMAND_READ = 0x40,
|
||||
DK_PCHAR_COMMAND_WRITE = 0x41,
|
||||
};
|
||||
|
||||
typedef struct PACKED {
|
||||
uint32_t command;
|
||||
uint8_t __unk[0x8];
|
||||
char path[0x20];
|
||||
uint8_t __padding[0x4];
|
||||
char smdWriteName[0x10];
|
||||
char smdReadName[0x10];
|
||||
} DKPCHARActivateParams;
|
||||
CHECK_SIZE(DKPCHARActivateParams, 0x50);
|
||||
|
||||
typedef struct PACKED {
|
||||
int32_t error;
|
||||
uint32_t param0;
|
||||
uint32_t param1;
|
||||
} DKPCHARResult;
|
||||
CHECK_SIZE(DKPCHARResult, 0xC);
|
||||
|
||||
typedef struct PACKED {
|
||||
uint32_t command;
|
||||
void *message;
|
||||
uint32_t unk;
|
||||
void *buf;
|
||||
uint32_t size;
|
||||
uint8_t __padding[0x3C];
|
||||
} DKPCHARResponse;
|
||||
CHECK_SIZE(DKPCHARResponse, 0x50);
|
||||
|
||||
int dkPCHARActivateSmd(IOSVec *vecs);
|
@ -1,25 +1,5 @@
|
||||
#include "imports.h"
|
||||
|
||||
void usleep(u32 time) {
|
||||
((void (*const)(u32)) 0x050564E4)(time);
|
||||
}
|
||||
|
||||
void *memset(void *dst, int val, size_t size) {
|
||||
char *_dst = dst;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
_dst[i] = val;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *(*const _memcpy)(void *dst, void *src, int size) = (void *) 0x05054E54;
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t size) {
|
||||
return _memcpy(dst, (void *) src, size);
|
||||
}
|
||||
|
||||
int strlen(const char *str) {
|
||||
unsigned int i = 0;
|
||||
while (str[i]) {
|
||||
@ -28,19 +8,6 @@ int strlen(const char *str) {
|
||||
return i;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
while (n && *s1 && (*s1 == *s2)) {
|
||||
++s1;
|
||||
++s2;
|
||||
--n;
|
||||
}
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return (*(unsigned char *) s1 - *(unsigned char *) s2);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to implement strncat() function in C
|
||||
char *strncat(char *destination, const char *source, size_t num) {
|
||||
// make ptr point to the end of destination string
|
||||
@ -56,18 +23,3 @@ char *strncat(char *destination, const char *source, size_t num) {
|
||||
// destination string is returned by standard strncat()
|
||||
return destination;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t size) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
dst[i] = src[i];
|
||||
if (src[i] == '\0')
|
||||
return dst;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int vsnprintf(char *s, size_t n, const char *format, va_list arg) {
|
||||
return ((int (*const)(char *, size_t, const char *, va_list)) 0x05055C40)(s, n, format, arg);
|
||||
}
|
||||
|
@ -7,6 +7,32 @@
|
||||
|
||||
#define MCP_SVC_BASE ((void *) 0x050567EC)
|
||||
|
||||
void usleep(u32 time);
|
||||
typedef enum {
|
||||
MEM_PERM_R = 1 << 0,
|
||||
MEM_PERM_W = 1 << 1,
|
||||
MEM_PERM_RW = (MEM_PERM_R | MEM_PERM_W),
|
||||
} MemPermFlags;
|
||||
|
||||
int IOS_JoinThread(int threadid, int32_t *returned_value);
|
||||
|
||||
int IOS_CreateMessageQueue(uint32_t *ptr, uint32_t n_msgs);
|
||||
int IOS_DestroyMessageQueue(int queueid);
|
||||
int IOS_SendMessage(int queueid, uint32_t message, uint32_t flags);
|
||||
int IOS_ReceiveMessage(int queueid, uint32_t *message, uint32_t flags);
|
||||
|
||||
int IOS_CreateTimer(uint32_t time_us, uint32_t repeat_time_us, int queueid, uint32_t message);
|
||||
int IOS_RestartTimer(int timerid, uint32_t time_us, uint32_t repeat_time_us);
|
||||
int IOS_DestroyTimer(int timerid);
|
||||
|
||||
void IOS_InvalidateDCache(void *ptr, uint32_t len);
|
||||
void IOS_FlushDCache(void *ptr, uint32_t len);
|
||||
|
||||
int32_t IOS_CheckIOPAddressRange(void *ptr, uint32_t size, MemPermFlags perm);
|
||||
uint32_t IOS_VirtToPhys(void *ptr);
|
||||
|
||||
int IOS_CreateSemaphore(int32_t maxCount, int32_t initialCount);
|
||||
int IOS_WaitSemaphore(int id, uint32_t tryWait);
|
||||
int IOS_SignalSemaphore(int id);
|
||||
int IOS_DestroySemaphore(int id);
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
* distribution.
|
||||
***************************************************************************/
|
||||
#include "../../common/kernel_commands.h"
|
||||
#include "dk.h"
|
||||
#include "fsa.h"
|
||||
#include "imports.h"
|
||||
#include "logger.h"
|
||||
@ -31,48 +32,50 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6
|
||||
#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3
|
||||
#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9
|
||||
#define IOS_ERROR_UNKNOWN 0xFFFFFFF7
|
||||
#define IOS_ERROR_NOEXISTS 0xFFFFFFFA
|
||||
#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6
|
||||
#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3
|
||||
#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9
|
||||
#define IOS_ERROR_UNKNOWN 0xFFFFFFF7
|
||||
#define IOS_ERROR_NOEXISTS 0xFFFFFFFA
|
||||
|
||||
#define IOCTL_MEM_WRITE 0x00
|
||||
#define IOCTL_MEM_READ 0x01
|
||||
#define IOCTL_SVC 0x02
|
||||
#define IOCTL_KILL_SERVER 0x03
|
||||
#define IOCTL_MEMCPY 0x04
|
||||
#define IOCTL_REPEATED_WRITE 0x05
|
||||
#define IOCTL_KERN_READ32 0x06
|
||||
#define IOCTL_KERN_WRITE32 0x07
|
||||
#define IOCTL_READ_OTP 0x08
|
||||
#define IOCTL_MEM_WRITE 0x00
|
||||
#define IOCTL_MEM_READ 0x01
|
||||
#define IOCTL_SVC 0x02
|
||||
#define IOCTL_KILL_SERVER 0x03
|
||||
#define IOCTL_MEMCPY 0x04
|
||||
#define IOCTL_REPEATED_WRITE 0x05
|
||||
#define IOCTL_KERN_READ32 0x06
|
||||
#define IOCTL_KERN_WRITE32 0x07
|
||||
#define IOCTL_READ_OTP 0x08
|
||||
|
||||
#define IOCTL_FSA_OPEN 0x40
|
||||
#define IOCTL_FSA_CLOSE 0x41
|
||||
#define IOCTL_FSA_MOUNT 0x42
|
||||
#define IOCTL_FSA_UNMOUNT 0x43
|
||||
#define IOCTL_FSA_GETDEVICEINFO 0x44
|
||||
#define IOCTL_FSA_OPENDIR 0x45
|
||||
#define IOCTL_FSA_READDIR 0x46
|
||||
#define IOCTL_FSA_CLOSEDIR 0x47
|
||||
#define IOCTL_FSA_MAKEDIR 0x48
|
||||
#define IOCTL_FSA_OPENFILE 0x49
|
||||
#define IOCTL_FSA_READFILE 0x4A
|
||||
#define IOCTL_FSA_WRITEFILE 0x4B
|
||||
#define IOCTL_FSA_STATFILE 0x4C
|
||||
#define IOCTL_FSA_CLOSEFILE 0x4D
|
||||
#define IOCTL_FSA_SETFILEPOS 0x4E
|
||||
#define IOCTL_FSA_GETSTAT 0x4F
|
||||
#define IOCTL_FSA_REMOVE 0x50
|
||||
#define IOCTL_FSA_REWINDDIR 0x51
|
||||
#define IOCTL_FSA_CHDIR 0x52
|
||||
#define IOCTL_FSA_RENAME 0x53
|
||||
#define IOCTL_FSA_RAW_OPEN 0x54
|
||||
#define IOCTL_FSA_RAW_READ 0x55
|
||||
#define IOCTL_FSA_RAW_WRITE 0x56
|
||||
#define IOCTL_FSA_RAW_CLOSE 0x57
|
||||
#define IOCTL_FSA_CHANGEMODE 0x58
|
||||
#define IOCTL_FSA_FLUSHVOLUME 0x59
|
||||
#define IOCTL_FSA_OPEN 0x40
|
||||
#define IOCTL_FSA_CLOSE 0x41
|
||||
#define IOCTL_FSA_MOUNT 0x42
|
||||
#define IOCTL_FSA_UNMOUNT 0x43
|
||||
#define IOCTL_FSA_GETDEVICEINFO 0x44
|
||||
#define IOCTL_FSA_OPENDIR 0x45
|
||||
#define IOCTL_FSA_READDIR 0x46
|
||||
#define IOCTL_FSA_CLOSEDIR 0x47
|
||||
#define IOCTL_FSA_MAKEDIR 0x48
|
||||
#define IOCTL_FSA_OPENFILE 0x49
|
||||
#define IOCTL_FSA_READFILE 0x4A
|
||||
#define IOCTL_FSA_WRITEFILE 0x4B
|
||||
#define IOCTL_FSA_STATFILE 0x4C
|
||||
#define IOCTL_FSA_CLOSEFILE 0x4D
|
||||
#define IOCTL_FSA_SETFILEPOS 0x4E
|
||||
#define IOCTL_FSA_GETSTAT 0x4F
|
||||
#define IOCTL_FSA_REMOVE 0x50
|
||||
#define IOCTL_FSA_REWINDDIR 0x51
|
||||
#define IOCTL_FSA_CHDIR 0x52
|
||||
#define IOCTL_FSA_RENAME 0x53
|
||||
#define IOCTL_FSA_RAW_OPEN 0x54
|
||||
#define IOCTL_FSA_RAW_READ 0x55
|
||||
#define IOCTL_FSA_RAW_WRITE 0x56
|
||||
#define IOCTL_FSA_RAW_CLOSE 0x57
|
||||
#define IOCTL_FSA_CHANGEMODE 0x58
|
||||
#define IOCTL_FSA_FLUSHVOLUME 0x59
|
||||
|
||||
#define IOCTLV_DK_PCHAR_ACTIVATE 0x30
|
||||
|
||||
static int ipcNodeKilled;
|
||||
static u8 threadStack[0x1000] __attribute__((aligned(0x20)));
|
||||
@ -384,6 +387,21 @@ static int ipc_ioctl(ipcmessage *message) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ipc_ioctlv(ipcmessage *message) {
|
||||
int res = 0;
|
||||
|
||||
switch (message->ioctlv.command) {
|
||||
case IOCTLV_DK_PCHAR_ACTIVATE:
|
||||
res = dkPCHARActivateSmd(message->ioctlv.vecs);
|
||||
break;
|
||||
default:
|
||||
res = IOS_ERROR_INVALID_ARG;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ipc_thread(void *arg) {
|
||||
int res;
|
||||
ipcmessage *message;
|
||||
@ -417,7 +435,7 @@ static int ipc_thread(void *arg) {
|
||||
}
|
||||
case IOS_IOCTLV: {
|
||||
log_printf("IOS_IOCTLV\n");
|
||||
res = 0;
|
||||
res = ipc_ioctlv(message);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -19,6 +19,11 @@
|
||||
#define IOS_RESUME 0x0D
|
||||
#define IOS_SVCMSG 0x0E
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
uint32_t len;
|
||||
uint32_t paddr;
|
||||
} IOSVec;
|
||||
|
||||
/* IPC message */
|
||||
typedef struct ipcmessage {
|
||||
@ -61,9 +66,9 @@ typedef struct ipcmessage {
|
||||
struct _ioctlv {
|
||||
u32 command;
|
||||
|
||||
u32 num_in;
|
||||
u32 num_io;
|
||||
struct _ioctlv *vector;
|
||||
uint32_t num_in;
|
||||
uint32_t num_out;
|
||||
IOSVec *vecs;
|
||||
} ioctlv;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "ipc.h"
|
||||
#include "wupserver.h"
|
||||
|
||||
static int threadsStarted = 0;
|
||||
|
||||
|
@ -79,9 +79,9 @@ int _MCP_LoadFile_patch(ipcmessage *msg) {
|
||||
if (strncmp(request->name, "men.rpx", strlen("men.rpx")) == 0) {
|
||||
rpxpath[0] = '\0';
|
||||
if (skipPPCSetup) {
|
||||
snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/men.rpx", &((char *) 0x05119F00)[19]); // Copy in environment path
|
||||
snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/men.rpx", &((char *) 0x0511FF00)[19]); // Copy in environment path
|
||||
} else {
|
||||
snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/root.rpx", &((char *) 0x05119F00)[19]); // Copy in environment path
|
||||
snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/root.rpx", &((char *) 0x0511FF00)[19]); // Copy in environment path
|
||||
}
|
||||
|
||||
// At startup we want to hook into the Wii U Menu by replacing the men.rpx with a file from the SD Card
|
||||
@ -296,7 +296,7 @@ int _MCP_ioctl100_patch(ipcmessage *msg) {
|
||||
}
|
||||
case IPC_CUSTOM_COPY_ENVIRONMENT_PATH: {
|
||||
if (msg->ioctl.buffer_io && msg->ioctl.length_io >= 0x100) {
|
||||
strncpy((char *) msg->ioctl.buffer_io, (void *) 0x05119F00, 0xFF);
|
||||
strncpy((char *) msg->ioctl.buffer_io, (void *) 0x0511FF00, 0xFF);
|
||||
return 0;
|
||||
} else {
|
||||
return 29;
|
||||
|
320
source/ios_mcp/source/smd.c
Normal file
320
source/ios_mcp/source/smd.c
Normal file
@ -0,0 +1,320 @@
|
||||
#include "smd.h"
|
||||
|
||||
#include <imports.h>
|
||||
#include <string.h>
|
||||
|
||||
static SmdIopContext contexts[8];
|
||||
|
||||
static void *smdPhysToVirt(SmdIopContext *ctx, uint32_t paddr) {
|
||||
return (void *) (paddr + ctx->memVirtOffset);
|
||||
}
|
||||
|
||||
static uint32_t smdVirtToPhys(SmdIopContext *ctx, void *vaddr) {
|
||||
return (uint32_t) vaddr + ctx->memPhysOffset;
|
||||
}
|
||||
|
||||
int32_t smdIopInit(int32_t index, SmdControlTable *table, const char *name, int lock) {
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
|
||||
// Verify table pointer
|
||||
if (IOS_CheckIOPAddressRange(table, sizeof(SmdControlTable), MEM_PERM_RW) != 0) {
|
||||
return -0xc0007;
|
||||
}
|
||||
|
||||
ctx->controlTable = table;
|
||||
|
||||
if (lock && !ctx->hasSemaphore) {
|
||||
ctx->semaphore = IOS_CreateSemaphore(1, 1);
|
||||
if (ctx->semaphore < 0) {
|
||||
return -0xc0008;
|
||||
}
|
||||
|
||||
ctx->hasSemaphore = 1;
|
||||
}
|
||||
ctx->shouldLock = lock;
|
||||
|
||||
IOS_InvalidateDCache(table, sizeof(SmdControlTable));
|
||||
|
||||
if (strncmp(table->name, name, sizeof(table->name)) != 0) {
|
||||
return -0xc0007;
|
||||
}
|
||||
|
||||
// Calculate virt and phys offsets
|
||||
uint32_t paddr = IOS_VirtToPhys(table);
|
||||
ctx->memVirtOffset = (int32_t) table - paddr;
|
||||
ctx->memPhysOffset = paddr - (int32_t) table;
|
||||
|
||||
ctx->iopElementBuf = (SmdElement *) smdPhysToVirt(ctx, table->iopInterface.bufPaddr);
|
||||
ctx->iopElementCount = table->iopInterface.elementCount;
|
||||
|
||||
ctx->ppcElementBuf = (SmdElement *) smdPhysToVirt(ctx, table->ppcInterface.bufPaddr);
|
||||
ctx->ppcElementCount = table->ppcInterface.elementCount;
|
||||
|
||||
// Verify element bufffers
|
||||
if (IOS_CheckIOPAddressRange(ctx->iopElementBuf, ctx->iopElementCount * sizeof(SmdElement), MEM_PERM_RW) != 0 ||
|
||||
IOS_CheckIOPAddressRange(ctx->ppcElementBuf, ctx->ppcElementCount * sizeof(SmdElement), MEM_PERM_RW) != 0) {
|
||||
return -0xc0007;
|
||||
}
|
||||
|
||||
ctx->state = SMD_STATE_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t smdIopOpen(int32_t index) {
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
if (ctx->state < SMD_STATE_INITIALIZED) {
|
||||
return -0xc000d;
|
||||
}
|
||||
|
||||
// Update interface state
|
||||
ctx->controlTable->iopInterface.state = SMD_INTERFACE_STATE_OPENED;
|
||||
IOS_FlushDCache(&ctx->controlTable->iopInterface.state, 4);
|
||||
|
||||
ctx->state = SMD_STATE_OPENED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t smdIopClose(int32_t index) {
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
if (ctx->state < SMD_STATE_INITIALIZED) {
|
||||
return -0xc000d;
|
||||
}
|
||||
|
||||
// Update interface state
|
||||
ctx->controlTable->iopInterface.state = SMD_INTERFACE_STATE_CLOSED;
|
||||
IOS_FlushDCache(&ctx->controlTable->iopInterface.state, 4);
|
||||
|
||||
ctx->state = SMD_STATE_CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t smdIopGetInterfaceState(int32_t index, SmdInterfaceState *iopState, SmdInterfaceState *ppcState) {
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
if (ctx->state < SMD_STATE_INITIALIZED) {
|
||||
return -0xc000d;
|
||||
}
|
||||
|
||||
// Read interface states
|
||||
if (ppcState) {
|
||||
IOS_InvalidateDCache(&ctx->controlTable->ppcInterface.state, 4);
|
||||
*ppcState = (SmdInterfaceState) ctx->controlTable->ppcInterface.state;
|
||||
}
|
||||
|
||||
if (iopState) {
|
||||
IOS_InvalidateDCache(&ctx->controlTable->iopInterface.state, 4);
|
||||
*iopState = (SmdInterfaceState) ctx->controlTable->iopInterface.state;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t smdIopReceive(int32_t index, SmdReceiveData *data) {
|
||||
int32_t ret = 0;
|
||||
int32_t incoming;
|
||||
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
SmdInterface *iface = &ctx->controlTable->iopInterface;
|
||||
|
||||
memset(data, 0, sizeof(SmdReceiveData));
|
||||
|
||||
if (ctx->shouldLock) {
|
||||
IOS_WaitSemaphore(ctx->semaphore, 0);
|
||||
}
|
||||
|
||||
IOS_InvalidateDCache(iface, sizeof(SmdInterface));
|
||||
|
||||
if (iface->readOffset > (int32_t) ctx->iopElementCount) {
|
||||
ret = -0xc0007;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// figure out how many incoming elements we can receive
|
||||
if (iface->readOffset < iface->writeOffset) {
|
||||
incoming = iface->writeOffset - iface->readOffset;
|
||||
} else if (iface->writeOffset < iface->readOffset) {
|
||||
incoming = iface->elementCount - iface->readOffset;
|
||||
if (iface->writeOffset > 0) {
|
||||
incoming += iface->writeOffset;
|
||||
}
|
||||
} else {
|
||||
ret = -0xc0005;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (incoming <= 0) {
|
||||
ret = -0xc0005;
|
||||
goto done;
|
||||
}
|
||||
|
||||
SmdElement *element = &ctx->iopElementBuf[iface->readOffset];
|
||||
IOS_InvalidateDCache(element, sizeof(SmdElement));
|
||||
|
||||
data->size = element->size;
|
||||
data->type = element->type;
|
||||
|
||||
// handle message types
|
||||
if (element->type == SMD_ELEMENT_TYPE_MESSAGE) {
|
||||
if (element->size > 0x80) {
|
||||
ret = -0xc0001;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(data->message, element->data, element->size);
|
||||
} else if (element->type == SMD_ELEMENT_TYPE_VECTOR_SPEC) {
|
||||
SmdVector *vec = &element->spec;
|
||||
data->spec.count = vec->count;
|
||||
data->spec.id = vec->id;
|
||||
|
||||
if (data->spec.count > 4) {
|
||||
ret = -0xc0002;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Translate and verify spec pointers
|
||||
for (int i = 0; i < data->spec.count; ++i) {
|
||||
SmdVectorSpec *spec = &data->spec.vecs[i];
|
||||
spec->ptr = smdPhysToVirt(ctx, (uint32_t) vec->vecs[i].ptr);
|
||||
spec->size = vec->vecs[i].size;
|
||||
|
||||
if (IOS_CheckIOPAddressRange(spec->ptr, spec->size, MEM_PERM_RW) != 0) {
|
||||
ret = -0xc000f;
|
||||
goto done;
|
||||
}
|
||||
|
||||
IOS_InvalidateDCache(spec->ptr, spec->size);
|
||||
}
|
||||
} else if (element->type == SMD_ELEMENT_TYPE_VECTOR) {
|
||||
SmdVector *vec = (SmdVector *) smdPhysToVirt(ctx, element->vectorPaddr);
|
||||
IOS_InvalidateDCache(vec, sizeof(SmdVector));
|
||||
|
||||
if (vec->count > 4) {
|
||||
ret = -0xc0002;
|
||||
goto done;
|
||||
}
|
||||
|
||||
data->vector = vec;
|
||||
|
||||
// Translate and verify pointers
|
||||
for (int i = 0; i < vec->count; ++i) {
|
||||
SmdVectorSpec *spec = &data->vector->vecs[i];
|
||||
spec->ptr = smdPhysToVirt(ctx, (uint32_t) spec->ptr);
|
||||
|
||||
if (IOS_CheckIOPAddressRange(spec->ptr, spec->size, MEM_PERM_RW) != 0) {
|
||||
ret = -0xc000f;
|
||||
goto done;
|
||||
}
|
||||
|
||||
IOS_InvalidateDCache(spec->ptr, spec->size);
|
||||
}
|
||||
} else {
|
||||
ret = -0xc0006;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Increment read offset
|
||||
iface->readOffset = (iface->readOffset + 1) % iface->elementCount;
|
||||
IOS_FlushDCache(&iface->readOffset, 4);
|
||||
|
||||
done:;
|
||||
if (ctx->shouldLock) {
|
||||
IOS_SignalSemaphore(ctx->semaphore);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t writeElement(SmdIopContext *ctx, SmdElementType type, void *data, uint32_t size) {
|
||||
int32_t ret = 0;
|
||||
int32_t outgoing;
|
||||
|
||||
if (ctx->shouldLock) {
|
||||
IOS_WaitSemaphore(ctx->semaphore, 0);
|
||||
}
|
||||
|
||||
SmdInterface *iface = &ctx->controlTable->ppcInterface;
|
||||
IOS_InvalidateDCache(iface, sizeof(SmdInterface));
|
||||
|
||||
if (iface->writeOffset > (int32_t) ctx->ppcElementCount) {
|
||||
ret = -0xc0007;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// figure out how many outgoing messages we can send
|
||||
if (iface->writeOffset < iface->readOffset) {
|
||||
outgoing = iface->readOffset - iface->writeOffset;
|
||||
} else {
|
||||
outgoing = iface->elementCount - iface->writeOffset;
|
||||
if (iface->readOffset >= 0) {
|
||||
outgoing += iface->readOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (outgoing <= 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// write data to element
|
||||
SmdElement *element = &ctx->ppcElementBuf[iface->writeOffset];
|
||||
element->type = type;
|
||||
element->size = size;
|
||||
memcpy(element->data, data, size);
|
||||
|
||||
IOS_FlushDCache(element, sizeof(SmdElement));
|
||||
|
||||
// Increment write offset
|
||||
iface->writeOffset = (iface->writeOffset + 1) % iface->elementCount;
|
||||
IOS_FlushDCache(&iface->writeOffset, 4);
|
||||
|
||||
done:;
|
||||
if (ctx->shouldLock) {
|
||||
IOS_SignalSemaphore(ctx->semaphore);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t smdIopSendVector(int32_t index, SmdVector *vector) {
|
||||
if (index > 7) {
|
||||
return -0xc0003;
|
||||
}
|
||||
|
||||
SmdIopContext *ctx = &contexts[index];
|
||||
|
||||
if (vector->count > 4) {
|
||||
return -0xc0002;
|
||||
}
|
||||
|
||||
// flush and translate pointers
|
||||
for (int i = 0; i < vector->count; ++i) {
|
||||
SmdVectorSpec *spec = &vector->vecs[i];
|
||||
IOS_FlushDCache(spec->ptr, spec->size);
|
||||
|
||||
spec->ptr = (void *) smdVirtToPhys(ctx, spec->ptr);
|
||||
}
|
||||
|
||||
IOS_FlushDCache(vector, sizeof(SmdVector));
|
||||
|
||||
// write vector paddr as element
|
||||
uint32_t paddr = smdVirtToPhys(ctx, vector);
|
||||
return writeElement(ctx, SMD_ELEMENT_TYPE_VECTOR, &paddr, sizeof(paddr));
|
||||
}
|
128
source/ios_mcp/source/smd.h
Normal file
128
source/ios_mcp/source/smd.h
Normal file
@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PACKED
|
||||
#define PACKED __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef CHECK_SIZE
|
||||
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, #type " must be " #size " bytes")
|
||||
#endif
|
||||
|
||||
typedef enum SmdState SmdState;
|
||||
typedef enum SmdInterfaceState SmdInterfaceState;
|
||||
typedef enum SmdElementType SmdElementType;
|
||||
typedef struct SmdIopContext SmdIopContext;
|
||||
typedef struct SmdInterface SmdInterface;
|
||||
typedef struct SmdControlTable SmdControlTable;
|
||||
typedef struct SmdVectorSpec SmdVectorSpec;
|
||||
typedef struct SmdVector SmdVector;
|
||||
typedef struct SmdElement SmdElement;
|
||||
typedef struct SmdReceiveData SmdReceiveData;
|
||||
|
||||
enum SmdState {
|
||||
SMD_STATE_INVALID = 0,
|
||||
SMD_STATE_INITIALIZED = 2,
|
||||
SMD_STATE_CLOSED = 3,
|
||||
SMD_STATE_OPENED = 4,
|
||||
};
|
||||
|
||||
enum SmdInterfaceState {
|
||||
SMD_INTERFACE_STATE_OPENED = 0x2222,
|
||||
SMD_INTERFACE_STATE_CLOSED = 0x3333,
|
||||
};
|
||||
|
||||
enum SmdElementType {
|
||||
SMD_ELEMENT_TYPE_MESSAGE = 0,
|
||||
SMD_ELEMENT_TYPE_VECTOR_SPEC = 1,
|
||||
SMD_ELEMENT_TYPE_VECTOR = 2,
|
||||
};
|
||||
|
||||
struct SmdIopContext {
|
||||
SmdControlTable *controlTable;
|
||||
int32_t memVirtOffset;
|
||||
int32_t memPhysOffset;
|
||||
int shouldLock;
|
||||
int semaphore;
|
||||
int hasSemaphore;
|
||||
int logHandle;
|
||||
SmdElement *iopElementBuf;
|
||||
uint32_t iopElementCount;
|
||||
SmdElement *ppcElementBuf;
|
||||
uint32_t ppcElementCount;
|
||||
SmdState state;
|
||||
};
|
||||
|
||||
struct PACKED SmdInterface {
|
||||
uint32_t state;
|
||||
uint8_t __padding0[0x7C];
|
||||
uint32_t elementCount;
|
||||
uint8_t __padding1[0x7C];
|
||||
int32_t readOffset;
|
||||
uint8_t __padding2[0x7C];
|
||||
int32_t writeOffset;
|
||||
uint8_t __padding3[0x7C];
|
||||
uint32_t bufPaddr;
|
||||
uint8_t __padding4[0x7C];
|
||||
};
|
||||
CHECK_SIZE(SmdInterface, 0x280);
|
||||
|
||||
struct PACKED SmdControlTable {
|
||||
char name[0x10];
|
||||
uint32_t reinitCount;
|
||||
uint8_t __padding0[0x6C];
|
||||
SmdInterface iopInterface;
|
||||
uint8_t __padding1[0x40];
|
||||
SmdInterface ppcInterface;
|
||||
uint8_t __padding2[0x40];
|
||||
};
|
||||
CHECK_SIZE(SmdControlTable, 0x600);
|
||||
|
||||
struct PACKED SmdVectorSpec {
|
||||
void *ptr;
|
||||
uint32_t size;
|
||||
};
|
||||
CHECK_SIZE(SmdVectorSpec, 0x8);
|
||||
|
||||
struct PACKED SmdVector {
|
||||
uint32_t id;
|
||||
int32_t count;
|
||||
SmdVectorSpec vecs[4];
|
||||
};
|
||||
CHECK_SIZE(SmdVector, 0x28);
|
||||
|
||||
struct PACKED SmdElement {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
union {
|
||||
uint8_t data[0xf8];
|
||||
SmdVector spec;
|
||||
uint32_t vectorPaddr;
|
||||
};
|
||||
};
|
||||
CHECK_SIZE(SmdElement, 0x100);
|
||||
|
||||
struct PACKED SmdReceiveData {
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
union {
|
||||
uint8_t message[0x80];
|
||||
SmdVector spec;
|
||||
SmdVector *vector;
|
||||
};
|
||||
};
|
||||
CHECK_SIZE(SmdReceiveData, 0x88);
|
||||
|
||||
int32_t smdIopInit(int32_t index, SmdControlTable *table, const char *name, int lock);
|
||||
|
||||
int32_t smdIopOpen(int32_t index);
|
||||
|
||||
int32_t smdIopClose(int32_t index);
|
||||
|
||||
int32_t smdIopGetInterfaceState(int32_t index, SmdInterfaceState *iopState, SmdInterfaceState *ppcState);
|
||||
|
||||
int32_t smdIopReceive(int32_t index, SmdReceiveData *data);
|
||||
|
||||
int32_t smdIopSendVector(int32_t index, SmdVector *vector);
|
@ -209,3 +209,27 @@ int send(int sockfd, const void *buf, size_t len, int flags) {
|
||||
freeIobuf(iobuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
void *data_buf = svcAllocAlign(0xCAFF, optlen, 0x40);
|
||||
if (!data_buf) return -100;
|
||||
|
||||
u8 *iobuf = allocIobuf(sizeof(IOSVec) * 2 + sizeof(uint32_t) * 3);
|
||||
iovec_s *iovec = (iovec_s *) iobuf;
|
||||
|
||||
memcpy(data_buf, optval, optlen);
|
||||
iovec[0].ptr = data_buf;
|
||||
iovec[0].len = optlen;
|
||||
|
||||
iovec[1].ptr = iovec;
|
||||
iovec[1].len = sizeof(IOSVec) * 3;
|
||||
|
||||
((uint32_t *) iovec)[6] = sockfd;
|
||||
((uint32_t *) iovec)[7] = level;
|
||||
((uint32_t *) iovec)[8] = optname;
|
||||
|
||||
int ret = svcIoctlv(socket_handle, 0x9, 2, 0, iovec);
|
||||
freeIobuf(iobuf);
|
||||
freeIobuf(data_buf);
|
||||
return ret;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SOL_SOCKET 0xFFFF
|
||||
#define SOL_SOCKET -1
|
||||
|
||||
#define PF_UNSPEC 0
|
||||
#define PF_INET 2
|
||||
@ -30,24 +30,29 @@
|
||||
#define SHUT_WR 1
|
||||
#define SHUT_RDWR 2
|
||||
|
||||
#define SO_DEBUG 0x0001
|
||||
#define SO_ACCEPTCONN 0x0002
|
||||
#define SO_REUSEADDR 0x0004
|
||||
#define SO_KEEPALIVE 0x0008
|
||||
#define SO_DONTROUTE 0x0010
|
||||
#define SO_BROADCAST 0x0020
|
||||
#define SO_USELOOPBACK 0x0040
|
||||
#define SO_LINGER 0x0080
|
||||
#define SO_OOBINLINE 0x0100
|
||||
#define SO_REUSEPORT 0x0200
|
||||
#define SO_SNDBUF 0x1001
|
||||
#define SO_RCVBUF 0x1002
|
||||
#define SO_SNDLOWAT 0x1003
|
||||
#define SO_RCVLOWAT 0x1004
|
||||
#define SO_SNDTIMEO 0x1005
|
||||
#define SO_RCVTIMEO 0x1006
|
||||
#define SO_ERROR 0x1007
|
||||
#define SO_TYPE 0x1008
|
||||
/*
|
||||
* SOL_SOCKET options
|
||||
*/
|
||||
#define SO_REUSEADDR 0x0004 // reuse address
|
||||
#define SO_KEEPALIVE 0x0008 // keep connections alive
|
||||
#define SO_BROADCAST 0x0020 // broadcast
|
||||
#define SO_LINGER 0x0080 // linger (no effect?)
|
||||
#define SO_OOBINLINE 0x0100 // out-of-band data inline (no effect?)
|
||||
#define SO_TCPSACK 0x0200 // set tcp selective acknowledgment
|
||||
#define SO_WINSCALE 0x0400 // set tcp window scaling
|
||||
#define SO_SNDBUF 0x1001 // send buffer size
|
||||
#define SO_RCVBUF 0x1002 // receive buffer size
|
||||
#define SO_SNDLOWAT 0x1003 // send low-water mark (no effect?)
|
||||
#define SO_RCVLOWAT 0x1004 // receive low-water mark
|
||||
#define SO_TYPE 0x1008 // get socket type
|
||||
#define SO_ERROR 0x1009 // get socket error
|
||||
#define SO_RXDATA 0x1011 // get count of bytes in sb_rcv
|
||||
#define SO_TXDATA 0x1012 // get count of bytes in sb_snd
|
||||
#define SO_NBIO 0x1014 // set socket to NON-blocking mode
|
||||
#define SO_BIO 0x1015 // set socket to blocking mode
|
||||
#define SO_NONBLOCK 0x1016 // set/get blocking mode via optval param
|
||||
|
||||
#define TCP_NODELAY 0x2004
|
||||
|
||||
#define INADDR_ANY 0x00000000
|
||||
#define INADDR_BROADCAST 0xFFFFFFFF
|
||||
|
Loading…
Reference in New Issue
Block a user