mirror of
https://github.com/wiiu-env/wiiu-nanddumper-payload.git
synced 2024-11-15 08:05:11 +01:00
481 lines
15 KiB
C
481 lines
15 KiB
C
|
/***************************************************************************
|
||
|
* Copyright (C) 2016
|
||
|
* by Dimok
|
||
|
*
|
||
|
* This software is provided 'as-is', without any express or implied
|
||
|
* warranty. In no event will the authors be held liable for any
|
||
|
* damages arising from the use of this software.
|
||
|
*
|
||
|
* Permission is granted to anyone to use this software for any
|
||
|
* purpose, including commercial applications, and to alter it and
|
||
|
* redistribute it freely, subject to the following restrictions:
|
||
|
*
|
||
|
* 1. The origin of this software must not be misrepresented; you
|
||
|
* must not claim that you wrote the original software. If you use
|
||
|
* this software in a product, an acknowledgment in the product
|
||
|
* documentation would be appreciated but is not required.
|
||
|
*
|
||
|
* 2. Altered source versions must be plainly marked as such, and
|
||
|
* must not be misrepresented as being the original software.
|
||
|
*
|
||
|
* 3. This notice may not be removed or altered from any source
|
||
|
* distribution.
|
||
|
***************************************************************************/
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include "imports.h"
|
||
|
#include "fsa.h"
|
||
|
#include "svc.h"
|
||
|
#include "text.h"
|
||
|
#include "logger.h"
|
||
|
#include "fsa.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 IOCTL_MEM_WRITE 0x00
|
||
|
#define IOCTL_MEM_READ 0x01
|
||
|
#define IOCTL_SVC 0x02
|
||
|
#define IOCTL_MEMCPY 0x04
|
||
|
#define IOCTL_REPEATED_WRITE 0x05
|
||
|
#define IOCTL_KERN_READ32 0x06
|
||
|
#define IOCTL_KERN_WRITE32 0x07
|
||
|
|
||
|
#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
|
||
|
|
||
|
static u8 threadStack[0x1000] __attribute__((aligned(0x20)));
|
||
|
|
||
|
static int ipc_ioctl(ipcmessage *message)
|
||
|
{
|
||
|
int res = 0;
|
||
|
|
||
|
switch(message->ioctl.command)
|
||
|
{
|
||
|
case IOCTL_MEM_WRITE:
|
||
|
{
|
||
|
if(message->ioctl.length_in < 4)
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy((void*)message->ioctl.buffer_in[0], message->ioctl.buffer_in + 1, message->ioctl.length_in - 4);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_MEM_READ:
|
||
|
{
|
||
|
if(message->ioctl.length_in < 4)
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy(message->ioctl.buffer_io, (void*)message->ioctl.buffer_in[0], message->ioctl.length_io);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_SVC:
|
||
|
{
|
||
|
if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4))
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int svc_id = message->ioctl.buffer_in[0];
|
||
|
int size_arguments = message->ioctl.length_in - 4;
|
||
|
|
||
|
u32 arguments[8];
|
||
|
memset(arguments, 0x00, sizeof(arguments));
|
||
|
memcpy(arguments, message->ioctl.buffer_in + 1, (size_arguments < 8 * 4) ? size_arguments : (8 * 4));
|
||
|
|
||
|
// return error code as data
|
||
|
message->ioctl.buffer_io[0] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_MEMCPY:
|
||
|
{
|
||
|
if(message->ioctl.length_in < 12)
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy((void*)message->ioctl.buffer_in[0], (void*)message->ioctl.buffer_in[1], message->ioctl.buffer_in[2]);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_REPEATED_WRITE:
|
||
|
{
|
||
|
if(message->ioctl.length_in < 12)
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
u32* dst = (u32*)message->ioctl.buffer_in[0];
|
||
|
u32* cache_range = (u32*)(message->ioctl.buffer_in[0] & ~0xFF);
|
||
|
u32 value = message->ioctl.buffer_in[1];
|
||
|
u32 n = message->ioctl.buffer_in[2];
|
||
|
|
||
|
u32 old = *dst;
|
||
|
int i;
|
||
|
for(i = 0; i < n; i++)
|
||
|
{
|
||
|
if(*dst != old)
|
||
|
{
|
||
|
if(*dst == 0x0) old = *dst;
|
||
|
else
|
||
|
{
|
||
|
*dst = value;
|
||
|
svcFlushDCache(cache_range, 0x100);
|
||
|
break;
|
||
|
}
|
||
|
}else
|
||
|
{
|
||
|
svcInvalidateDCache(cache_range, 0x100);
|
||
|
usleep(50);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_KERN_READ32:
|
||
|
{
|
||
|
if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4))
|
||
|
{
|
||
|
res = IOS_ERROR_INVALID_SIZE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for(u32 i = 0; i < (message->ioctl.length_io/4); i++)
|
||
|
{
|
||
|
message->ioctl.buffer_io[i] = svcRead32(message->ioctl.buffer_in[0] + i * 4);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_KERN_WRITE32:
|
||
|
{
|
||
|
//! TODO: add syscall as on kern_read32
|
||
|
res = IOS_ERROR_NOEXISTS;
|
||
|
break;
|
||
|
}
|
||
|
//!--------------------------------------------------------------------------------------------------------------
|
||
|
//! FSA handles for better performance
|
||
|
//!--------------------------------------------------------------------------------------------------------------
|
||
|
//! TODO: add checks for i/o buffer length
|
||
|
case IOCTL_FSA_OPEN:
|
||
|
{
|
||
|
message->ioctl.buffer_io[0] = svcOpen("/dev/fsa", 0);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_CLOSE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
message->ioctl.buffer_io[0] = svcClose(fd);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_MOUNT:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
char *volume_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2];
|
||
|
u32 flags = message->ioctl.buffer_in[3];
|
||
|
char *arg_string = (message->ioctl.buffer_in[4] > 0) ? (((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[4]) : 0;
|
||
|
int arg_string_len = message->ioctl.buffer_in[5];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_Mount(fd, device_path, volume_path, flags, arg_string, arg_string_len);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_UNMOUNT:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
u32 flags = message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_Unmount(fd, device_path, flags);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_GETDEVICEINFO:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
int type = message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_GetDeviceInfo(fd, device_path, type, message->ioctl.buffer_io + 1);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_OPENDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_OpenDir(fd, path, (int*)message->ioctl.buffer_io + 1);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_READDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int handle = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_ReadDir(fd, handle, (directoryEntry_s*)(message->ioctl.buffer_io + 1));
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_CLOSEDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int handle = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_CloseDir(fd, handle);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_MAKEDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
u32 flags = message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_MakeDir(fd, path, flags);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_OPENFILE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
char *mode = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_OpenFile(fd, path, mode, (int*)message->ioctl.buffer_io + 1);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_READFILE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
u32 size = message->ioctl.buffer_in[1];
|
||
|
u32 cnt = message->ioctl.buffer_in[2];
|
||
|
int fileHandle = message->ioctl.buffer_in[3];
|
||
|
u32 flags = message->ioctl.buffer_in[4];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_ReadFile(fd, ((u8*)message->ioctl.buffer_io) + 0x40, size, cnt, fileHandle, flags);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_WRITEFILE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
u32 size = message->ioctl.buffer_in[1];
|
||
|
u32 cnt = message->ioctl.buffer_in[2];
|
||
|
int fileHandle = message->ioctl.buffer_in[3];
|
||
|
u32 flags = message->ioctl.buffer_in[4];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_WriteFile(fd, ((u8*)message->ioctl.buffer_in) + 0x40, size, cnt, fileHandle, flags);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_STATFILE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int fileHandle = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_StatFile(fd, fileHandle, (fileStat_s*)(message->ioctl.buffer_io + 1));
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_CLOSEFILE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int fileHandle = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_CloseFile(fd, fileHandle);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_SETFILEPOS:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int fileHandle = message->ioctl.buffer_in[1];
|
||
|
u32 position = message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_SetPosFile(fd, fileHandle, position);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_GETSTAT:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_GetStat(fd, path, (fileStat_s*)(message->ioctl.buffer_io + 1));
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_REMOVE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_Remove(fd, path);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_REWINDDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int dirFd = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_RewindDir(fd, dirFd);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_CHDIR:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_ChangeDir(fd, path);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_RAW_OPEN:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_RawOpen(fd, path, (int*)(message->ioctl.buffer_io + 1));
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_RAW_READ:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
u32 block_size = message->ioctl.buffer_in[1];
|
||
|
u32 cnt = message->ioctl.buffer_in[2];
|
||
|
u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4];
|
||
|
int deviceHandle = message->ioctl.buffer_in[5];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_RawRead(fd, ((u8*)message->ioctl.buffer_io) + 0x40, block_size, cnt, sector_offset, deviceHandle);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_RAW_WRITE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
u32 block_size = message->ioctl.buffer_in[1];
|
||
|
u32 cnt = message->ioctl.buffer_in[2];
|
||
|
u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4];
|
||
|
int deviceHandle = message->ioctl.buffer_in[5];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_RawWrite(fd, ((u8*)message->ioctl.buffer_in) + 0x40, block_size, cnt, sector_offset, deviceHandle);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_RAW_CLOSE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
int deviceHandle = message->ioctl.buffer_in[1];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_RawClose(fd, deviceHandle);
|
||
|
break;
|
||
|
}
|
||
|
case IOCTL_FSA_CHANGEMODE:
|
||
|
{
|
||
|
int fd = message->ioctl.buffer_in[0];
|
||
|
char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1];
|
||
|
int mode = message->ioctl.buffer_in[2];
|
||
|
|
||
|
message->ioctl.buffer_io[0] = FSA_ChangeMode(fd, path, mode);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
res = IOS_ERROR_INVALID_ARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
static int ipc_thread(void *arg)
|
||
|
{
|
||
|
int res;
|
||
|
ipcmessage *message;
|
||
|
u32 messageQueue[0x10];
|
||
|
|
||
|
int queueId = svcCreateMessageQueue(messageQueue, sizeof(messageQueue) / 4);
|
||
|
|
||
|
if(svcRegisterResourceManager("/dev/iosuhax", queueId) != 0)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
res = svcReceiveMessage(queueId, &message, 0);
|
||
|
if(res < 0)
|
||
|
{
|
||
|
usleep(10000);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch(message->command)
|
||
|
{
|
||
|
case IOS_OPEN:
|
||
|
{
|
||
|
log_printf("IOS_OPEN\n");
|
||
|
res = 0;
|
||
|
break;
|
||
|
}
|
||
|
case IOS_CLOSE:
|
||
|
{
|
||
|
log_printf("IOS_CLOSE\n");
|
||
|
res = 0;
|
||
|
break;
|
||
|
}
|
||
|
case IOS_IOCTL:
|
||
|
{
|
||
|
log_printf("IOS_IOCTL\n");
|
||
|
res = ipc_ioctl(message);
|
||
|
break;
|
||
|
}
|
||
|
case IOS_IOCTLV:
|
||
|
{
|
||
|
log_printf("IOS_IOCTLV\n");
|
||
|
res = 0;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
log_printf("unexpected command 0x%X\n", message->command);
|
||
|
res = IOS_ERROR_UNKNOWN_VALUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
svcResourceReply(message, res);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ipc_init(void)
|
||
|
{
|
||
|
int threadId = svcCreateThread(ipc_thread, 0, (u32*)(threadStack + sizeof(threadStack)), sizeof(threadStack), 0x78, 1);
|
||
|
if(threadId >= 0)
|
||
|
svcStartThread(threadId);
|
||
|
}
|