Merge remote-tracking branch 'origin/master'

* origin/master: (98 commits)
  rosalina: fix for latest libctru changes
  pm: fix critical bugs where 1.0(?) titles not in the list have scheduling mode misconfigured
  loader: revert to use the NS patch due to a Nintendo bug: https://www.3dbrew.org/wiki/NCCH/Extended_Header#Flag1
  loader: replace NS N3DS CPU patch with exheader override, fix overriding exheader with homebrew
  rosalina: ntp: use PTMSYSM_SetRtcTime
  revert the memory map to the old one (mostly)
  fix module loading
  kext: fix outer memory cacheability on newer versions
  so bascially rosalina's image...
  rosalina: add hidden debug info menu
  rosalina: refactor menu handling
  rosalina: rephrase brightness warning
  rosalina: add brightness control menu
  rosalina/pm: remove fs patch, use pm instead
  rosalina: cleanup variable names
  rosalina: reorder menus
  Fix latest commit
  rosalina menu: add scrolling, cpad and inputredir support (note: no ZL/ZR due to technical reasons)
  stuff
  newlib...
  ...

# Conflicts:
#	k11_extension/source/main.c
#	k11_extension/source/svc/UnmapProcessMemoryEx.c
#	sysmodules/rosalina/Makefile
#	sysmodules/rosalina/include/menu.h
#	sysmodules/rosalina/include/utils.h
#	sysmodules/rosalina/source/errdisp.c
#	sysmodules/rosalina/source/main.c
#	sysmodules/rosalina/source/menu.c
#	sysmodules/rosalina/source/menus.c
This commit is contained in:
Lorenzo Dellacà
2020-07-04 02:43:27 +02:00
266 changed files with 3161 additions and 1525 deletions

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,22 +32,22 @@
#include "memory.h"
#include "menu.h"
#include "utils.h"
#include "csvc.h"
u8 framebufferCache[FB_BOTTOM_SIZE];
#define KERNPA2VA(a) ((a) + (GET_VERSION_MINOR(osGetKernelVersion()) < 44 ? 0xD0000000 : 0xC0000000))
static u32 gpuSavedFramebufferAddr1, gpuSavedFramebufferAddr2, gpuSavedFramebufferFormat, gpuSavedFramebufferStride;
static u32 framebufferCacheSize;
static void *framebufferCache;
static RecursiveLock lock;
void Draw_Init(void)
{
RecursiveLock_Init(&lock);
}
void Draw_Lock(void)
{
static bool lockInitialized = false;
if(!lockInitialized)
{
RecursiveLock_Init(&lock);
lockInitialized = true;
}
RecursiveLock_Lock(&lock);
}
@@ -58,7 +58,7 @@ void Draw_Unlock(void)
void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character)
{
volatile u16 *const fb = (volatile u16 *const)FB_BOTTOM_VRAM_ADDR;
u16 *const fb = (u16 *)FB_BOTTOM_VRAM_ADDR;
s32 y;
for(y = 0; y < 10; y++)
@@ -129,34 +129,78 @@ void Draw_ClearFramebuffer(void)
Draw_FillFramebuffer(0);
}
void Draw_SetupFramebuffer(void)
u32 Draw_AllocateFramebufferCache(void)
{
// Try to see how much we can allocate...
// Can't use fbs in FCRAM when Home Menu is active (AXI config related maybe?)
u32 addr = 0x0D000000;
u32 tmp;
u32 minSize = (FB_BOTTOM_SIZE + 0xFFF) & ~0xFFF;
u32 maxSize = (FB_SCREENSHOT_SIZE + 0xFFF) & ~0xFFF;
u32 remaining = (u32)osGetMemRegionFree(MEMREGION_SYSTEM);
u32 size = remaining < maxSize ? remaining : maxSize;
if (size < minSize || R_FAILED(svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_ALLOC, MEMREGION_SYSTEM | MEMPERM_READ | MEMPERM_WRITE, true)))
{
framebufferCache = NULL;
framebufferCacheSize = 0;
}
else
{
framebufferCache = (u32 *)addr;
framebufferCacheSize = size;
}
return framebufferCacheSize;
}
void Draw_FreeFramebufferCache(void)
{
u32 tmp;
svcControlMemory(&tmp, (u32)framebufferCache, 0, framebufferCacheSize, MEMOP_FREE, 0);
framebufferCacheSize = 0;
framebufferCache = NULL;
}
void *Draw_GetFramebufferCache(void)
{
return framebufferCache;
}
u32 Draw_GetFramebufferCacheSize(void)
{
return framebufferCacheSize;
}
u32 Draw_SetupFramebuffer(void)
{
while((GPU_PSC0_CNT | GPU_PSC1_CNT | GPU_TRANSFER_CNT | GPU_CMDLIST_CNT) & 1);
svcFlushEntireDataCache();
Draw_FlushFramebuffer();
memcpy(framebufferCache, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE);
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
gpuSavedFramebufferAddr1 = GPU_FB_BOTTOM_ADDR_1;
gpuSavedFramebufferAddr2 = GPU_FB_BOTTOM_ADDR_2;
gpuSavedFramebufferFormat = GPU_FB_BOTTOM_FMT;
gpuSavedFramebufferStride = GPU_FB_BOTTOM_STRIDE;
GPU_FB_BOTTOM_ADDR_1 = GPU_FB_BOTTOM_ADDR_2 = FB_BOTTOM_VRAM_PA;
GPU_FB_BOTTOM_FMT = (GPU_FB_BOTTOM_FMT & ~7) | 2;
GPU_FB_BOTTOM_FMT = (GPU_FB_BOTTOM_FMT & ~7) | GSP_RGB565_OES;
GPU_FB_BOTTOM_STRIDE = 240 * 2;
Draw_FlushFramebuffer();
return framebufferCacheSize;
}
void Draw_RestoreFramebuffer(void)
{
memcpy(FB_BOTTOM_VRAM_ADDR, framebufferCache, FB_BOTTOM_SIZE);
Draw_FlushFramebuffer();
GPU_FB_BOTTOM_ADDR_1 = gpuSavedFramebufferAddr1;
GPU_FB_BOTTOM_ADDR_2 = gpuSavedFramebufferAddr2;
GPU_FB_BOTTOM_FMT = gpuSavedFramebufferFormat;
GPU_FB_BOTTOM_STRIDE = gpuSavedFramebufferStride;
Draw_FlushFramebuffer();
}
void Draw_FlushFramebuffer(void)
@@ -203,7 +247,7 @@ void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth)
Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4);
}
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormats srcFormat)
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormat srcFormat)
{
u8 red, green, blue;
switch(srcFormat)
@@ -267,16 +311,37 @@ static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_Frameb
}
}
void Draw_ConvertFrameBufferLine(u8 *line, bool top, bool left, u32 y)
typedef struct FrameBufferConvertArgs {
u8 *buf;
u8 startingLine;
u8 numLines;
bool top;
bool left;
} FrameBufferConvertArgs;
static void Draw_ConvertFrameBufferLinesKernel(const FrameBufferConvertArgs *args)
{
GSPGPU_FramebufferFormats fmt = top ? (GSPGPU_FramebufferFormats)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormats)(GPU_FB_BOTTOM_FMT & 7);
u32 width = top ? 400 : 320;
u8 formatSizes[] = { 4, 3, 2, 2, 2 };
u32 stride = top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE;
static const u8 formatSizes[] = { 4, 3, 2, 2, 2 };
u32 pa = Draw_GetCurrentFramebufferAddress(top, left);
u8 *addr = (u8 *)PA_PTR(pa);
GSPGPU_FramebufferFormat fmt = args->top ? (GSPGPU_FramebufferFormat)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormat)(GPU_FB_BOTTOM_FMT & 7);
u32 width = args->top ? 400 : 320;
u32 stride = args->top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE;
for(u32 x = 0; x < width; x++)
Draw_ConvertPixelToBGR8(line + x * 3 , addr + x * stride + y * formatSizes[(u8)fmt], fmt);
u32 pa = Draw_GetCurrentFramebufferAddress(args->top, args->left);
u8 *addr = (u8 *)KERNPA2VA(pa);
for (u32 y = args->startingLine; y < args->startingLine + args->numLines; y++)
{
for(u32 x = 0; x < width; x++)
{
__builtin_prefetch(addr + x * stride + y * formatSizes[fmt], 0, 3);
Draw_ConvertPixelToBGR8(args->buf + (x + width * y) * 3 , addr + x * stride + y * formatSizes[fmt], fmt);
}
}
}
void Draw_ConvertFrameBufferLines(u8 *buf, u32 startingLine, u32 numLines, bool top, bool left)
{
FrameBufferConvertArgs args = { buf, (u8)startingLine, (u8)numLines, top, left };
svcCustomBackdoor(Draw_ConvertFrameBufferLinesKernel, &args);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,19 @@
#include "fmt.h"
#include "ifile.h"
extern Handle preTerminationEvent;
static MyThread errDispThread;
static u8 ALIGN(8) errDispThreadStack[0xD00];
static char userString[0x100 + 1] = {0};
static char staticBuf[0x100 + 1] = {0};
MyThread *errDispCreateThread(void)
{
if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, 0xD00, 55, CORE_SYSTEM)))
svcBreak(USERBREAK_PANIC);
return &errDispThread;
}
static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name, u32 value)
{
@@ -44,6 +56,11 @@ static inline int ERRF_FormatRegisterValue(char *out, const char *name, u32 valu
return sprintf(out, "%-9s %08lx", name, value);
}
static inline void ERRF_GetErrInfo(ERRF_FatalErrInfo* info, u32* in, u32 size)
{
memcpy(info, in, size);
}
static int ERRF_FormatError(char *out, ERRF_FatalErrInfo *info)
{
char *outStart = out;
@@ -148,7 +165,7 @@ static int ERRF_FormatError(char *out, ERRF_FatalErrInfo *info)
desc = "The System Memory has been damaged.";
break;
case ERRF_ERRTYPE_FAILURE:
info->data.failure_mesg[0x60] = 0; // make sure the last byte in the IPC buffer is NULL
info->data.failure_mesg[0x5F] = 0; // make sure the last byte in the IPC buffer is NULL
desc = info->data.failure_mesg;
break;
default:
@@ -219,18 +236,18 @@ static Result ERRF_SaveErrorToFile(ERRF_FatalErrInfo *info)
return res;
}
void ERRF_HandleCommands(void *ctx)
void ERRF_HandleCommands(void)
{
(void)ctx;
u32 *cmdbuf = getThreadCommandBuffer();
ERRF_FatalErrInfo info;
switch(cmdbuf[0] >> 16)
{
case 1: // Throw
{
ERRF_FatalErrInfo *info = (ERRF_FatalErrInfo *)(cmdbuf + 1);
ERRF_SaveErrorToFile(info);
if(info->type != ERRF_ERRTYPE_LOGGED || info->procId == 0)
ERRF_GetErrInfo(&info, (cmdbuf + 1), sizeof(ERRF_FatalErrInfo));
ERRF_SaveErrorToFile(&info);
if(!menuShouldExit && (info.type != ERRF_ERRTYPE_LOGGED || info.procId == 0))
{
menuEnter();
@@ -238,7 +255,7 @@ void ERRF_HandleCommands(void *ctx)
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
ERRF_DisplayError(info);
ERRF_DisplayError(&info);
/*
If we ever wanted to return:
@@ -252,26 +269,98 @@ void ERRF_HandleCommands(void *ctx)
__builtin_unreachable();
}
cmdbuf[0] = 0x10040;
cmdbuf[0] = IPC_MakeHeader(1, 1, 0);
cmdbuf[1] = 0;
break;
}
case 2: // SetUserString
{
if(cmdbuf[0] != 0x20042 || (cmdbuf[2] & 0x3C0F) != 2)
if(cmdbuf[0] != IPC_MakeHeader(2, 1, 2) || (cmdbuf[2] & 0x3C0F) != 2)
{
cmdbuf[0] = 0x40;
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
cmdbuf[1] = 0xD9001830;
}
else
{
cmdbuf[0] = 0x20040;
u32 sz = cmdbuf[1] <= 0x100 ? sz : 0x100;
u32 sz = cmdbuf[1] <= 0x100 ? cmdbuf[1] : 0x100;
memcpy(userString, cmdbuf + 3, sz);
userString[sz] = 0;
cmdbuf[0] = IPC_MakeHeader(2, 1, 0);
cmdbuf[1] = 0;
}
break;
}
}
}
void errDispThreadMain(void)
{
Handle handles[3];
Handle serverHandle, clientHandle, sessionHandle = 0;
u32 replyTarget = 0;
s32 index;
Result res;
u32 *cmdbuf = getThreadCommandBuffer();
u32 *sbuf = getThreadStaticBuffers();
sbuf[0] = IPC_Desc_StaticBuffer(0x100, 0);
sbuf[1] = (u32)staticBuf;
assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "err:f", 1));
do
{
handles[0] = preTerminationEvent;
handles[1] = serverHandle;
handles[2] = sessionHandle;
if(replyTarget == 0) // k11
cmdbuf[0] = 0xFFFF0000;
res = svcReplyAndReceive(&index, handles, 1 + (sessionHandle == 0 ? 1 : 2), replyTarget);
if(R_FAILED(res))
{
if((u32)res == 0xC920181A) // session closed by remote
{
svcCloseHandle(sessionHandle);
sessionHandle = 0;
replyTarget = 0;
}
else
svcBreak(USERBREAK_PANIC);
}
else
{
if (index == 0)
{
break;
}
else if(index == 1)
{
Handle session;
assertSuccess(svcAcceptSession(&session, serverHandle));
if(sessionHandle == 0)
sessionHandle = session;
else
svcCloseHandle(session);
}
else
{
ERRF_HandleCommands();
replyTarget = sessionHandle;
}
}
}
while(!preTerminationRequested);
svcCloseHandle(sessionHandle);
svcCloseHandle(clientHandle);
svcCloseHandle(serverHandle);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -9,15 +9,15 @@
#include "gdb/net.h"
#include "gdb/debug.h"
extern Handle terminationRequestEvent;
extern bool terminationRequest;
extern Handle preTerminationEvent;
extern bool preTerminationRequested;
void GDB_RunMonitor(GDBServer *server)
{
Handle handles[3 + MAX_DEBUG];
Result r = 0;
handles[0] = terminationRequestEvent;
handles[0] = preTerminationEvent;
handles[1] = server->super.shall_terminate_event;
handles[2] = server->statusUpdated;
@@ -81,5 +81,5 @@ void GDB_RunMonitor(GDBServer *server)
RecursiveLock_Unlock(&ctx->lock);
}
}
while(!terminationRequest && server->super.running);
while(!preTerminationRequested && server->super.running);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -177,7 +177,7 @@ int GDB_ReceivePacket(GDBContext *ctx)
memcpy(backupbuf, ctx->buffer, ctx->latestSentPacketSize);
memset(ctx->buffer, 0, sizeof(ctx->buffer));
int r = soc_recv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK);
int r = socRecv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK);
if(r < 1)
return -1;
if(ctx->buffer[0] == '+') // GDB sometimes acknowleges TCP acknowledgment packets (yes...). IDA does it properly
@@ -186,20 +186,20 @@ int GDB_ReceivePacket(GDBContext *ctx)
return -1;
// Consume it
r = soc_recv(ctx->super.sockfd, ctx->buffer, 1, 0);
r = socRecv(ctx->super.sockfd, ctx->buffer, 1, 0);
if(r != 1)
return -1;
ctx->buffer[0] = 0;
r = soc_recv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK);
r = socRecv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK);
if(r == -1)
goto packet_error;
}
else if(ctx->buffer[0] == '-')
{
soc_send(ctx->super.sockfd, backupbuf, ctx->latestSentPacketSize, 0);
socSend(ctx->super.sockfd, backupbuf, ctx->latestSentPacketSize, 0);
return 0;
}
int maxlen = r > (int)sizeof(ctx->buffer) ? (int)sizeof(ctx->buffer) : r;
@@ -215,7 +215,7 @@ int GDB_ReceivePacket(GDBContext *ctx)
else
{
u8 checksum;
r = soc_recv(ctx->super.sockfd, ctx->buffer, 3 + pos - ctx->buffer, 0);
r = socRecv(ctx->super.sockfd, ctx->buffer, 3 + pos - ctx->buffer, 0);
if(r != 3 + pos - ctx->buffer || GDB_DecodeHex(&checksum, pos + 1, 1) != 1)
goto packet_error;
else if(GDB_ComputeChecksum(ctx->buffer + 1, pos - ctx->buffer - 1) != checksum)
@@ -227,7 +227,7 @@ int GDB_ReceivePacket(GDBContext *ctx)
}
else if(ctx->buffer[0] == '\x03')
{
r = soc_recv(ctx->super.sockfd, ctx->buffer, 1, 0);
r = socRecv(ctx->super.sockfd, ctx->buffer, 1, 0);
if(r != 1)
goto packet_error;
@@ -236,7 +236,7 @@ int GDB_ReceivePacket(GDBContext *ctx)
if(!(ctx->flags & GDB_FLAG_NOACK))
{
int r2 = soc_send(ctx->super.sockfd, "+", 1, 0);
int r2 = socSend(ctx->super.sockfd, "+", 1, 0);
if(r2 != 1)
return -1;
}
@@ -252,7 +252,7 @@ int GDB_ReceivePacket(GDBContext *ctx)
packet_error:
if(!(ctx->flags & GDB_FLAG_NOACK))
{
r = soc_send(ctx->super.sockfd, "-", 1, 0);
r = socSend(ctx->super.sockfd, "-", 1, 0);
if(r != 1)
return -1;
else
@@ -264,7 +264,7 @@ packet_error:
static int GDB_DoSendPacket(GDBContext *ctx, u32 len)
{
int r = soc_send(ctx->super.sockfd, ctx->buffer, len, 0);
int r = socSend(ctx->super.sockfd, ctx->buffer, len, 0);
if(r > 0)
ctx->latestSentPacketSize = r;

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -12,6 +12,8 @@
#include "gdb/breakpoints.h"
#include "utils.h"
#include "../utils.h"
struct
{
const char *name;
@@ -359,81 +361,19 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig)
return GDB_SendHexPacket(ctx, outbuf, n);
}
static const char *FormatMemPerm(u32 perm)
{
if (perm == MEMPERM_DONTCARE)
return "???";
static char buf[4] = {0};
buf[0] = perm & MEMPERM_READ ? 'r' : '-';
buf[1] = perm & MEMPERM_WRITE ? 'w' : '-';
buf[2] = perm & MEMPERM_EXECUTE ? 'x' : '-';
return buf;
}
static const char *FormatMemState(u32 state)
{
if (state > 11)
return "Unknown";
static const char *states[12] =
{
"Free",
"Reserved",
"IO",
"Static",
"Code",
"Private",
"Shared",
"Continuous",
"Aliased",
"Alias",
"AliasCode",
"Locked"
};
return states[state];
}
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions)
{
u32 address = 0;
u32 posInBuffer = 0;
u32 maxPosInBuffer = GDB_BUF_LEN / 2 - 35; ///< 35 is the maximum length of a formatted region
Handle handle;
MemInfo memi;
PageInfo pagei;
char outbuf[GDB_BUF_LEN / 2 + 1];
if(R_FAILED(svcOpenProcess(&handle, ctx->pid)))
{
posInBuffer = sprintf(outbuf, "Invalid process (wtf?)\n");
goto end;
return GDB_SendHexPacket(ctx, outbuf, posInBuffer);
}
while (address < 0x40000000 ///< Limit to check for regions
&& posInBuffer < maxPosInBuffer
&& R_SUCCEEDED(svcQueryProcessMemory(&memi, &pagei, handle, address)))
{
// Update the address for next region
address = memi.base_addr + memi.size;
// If region isn't FREE then add it to the list
if (memi.state != MEMSTATE_FREE)
{
const char *perm = FormatMemPerm(memi.perm);
const char *state = FormatMemState(memi.state);
posInBuffer += sprintf(outbuf + posInBuffer, "%08lx - %08lx %s %s\n",
memi.base_addr, address, perm, state);
}
}
svcCloseHandle(handle);
end:
posInBuffer = formatMemoryMapOfProcess(outbuf, GDB_BUF_LEN / 2, handle);
return GDB_SendHexPacket(ctx, outbuf, posInBuffer);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -74,13 +74,14 @@ void GDB_DecrementServerReferenceCount(GDBServer *server)
void GDB_RunServer(GDBServer *server)
{
server_bind(&server->super, GDB_PORT_BASE);
server_bind(&server->super, GDB_PORT_BASE + 1);
server_bind(&server->super, GDB_PORT_BASE + 2);
Result res = server_bind(&server->super, GDB_PORT_BASE);
if(R_SUCCEEDED(res)) res = server_bind(&server->super, GDB_PORT_BASE + 1);
if(R_SUCCEEDED(res)) res = server_bind(&server->super, GDB_PORT_BASE + 2);
server_bind(&server->super, GDB_PORT_BASE + 3); // next application
if(R_SUCCEEDED(res)) res = server_bind(&server->super, GDB_PORT_BASE + 3); // next application
server_run(&server->super);
if(R_SUCCEEDED(res))
server_run(&server->super);
}
void GDB_LockAllContexts(GDBServer *server)
@@ -136,9 +137,9 @@ GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPo
{
ctx->flags |= GDB_FLAG_SELECTED;
ctx->localPort = port;
ctx->parent = server;
}
ctx->parent = server;
GDB_UnlockAllContexts(server);
return ctx;
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -85,38 +85,38 @@
typedef u32 gdbhio_time_t;
typedef int gdbhio_mode_t;
struct gdbhio_stat {
unsigned int st_dev; /* device */
unsigned int st_ino; /* inode */
gdbhio_mode_t st_mode; /* protection */
unsigned int st_nlink; /* number of hard links */
unsigned int st_uid; /* user ID of owner */
unsigned int st_gid; /* group ID of owner */
unsigned int st_rdev; /* device type (if inode device) */
u64 st_size; /* total size, in bytes */
u64 st_blksize; /* blocksize for filesystem I/O */
u64 st_blocks; /* number of blocks allocated */
gdbhio_time_t st_atime; /* time of last access */
gdbhio_time_t st_mtime; /* time of last modification */
gdbhio_time_t st_ctime; /* time of last change */
struct PACKED ALIGN(4) gdbhio_stat {
u32 gst_dev; /* device */
u32 gst_ino; /* inode */
gdbhio_mode_t gst_mode; /* protection */
u32 gst_nlink; /* number of hard links */
u32 gst_uid; /* user ID of owner */
u32 gst_gid; /* group ID of owner */
u32 gst_rdev; /* device type (if inode device) */
u64 gst_size; /* total size, in bytes */
u64 gst_blksize; /* blocksize for filesystem I/O */
u64 gst_blocks; /* number of blocks allocated */
gdbhio_time_t gst_atime; /* time of last access */
gdbhio_time_t gst_mtime; /* time of last modification */
gdbhio_time_t gst_ctime; /* time of last change */
};
static void GDB_TioMakeStructStat(struct gdbhio_stat *out, const struct gdbhio_stat *in)
{
memset(out, 0, sizeof(struct gdbhio_stat));
out->st_dev = __builtin_bswap32(in->st_dev);
out->st_ino = __builtin_bswap32(in->st_ino);
out->st_mode = __builtin_bswap32(in->st_dev);
out->st_nlink = __builtin_bswap32(in->st_nlink);
out->st_uid = __builtin_bswap32(in->st_uid);
out->st_gid = __builtin_bswap32(in->st_gid);
out->st_rdev = __builtin_bswap32(in->st_rdev);
out->st_size = __builtin_bswap64(in->st_size);
out->st_blksize = __builtin_bswap64(in->st_blksize);
out->st_blocks = __builtin_bswap64(in->st_blocks);
out->st_atime = __builtin_bswap32(in->st_atime);
out->st_mtime = __builtin_bswap32(in->st_mtime);
out->st_ctime = __builtin_bswap32(in->st_ctime);
out->gst_dev = __builtin_bswap32(in->gst_dev);
out->gst_ino = __builtin_bswap32(in->gst_ino);
out->gst_mode = __builtin_bswap32(in->gst_dev);
out->gst_nlink = __builtin_bswap32(in->gst_nlink);
out->gst_uid = __builtin_bswap32(in->gst_uid);
out->gst_gid = __builtin_bswap32(in->gst_gid);
out->gst_rdev = __builtin_bswap32(in->gst_rdev);
out->gst_size = __builtin_bswap64(in->gst_size);
out->gst_blksize = __builtin_bswap64(in->gst_blksize);
out->gst_blocks = __builtin_bswap64(in->gst_blocks);
out->gst_atime = __builtin_bswap32(in->gst_atime);
out->gst_mtime = __builtin_bswap32(in->gst_mtime);
out->gst_ctime = __builtin_bswap32(in->gst_ctime);
}
// Inspired from https://github.com/smealum/ctrulib/blob/master/libctru/source/sdmc_dev.c
@@ -408,8 +408,8 @@ GDB_DECLARE_TIO_HANDLER(Stat)
if (err == 0)
{
gdbSt.st_nlink = 1;
gdbSt.st_mode = GDBHIO_S_IFREG | GDBHIO_S_IRUSR | GDBHIO_S_IWUSR |
gdbSt.gst_nlink = 1;
gdbSt.gst_mode = GDBHIO_S_IFREG | GDBHIO_S_IRUSR | GDBHIO_S_IWUSR |
GDBHIO_S_IRGRP | GDBHIO_S_IWGRP | GDBHIO_S_IROTH | GDBHIO_S_IWOTH;
}
}
@@ -419,8 +419,8 @@ GDB_DECLARE_TIO_HANDLER(Stat)
if (err == 0)
{
FSDIR_Close(dirHandle);
gdbSt.st_nlink = 1;
gdbSt.st_mode = GDBHIO_S_IFDIR | GDBHIO_S_IRWXU | GDBHIO_S_IRWXG | GDBHIO_S_IRWXO;
gdbSt.gst_nlink = 1;
gdbSt.gst_mode = GDBHIO_S_IFDIR | GDBHIO_S_IRWXU | GDBHIO_S_IRWXG | GDBHIO_S_IRWXO;
}
}
@@ -524,4 +524,4 @@ GDB_DECLARE_VERBOSE_HANDLER(File)
}
return GDB_HandleUnsupported(ctx); // No handler found!
}
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -12,7 +12,7 @@
#include <errno.h>
/*
There are only 2 Watchpoint Register Pairs on MPCORE ARM11 CPUs,
There are only 2 Watchpoint Register Pairs on MPCORE Arm11 CPUs,
and only 2 Breakpoint Register Pairs with context ID capabilities (BRP4-5) as well.
We'll reserve and use all 4 of them

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,7 +36,8 @@
#include "gdb/server.h"
#include "pmdbgext.h"
#define MAP_BASE 0x10000000
#define SYSCOREVER (*(vu32 *)0x1FF80010)
#define APPMEMTYPE (*(vu32 *)0x1FF80030)
extern GDBContext *nextApplicationGdbCtx;
extern GDBServer gdbServer;
@@ -77,16 +78,13 @@ static const char serviceList[32][8] =
"y2r:u",
};
static const u64 dependencyList[] =
static const u64 dependencyListNativeFirm[] =
{
0x0004013000002402LL, //ac
0x0004013000001502LL, //am
0x0004013000003402LL, //boss
0x0004013000001602LL, //camera
0x0004013000001702LL, //cfg
0x0004013000001802LL, //codec
0x0004013000002702LL, //csnd
0x0004013000002802LL, //dlp
0x0004013000001A02LL, //dsp
0x0004013000001B02LL, //gpio
0x0004013000001C02LL, //gsp
@@ -95,23 +93,55 @@ static const u64 dependencyList[] =
0x0004013000001E02LL, //i2c
0x0004013000003302LL, //ir
0x0004013000001F02LL, //mcu
0x0004013000002002LL, //mic
0x0004013000002B02LL, //ndm
0x0004013000003502LL, //news
0x0004013000002C02LL, //nim
0x0004013000002D02LL, //nwm
0x0004013000002102LL, //pdn
0x0004013000003102LL, //ps
0x0004013000002202LL, //ptm
0x0004013000003702LL, //ro
0x0004013000002E02LL, //socket
0x0004013000002302LL, //spi
0x0004013000002F02LL, //ssl
// Not present on SAFE_FIRM:
0x0004013000003402LL, //boss
0x0004013000001602LL, //camera
0x0004013000002802LL, //dlp
0x0004013000002002LL, //mic
0x0004013000002B02LL, //ndm
0x0004013000003502LL, //news
0x0004013000003702LL, //ro
};
static const u64 dependencyListSafeFirm[] =
{
0x0004013000002403LL, //ac
0x0004013000001503LL, //am
0x0004013000001703LL, //cfg
0x0004013000001803LL, //codec
0x0004013000002703LL, //csnd
0x0004013000001A03LL, //dsp
0x0004013000001B03LL, //gpio
0x0004013000001C03LL, //gsp
0x0004013000001D03LL, //hid
0x0004013000002903LL, //http
0x0004013000001E03LL, //i2c
0x0004013000003303LL, //ir
0x0004013000001F03LL, //mcu
0x0004013000002C03LL, //nim
0x0004013000002D03LL, //nwm
0x0004013000002103LL, //pdn
0x0004013000003103LL, //ps
0x0004013000002203LL, //ptm
0x0004013000002E03LL, //socket
0x0004013000002303LL, //spi
0x0004013000002F03LL, //ssl
0x0004013000003203LL, //friends (wouldn't be launched otherwise)
};
static const u32 kernelCaps[] =
{
0xFC00022C, // Kernel release version: 8.0 (necessary for using the new linear mapping)
0xFC00022C, // Kernel release version 8.0 is necessary for using the new linear mapping. Modified below.
0xFF81FF50, // RW static mapping: 0x1FF50000
0xFF81FF58, // RW static mapping: 0x1FF58000
0xFF81FF70, // RW static mapping: 0x1FF70000
@@ -135,6 +165,31 @@ static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size)
return dest;
}
void HBLDR_RestartHbApplication(void *p)
{
(void)p;
// Don't crash if we fail
FS_ProgramInfo programInfo;
u32 pid;
u32 launchFlags;
Result res = PMDBG_GetCurrentAppInfo(&programInfo, &pid, &launchFlags);
if (R_FAILED(res)) return;
res = PMDBG_PrepareToChainloadHomebrew(programInfo.programId);
if (R_FAILED(res)) return;
res = PMAPP_TerminateCurrentApplication(3 * 1000 * 1000 *1000LL); // 3s, like what NS uses
if (R_FAILED(res)) return;
if (R_SUCCEEDED(res))
{
do
{
svcSleepThread(100 * 1000 * 1000LL);
res = PMAPP_LaunchTitle(&programInfo, PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING | launchFlags);
} while (res == (Result)0xC8A05BF0);
}
}
void HBLDR_HandleCommands(void *ctx)
{
(void)ctx;
@@ -181,8 +236,10 @@ void HBLDR_HandleCommands(void *ctx)
break;
}
// note: mappableFree doesn't do anything
u32 tmp = 0;
res = svcControlMemoryEx(&tmp, MAP_BASE, 0, totalSize, MEMOP_ALLOC | flags, MEMPERM_READ | MEMPERM_WRITE, true);
u32 *addr = mappableAlloc(totalSize);
res = svcControlMemoryEx(&tmp, (u32)addr, 0, totalSize, MEMOP_ALLOC | flags, MEMPERM_READ | MEMPERM_WRITE, true);
if (R_FAILED(res))
{
IFile_Close(&file);
@@ -190,12 +247,12 @@ void HBLDR_HandleCommands(void *ctx)
break;
}
Handle hCodeset = Ldr_CodesetFrom3dsx(name, (u32*)MAP_BASE, baseAddr, &file, tid);
Handle hCodeset = Ldr_CodesetFrom3dsx(name, addr, baseAddr, &file, tid);
IFile_Close(&file);
if (!hCodeset)
{
svcControlMemory(&tmp, MAP_BASE, 0, totalSize, MEMOP_FREE, 0);
svcControlMemory(&tmp, (u32)addr, 0, totalSize, MEMOP_FREE, 0);
error(cmdbuf, MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_LDR, RD_NOT_FOUND));
break;
}
@@ -252,28 +309,36 @@ void HBLDR_HandleCommands(void *ctx)
memcpy(exhi->sci.codeset_info.name, "3dsx_app", 8);
memcpy(&exhi->sci.codeset_info.stack_size, &stacksize, 4);
memset(&exhi->sci.dependencies, 0, sizeof(exhi->sci.dependencies));
memcpy(exhi->sci.dependencies, dependencyList, sizeof(dependencyList));
if (SYSCOREVER == 2)
memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
else if (SYSCOREVER == 3)
memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm));
ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps;
localcaps0->core_info.core_version = 2;
localcaps0->core_info.core_version = SYSCOREVER;
localcaps0->core_info.use_cpu_clockrate_804MHz = false;
localcaps0->core_info.enable_l2c = false;
localcaps0->core_info.n3ds_system_mode = SYSMODE_N3DS_PROD;
localcaps0->core_info.ideal_processor = 0;
localcaps0->core_info.affinity_mask = BIT(0);
localcaps0->core_info.o3ds_system_mode = SYSMODE_O3DS_PROD;
localcaps0->core_info.priority = 0x30;
u32 appmemtype = APPMEMTYPE;
localcaps0->core_info.o3ds_system_mode = appmemtype < 6 ? (SystemMode)appmemtype : SYSMODE_O3DS_PROD;
localcaps0->core_info.n3ds_system_mode = appmemtype >= 6 ? (SystemMode)(appmemtype - 6 + 1) : SYSMODE_N3DS_PROD;
memset(localcaps0->reslimits, 0, sizeof(localcaps0->reslimits));
localcaps0->reslimits[0] = 0x9E; // Stuff needed to run stuff on core1
// Set mode1 preemption mode for core1, max. 89% of CPU time (default 0, requires a APT_SetAppCpuTimeLimit call)
// See the big comment in sysmodules/pm/source/reslimit.c for technical details.
localcaps0->reslimits[0] = BIT(7) | 89;
localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything
//localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything
localcaps0->storage_info.no_romfs = true;
localcaps0->storage_info.use_extended_savedata_access = true; // Whatever
/* We have a patched SM, so whatever... */
// We have a patched SM, so whatever...
memset(localcaps0->service_access, 0, sizeof(localcaps0->service_access));
memcpy(localcaps0->service_access, serviceList, sizeof(serviceList));
@@ -283,9 +348,12 @@ void HBLDR_HandleCommands(void *ctx)
memset(kcaps0->descriptors, 0xFF, sizeof(kcaps0->descriptors));
memcpy(kcaps0->descriptors, kernelCaps, sizeof(kernelCaps));
u64 lastdep = sizeof(dependencyList)/8;
if (osGetFirmVersion() >= SYSTEM_VERSION(2,50,0)) // 9.6+ FIRM
// Set kernel release version to the current kernel version
kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16);
if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && SYSCOREVER == 2) // 9.6+ NFIRM
{
u64 lastdep = sizeof(dependencyListNativeFirm)/8;
exhi->sci.dependencies[lastdep++] = 0x0004013000004002ULL; // nfc
strncpy((char*)&localcaps0->service_access[0x20], "nfc:u", 8);
s64 dummy = 0;

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,9 +26,10 @@
#include <3ds.h>
#include <arpa/inet.h>
#include "utils.h" // for makeARMBranch
#include "utils.h" // for makeArmBranch
#include "minisoc.h"
#include "input_redirection.h"
#include "process_patches.h"
#include "menus.h"
#include "memory.h"
#include "sleep.h"
@@ -57,27 +58,51 @@ int inputRedirectionStartResult;
void inputRedirectionThreadMain(void)
{
Result res = 0;
inputRedirectionStartResult = 0;
res = miniSocInit();
if(R_FAILED(res))
{
// Socket services broken
inputRedirectionStartResult = res;
miniSocExit();
// Still signal the event
svcSignalEvent(inputRedirectionThreadStartedEvent);
return;
}
int sock = socSocket(AF_INET, SOCK_DGRAM, 0);
while(sock == -1)
u32 tries = 15;
while(sock == -1 && --tries > 0)
{
svcSleepThread(1000 * 0000 * 0000LL);
svcSleepThread(100 * 1000 * 1000LL);
sock = socSocket(AF_INET, SOCK_DGRAM, 0);
}
if (sock < -10000 || tries == 0) {
// Socket services broken
inputRedirectionStartResult = -1;
miniSocExit();
// Still signal the event
svcSignalEvent(inputRedirectionThreadStartedEvent);
return;
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(4950);
saddr.sin_addr.s_addr = gethostid();
saddr.sin_addr.s_addr = socGethostid();
res = socBind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));
if(res != 0)
{
socClose(sock);
miniSocExit();
inputRedirectionStartResult = res;
// Still signal the event
svcSignalEvent(inputRedirectionThreadStartedEvent);
return;
}
@@ -91,7 +116,7 @@ void inputRedirectionThreadMain(void)
char buf[20];
u32 oldSpecialButtons = 0, specialButtons = 0;
while(inputRedirectionEnabled && !terminationRequest)
while(inputRedirectionEnabled && !preTerminationRequested)
{
struct pollfd pfd;
pfd.fd = sock;
@@ -108,7 +133,7 @@ void inputRedirectionThreadMain(void)
int pollres = socPoll(&pfd, 1, 10);
if(pollres > 0 && (pfd.revents & POLLIN))
{
int n = soc_recvfrom(sock, buf, 20, 0, NULL, 0);
int n = socRecvfrom(sock, buf, 20, 0, NULL, 0);
if(n < 0)
break;
else if(n < 12)
@@ -134,21 +159,40 @@ void inputRedirectionThreadMain(void)
srvPublishToSubscriber(0x203, 0);
}
}
else if(pollres < -10000)
break;
}
inputRedirectionEnabled = false;
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
socSetsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger));
socClose(sock);
miniSocExit();
}
void hidCodePatchFunc(void);
void irCodePatchFunc(void);
Result InputRedirection_Disable(s64 timeout)
{
if(!inputRedirectionEnabled)
return 0;
Result res = InputRedirection_DoOrUndoPatches();
if(R_FAILED(res))
return res;
inputRedirectionEnabled = false;
res = MyThread_Join(&inputRedirectionThread, timeout);
svcCloseHandle(inputRedirectionThreadStartedEvent);
return res;
}
Result InputRedirection_DoOrUndoPatches(void)
{
s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize;
@@ -156,6 +200,8 @@ Result InputRedirection_DoOrUndoPatches(void)
Handle processHandle;
Result res = OpenProcessByName("hid", &processHandle);
static bool hidPatched = false;
static bool irPatched = false;
if(R_SUCCEEDED(res))
{
@@ -182,11 +228,12 @@ Result InputRedirection_DoOrUndoPatches(void)
static u32 *hidRegPatchOffsets[2];
static u32 *hidPatchJumpLoc;
if(inputRedirectionEnabled)
if(hidPatched)
{
memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode));
hidPatched = false;
}
else
{
@@ -227,6 +274,7 @@ Result InputRedirection_DoOrUndoPatches(void)
*off = *off2 = hidDataPhys;
memcpy(off3, &hidHook, sizeof(hidHook));
hidPatched = true;
}
}
@@ -235,7 +283,7 @@ Result InputRedirection_DoOrUndoPatches(void)
svcCloseHandle(processHandle);
res = OpenProcessByName("ir", &processHandle);
if(R_SUCCEEDED(res) && osGetKernelVersion() >= SYSTEM_VERSION(2, 44, 6))
if(R_SUCCEEDED(res) && GET_VERSION_MINOR(osGetKernelVersion()) >= 44)
{
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003);
@@ -273,7 +321,7 @@ Result InputRedirection_DoOrUndoPatches(void)
static u32 *irHookLoc, *irWaitSyncLoc, *irCppFlagLoc;
if(inputRedirectionEnabled)
if(irPatched)
{
memcpy(irHookLoc, &irOrigReadingCode, sizeof(irOrigReadingCode));
if(useOldSyncCode)
@@ -281,6 +329,8 @@ Result InputRedirection_DoOrUndoPatches(void)
else
memcpy(irWaitSyncLoc, &irOrigWaitSyncCode, sizeof(irOrigWaitSyncCode));
memcpy(irCppFlagLoc, &irOrigCppFlagCode, sizeof(irOrigCppFlagCode));
irPatched = false;
}
else
{
@@ -324,7 +374,7 @@ Result InputRedirection_DoOrUndoPatches(void)
return -6;
}
*(void **)(irCodePhys + 8) = decodeARMBranch(off + 4);
*(void **)(irCodePhys + 8) = decodeArmBranch(off + 4);
*(void **)(irCodePhys + 12) = (void*)irDataPhys;
irHookLoc = off;
@@ -340,6 +390,8 @@ Result InputRedirection_DoOrUndoPatches(void)
// This NOPs out a flag check in ir:user's CPP emulation
*irCppFlagLoc = 0xE3150000; // tst r5, #0
irPatched = true;
}
}

View File

@@ -1,5 +1,5 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016-2019 Aurora Wright, TuxSH
@ Copyright (C) 2016-2020 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,93 +33,53 @@
#include "3dsx.h"
#include "utils.h"
#include "MyThread.h"
#include "menus/process_patches.h"
#include "menus/miscellaneous.h"
#include "plgloader.h"
#include "menus/debugger.h"
#include "menus/screen_filters.h"
#include "menus/cheats.h"
#include "menus/sysconfig.h"
#include "input_redirection.h"
#include "minisoc.h"
#include "draw.h"
#include "task_runner.h"
static Result stealFsReg(void)
{
Result ret = 0;
ret = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, fsRegGetSessionHandle(), "fs:REG");
while(ret == 0x9401BFE)
{
svcSleepThread(500 * 1000LL);
ret = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, fsRegGetSessionHandle(), "fs:REG");
}
return ret;
}
static Result fsRegSetupPermissions(void)
{
u32 pid;
Result res;
FS_ProgramInfo info;
ExHeader_Arm11StorageInfo storageInfo = {
.fs_access_info = FSACCESS_NANDRO_RW | FSACCESS_NANDRW | FSACCESS_SDMC_RW,
};
info.programId = 0x0004013000006902LL; // Rosalina TID
info.mediaType = MEDIATYPE_NAND;
if(R_SUCCEEDED(res = svcGetProcessId(&pid, CUR_PROCESS_HANDLE)))
res = FSREG_Register(pid, 0xFFFF000000000000LL, &info, &storageInfo);
return res;
}
// this is called before main
bool isN3DS;
void __appInit()
{
Result res;
for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{
res = srvInit();
if(R_FAILED(res) && res != (Result)0xD88007FA)
svcBreak(USERBREAK_PANIC);
}
if (R_FAILED(stealFsReg()) || R_FAILED(fsRegSetupPermissions()) || R_FAILED(fsInit()))
svcBreak(USERBREAK_PANIC);
if (R_FAILED(pmDbgInit()))
svcBreak(USERBREAK_PANIC);
}
// this is called after main exits
void __appExit()
{
pmDbgExit();
fsExit();
svcCloseHandle(*fsRegGetSessionHandle());
srvExit();
}
Result __sync_init(void);
Result __sync_fini(void);
void __libc_init_array(void);
void __libc_fini_array(void);
void __ctru_exit()
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
// this is called after main exits
void __wrap_exit(int rc)
{
(void)rc;
// TODO: make pm terminate rosalina
__libc_fini_array();
__appExit();
__sync_fini();
// Kernel will take care of it all
/*
pmDbgExit();
fsExit();
svcCloseHandle(*fsRegGetSessionHandle());
srvExit();
__sync_fini();*/
svcExitProcess();
}
void initSystem()
// this is called before main
void initSystem(void)
{
s64 out;
Result res;
__sync_init();
mappableInit(0x10000000, 0x14000000);
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
svcGetSystemInfo(&out, 0x10000, 0x100);
@@ -131,50 +91,100 @@ void initSystem()
miscellaneousMenu.items[0].title = HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID ? "Switch the hb. title to the current app." :
"Switch the hb. title to hblauncher_loader";
ProcessPatchesMenu_PatchUnpatchFSDirectly();
__sync_init();
__appInit();
for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{
res = srvInit();
if(R_FAILED(res) && res != (Result)0xD88007FA)
svcBreak(USERBREAK_PANIC);
}
if (R_FAILED(pmAppInit()) || R_FAILED(pmDbgInit()))
svcBreak(USERBREAK_PANIC);
if (R_FAILED(fsInit()))
svcBreak(USERBREAK_PANIC);
// **** DO NOT init services that don't come from KIPs here ****
// Instead, init the service only where it's actually init (then deinit it).
__libc_init_array();
// ROSALINA HACKJOB BEGIN
// NORMAL APPS SHOULD NOT DO THIS, EVER
u32 *tls = (u32 *)getThreadLocalStorage();
memset(tls, 0, 0x80);
tls[0] = 0x21545624;
// ROSALINA HACKJOB END
// Rosalina specific:
u32 *tls = (u32 *)getThreadLocalStorage();
memset(tls, 0, 0x80);
tls[0] = 0x21545624;
// ROSALINA HACKJOB BEGIN
// NORMAL APPS SHOULD NOT DO THIS, EVER
srvSetBlockingPolicy(true); // GetServiceHandle nonblocking if service port is full
}
bool terminationRequest = false;
Handle terminationRequestEvent;
bool menuShouldExit = false;
bool preTerminationRequested = false;
Handle preTerminationEvent;
extern bool isHidInitialized;
static void handleTermNotification(u32 notificationId)
{
(void)notificationId;
}
static void handlePreTermNotification(u32 notificationId)
{
(void)notificationId;
// Might be subject to a race condition, but heh.
// Disable input redirection
InputRedirection_Disable(100 * 1000 * 1000LL);
// Ask the debugger to terminate in approx 2 * 100ms
debuggerDisable(100 * 1000 * 1000LL);
// Kill the ac session if needed
if(isConnectionForced)
{
acExit();
isConnectionForced = false;
SysConfigMenu_UpdateStatus(true);
}
Draw_Lock();
if (isHidInitialized)
hidExit();
// Termination request
terminationRequest = true;
svcSignalEvent(terminationRequestEvent);
menuShouldExit = true;
preTerminationRequested = true;
svcSignalEvent(preTerminationEvent);
Draw_Unlock();
}
static void handleNextApplicationDebuggedByForce(u32 notificationId)
{
int dummy;
(void)notificationId;
// Following call needs to be async because pm -> Loader depends on rosalina hb:ldr, handled in this very thread.
TaskRunner_RunTask(debuggerFetchAndSetNextApplicationDebugHandleTask, &dummy, 0);
TaskRunner_RunTask(debuggerFetchAndSetNextApplicationDebugHandleTask, NULL, 0);
}
static void handleRestartHbAppNotification(u32 notificationId)
{
(void)notificationId;
TaskRunner_RunTask(HBLDR_RestartHbApplication, NULL, 0);
}
static const ServiceManagerServiceEntry services[] = {
{ "err:f", 1, ERRF_HandleCommands, true },
{ "hb:ldr", 2, HBLDR_HandleCommands, true },
{ NULL },
};
static const ServiceManagerNotificationEntry notifications[] = {
{ 0x100 , handleTermNotification },
//{ 0x103 , handlePreTermNotification }, // Sleep mode entry <=== causes issues
{ 0x1000, handleNextApplicationDebuggedByForce },
{ 0x2000, handlePreTermNotification },
{ 0x3000, handleRestartHbAppNotification },
{ 0x000, NULL },
};
@@ -190,9 +200,12 @@ int main(void)
bufPtrs[2] = IPC_Desc_StaticBuffer(sizeof(ldrArgvBuf), 1);
bufPtrs[3] = (u32)ldrArgvBuf;
if(R_FAILED(svcCreateEvent(&terminationRequestEvent, RESET_STICKY)))
if(R_FAILED(svcCreateEvent(&preTerminationEvent, RESET_STICKY)))
svcBreak(USERBREAK_ASSERT);
Draw_Init();
Cheat_SeedRng(svcGetSystemTick());
MyThread *menuThread = menuCreateThread();
MyThread *taskRunnerThread = taskRunnerCreateThread();
MyThread *plgloaderThread = PluginLoader__CreateThread();

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,66 +37,85 @@
#include "menus/cheats.h"
#include "minisoc.h"
u32 waitInputWithTimeout(u32 msec)
bool isHidInitialized = false;
// libctru redefinition:
bool hidShouldUseIrrst(void)
{
bool pressedKey = false;
u32 key = 0;
u32 n = 0;
// ir:rst exposes only two sessions :(
return false;
}
//Wait for no keys to be pressed
while(HID_PAD && !terminationRequest && (msec == 0 || n < msec))
{
svcSleepThread(1 * 1000 * 1000LL);
n++;
}
static inline u32 convertHidKeys(u32 keys)
{
// Nothing to do yet
return keys;
}
if(terminationRequest || (msec != 0 && n >= msec))
return 0;
u32 waitInputWithTimeout(s32 msec)
{
s32 n = 0;
u32 keys;
do
{
//Wait for a key to be pressed
while(!HID_PAD && !terminationRequest && (msec == 0 || n < msec))
svcSleepThread(1 * 1000 * 1000LL);
Draw_Lock();
if (!isHidInitialized || menuShouldExit)
{
svcSleepThread(1 * 1000 * 1000LL);
n++;
keys = 0;
Draw_Unlock();
break;
}
n++;
if(terminationRequest || (msec != 0 && n >= msec))
return 0;
hidScanInput();
keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS);
Draw_Unlock();
} while (keys == 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec));
key = HID_PAD;
//Make sure it's pressed
for(u32 i = 0x26000; i > 0; i --)
{
if(key != HID_PAD) break;
if(i == 1) pressedKey = true;
}
}
while(!pressedKey);
return key;
return keys;
}
u32 waitInput(void)
{
return waitInputWithTimeout(0);
return waitInputWithTimeout(-1);
}
u32 waitComboWithTimeout(u32 msec)
static u32 scanHeldKeys(void)
{
u32 key = 0;
u32 n = 0;
u32 keys;
//Wait for no keys to be pressed
while(HID_PAD && !terminationRequest && (msec == 0 || n < msec))
Draw_Lock();
if (!isHidInitialized || menuShouldExit)
keys = 0;
else
{
hidScanInput();
keys = convertHidKeys(hidKeysHeld());
}
Draw_Unlock();
return keys;
}
u32 waitComboWithTimeout(s32 msec)
{
s32 n = 0;
u32 keys = 0;
u32 tempKeys = 0;
// Wait for nothing to be pressed
while (scanHeldKeys() != 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec))
{
svcSleepThread(1 * 1000 * 1000LL);
n++;
}
if(terminationRequest || (msec != 0 && n >= msec))
if (menuShouldExit || !isHidInitialized || !(msec < 0 || n < msec))
return 0;
do
@@ -104,32 +123,51 @@ u32 waitComboWithTimeout(u32 msec)
svcSleepThread(1 * 1000 * 1000LL);
n++;
u32 tempKey = HID_PAD;
tempKeys = scanHeldKeys();
for(u32 i = 0x26000; i > 0; i--)
for (u32 i = 0x10000; i > 0; i--)
{
if(tempKey != HID_PAD) break;
if(i == 1) key = tempKey;
if (tempKeys != scanHeldKeys()) break;
if (i == 1) keys = tempKeys;
}
}
while((!key || HID_PAD) && !terminationRequest && (msec == 0 || n < msec));
while((keys == 0 || scanHeldKeys() != 0) && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec));
if(terminationRequest || (msec != 0 && n >= msec))
return 0;
return key;
return keys;
}
u32 waitCombo(void)
{
return waitComboWithTimeout(0);
return waitComboWithTimeout(-1);
}
static MyThread menuThread;
static u8 ALIGN(8) menuThreadStack[0x3000];
static u8 ALIGN(8) menuThreadStack[0x1000];
static u8 batteryLevel = 255;
static u32 homeBtnPressed = 0;
static inline u32 menuAdvanceCursor(u32 pos, u32 numItems, s32 displ)
{
return (pos + numItems + displ) % numItems;
}
static inline bool menuItemIsHidden(const MenuItem *item)
{
return item->visibility != NULL && !item->visibility();
}
bool menuCheckN3ds(void)
{
return isN3DS;
}
u32 menuCountItems(const Menu *menu)
{
u32 n;
for (n = 0; menu->items[n].action_type != MENU_END; n++);
return n;
}
MyThread *menuCreateThread(void)
{
svcKernelSetState(0x10007, &homeBtnPressed);
@@ -138,31 +176,25 @@ MyThread *menuCreateThread(void)
return &menuThread;
}
extern bool isN3DS;
u32 menuCombo;
u32 DispWarningOnHome(void);
void menuThreadMain(void)
{
if(!isN3DS)
{
rosalinaMenu.nbItems--;
for(u32 i = 0; i <= rosalinaMenu.nbItems; i++)
rosalinaMenu.items[i] = rosalinaMenu.items[i+1];
}
else
if(isN3DS)
N3DSMenu_UpdateStatus();
bool isAcURegistered = false;
while (!isServiceUsable("ac:u") || !isServiceUsable("hid:USER"))
svcSleepThread(500 * 1000 * 1000LL);
while(!terminationRequest)
hidInit(); // assume this doesn't fail
isHidInitialized = true;
while(!preTerminationRequested)
{
if((HID_PAD & menuCombo) == menuCombo)
{
if (!isAcURegistered)
isAcURegistered = R_SUCCEEDED(srvIsServiceRegistered(&isAcURegistered, "ac:u"))
&& isAcURegistered;
if (menuShouldExit)
continue;
else
{
@@ -175,7 +207,10 @@ void menuThreadMain(void)
}
else
{
Cheat_ApplyCheats();
menuEnter();
if(isN3DS) N3DSMenu_UpdateStatus();
menuShow(&rosalinaMenu);
menuLeave();
}
// Check for home button on O3DS Mode3 with plugin loaded
@@ -194,27 +229,37 @@ void menuThreadMain(void)
static s32 menuRefCount = 0;
void menuEnter(void)
{
if(AtomicPostIncrement(&menuRefCount) == 0)
Draw_Lock();
if(!menuShouldExit && menuRefCount == 0)
{
menuRefCount++;
svcKernelSetState(0x10000, 1);
svcSleepThread(5 * 1000 * 100LL);
if (Draw_AllocateFramebufferCache() == 0)
{
// Oops
menuRefCount = 0;
svcKernelSetState(0x10000, 1);
svcSleepThread(5 * 1000 * 100LL);
}
Draw_SetupFramebuffer();
Draw_ClearFramebuffer();
}
Draw_Unlock();
}
void menuLeave(void)
{
svcSleepThread(50 * 1000 * 1000);
if(AtomicDecrement(&menuRefCount) == 0)
Draw_Lock();
if(--menuRefCount == 0)
{
Draw_Lock();
Draw_FlushFramebuffer();
Draw_RestoreFramebuffer();
Draw_Unlock();
Draw_FreeFramebufferCache();
svcKernelSetState(0x10000, 1);
}
Draw_Unlock();
}
static void menuDraw(Menu *menu, u32 selected)
@@ -249,19 +294,23 @@ static void menuDraw(Menu *menu, u32 selected)
sprintf(versionString, "v%lu.%lu.%lu", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version), GET_VERSION_REVISION(version));
Draw_DrawString(10, 10, COLOR_TITLE, menu->title);
u32 numItems = menuCountItems(menu);
u32 dispY = 0;
for(u32 i = 0; i < 15; i++)
for(u32 i = 0; i < numItems; i++)
{
if(i >= menu->nbItems)
break;
Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, menu->items[i].title);
Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, i == selected ? '>' : ' ');
if (menuItemIsHidden(&menu->items[i]))
continue;
Draw_DrawString(30, 30 + dispY, COLOR_WHITE, menu->items[i].title);
Draw_DrawCharacter(10, 30 + dispY, COLOR_TITLE, i == selected ? '>' : ' ');
dispY += SPACING_Y;
}
if(miniSocEnabled)
{
char ipBuffer[17];
u32 ip = gethostid();
u32 ip = socGethostid();
u8 *addr = (u8 *)&ip;
int n = sprintf(ipBuffer, "%hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]);
Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, ipBuffer);
@@ -290,17 +339,33 @@ void menuShow(Menu *root)
Menu *previousMenus[0x80];
u32 previousSelectedItems[0x80];
u32 numItems = menuCountItems(currentMenu);
if (menuItemIsHidden(&currentMenu->items[selectedItem]))
selectedItem = menuAdvanceCursor(selectedItem, numItems, 1);
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
hidSetRepeatParameters(0, 0);
menuDraw(currentMenu, selectedItem);
Draw_Unlock();
bool menuComboReleased = false;
do
{
u32 pressed = waitInputWithTimeout(1000);
numItems = menuCountItems(currentMenu);
if(pressed & BUTTON_A)
if(!menuComboReleased && (scanHeldKeys() & menuCombo) != menuCombo)
{
menuComboReleased = true;
Draw_Lock();
hidSetRepeatParameters(200, 100);
Draw_Unlock();
}
if(pressed & KEY_A)
{
Draw_Lock();
Draw_ClearFramebuffer();
@@ -319,6 +384,9 @@ void menuShow(Menu *root)
currentMenu = currentMenu->items[selectedItem].menu;
selectedItem = 0;
break;
default:
__builtin_trap(); // oops
break;
}
Draw_Lock();
@@ -326,7 +394,7 @@ void menuShow(Menu *root)
Draw_FlushFramebuffer();
Draw_Unlock();
}
else if(pressed & BUTTON_B)
else if(pressed & KEY_B)
{
Draw_Lock();
Draw_ClearFramebuffer();
@@ -341,22 +409,24 @@ void menuShow(Menu *root)
else
break;
}
else if(pressed & BUTTON_DOWN)
else if(pressed & KEY_DOWN)
{
if(++selectedItem >= currentMenu->nbItems)
selectedItem = 0;
selectedItem = menuAdvanceCursor(selectedItem, numItems, 1);
if (menuItemIsHidden(&currentMenu->items[selectedItem]))
selectedItem = menuAdvanceCursor(selectedItem, numItems, 1);
}
else if(pressed & BUTTON_UP)
else if(pressed & KEY_UP)
{
if(selectedItem-- <= 0)
selectedItem = currentMenu->nbItems - 1;
selectedItem = menuAdvanceCursor(selectedItem, numItems, -1);
if (menuItemIsHidden(&currentMenu->items[selectedItem]))
selectedItem = menuAdvanceCursor(selectedItem, numItems, -1);
}
Draw_Lock();
menuDraw(currentMenu, selectedItem);
Draw_Unlock();
}
while(!terminationRequest);
while(!menuShouldExit);
}
static const char *__press_b_to_close = "Press [B] to close";

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
#include "menu.h"
#include "draw.h"
#include "menus/process_list.h"
#include "menus/process_patches.h"
#include "menus/n3ds.h"
#include "menus/debugger.h"
#include "menus/miscellaneous.h"
@@ -40,19 +39,20 @@
#include "ifile.h"
#include "memory.h"
#include "fmt.h"
#include "process_patches.h"
Menu rosalinaMenu = {
"Rosalina menu",
.nbItems = 11,
{
{ "New 3DS menu...", MENU, .menu = &N3DSMenu },
{ "Take screenshot", METHOD, .method = &RosalinaMenu_TakeScreenshot },
{ "Change screen brightness", METHOD, .method = &RosalinaMenu_ChangeScreenBrightness },
{ "Cheats...", METHOD, .method = &RosalinaMenu_Cheats },
{ "", METHOD, .method = PluginLoader__MenuCallback},
{ "Process list", METHOD, .method = &RosalinaMenu_ProcessList },
{ "Take screenshot (slow!)", METHOD, .method = &RosalinaMenu_TakeScreenshot },
{ "Debugger options...", MENU, .menu = &debuggerMenu },
{ "System configuration...", MENU, .menu = &sysconfigMenu },
{ "Screen filters...", MENU, .menu = &screenFiltersMenu },
{ "New 3DS menu...", MENU, .menu = &N3DSMenu, .visibility = &menuCheckN3ds },
{ "Miscellaneous options...", MENU, .menu = &miscellaneousMenu },
{ "Power off", METHOD, .method = &RosalinaMenu_PowerOff },
{ "Reboot", METHOD, .method = &RosalinaMenu_Reboot },
@@ -60,6 +60,39 @@ Menu rosalinaMenu = {
}
};
bool rosalinaMenuShouldShowDebugInfo(void)
{
return true;
}
void RosalinaMenu_ShowDebugInfo(void)
{
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
char memoryMap[512];
formatMemoryMapOfProcess(memoryMap, 511, CUR_PROCESS_HANDLE);
s64 kextAddrSize;
svcGetSystemInfo(&kextAddrSize, 0x10000, 0x300);
u32 kextPa = (u32)((u64)kextAddrSize >> 32);
u32 kextSize = (u32)kextAddrSize;
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Debug info");
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, memoryMap);
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Kernel ext PA: %08lx - %08lx\n", kextPa, kextPa + kextSize);
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void RosalinaMenu_ShowCredits(void)
{
Draw_Lock();
@@ -72,7 +105,7 @@ void RosalinaMenu_ShowCredits(void)
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Luma3DS credits");
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2019 AuroraWright, TuxSH") + SPACING_Y;
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2020 AuroraWright, TuxSH") + SPACING_Y;
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3DSX loading code by fincs");
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Networking code & basic GDB functionality by Stary");
@@ -91,7 +124,7 @@ void RosalinaMenu_ShowCredits(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void RosalinaMenu_Reboot(void)
@@ -111,14 +144,118 @@ void RosalinaMenu_Reboot(void)
u32 pressed = waitInputWithTimeout(1000);
if(pressed & BUTTON_A)
if(pressed & KEY_A)
{
APT_HardwareResetAsync();
menuLeave();
} else if(pressed & BUTTON_B)
APT_HardwareResetAsync();
return;
} else if(pressed & KEY_B)
return;
}
while(!terminationRequest);
while(!menuShouldExit);
}
static u32 gspPatchAddrN3ds, gspPatchValuesN3ds[2];
static bool gspPatchDoneN3ds;
static Result RosalinaMenu_PatchN3dsGspForBrightness(u32 size)
{
u32 *off = (u32 *)0x00100000;
u32 *end = (u32 *)(0x00100000 + size);
for (; off < end && (off[0] != 0xE92D4030 || off[1] != 0xE1A04000 || off[2] != 0xE2805C01 || off[3] != 0xE5D0018C); off++);
if (off >= end) {
return -1;
}
gspPatchAddrN3ds = (u32)off;
gspPatchValuesN3ds[0] = off[26];
gspPatchValuesN3ds[1] = off[50];
// NOP brightness changing in GSP
off[26] = 0xE1A00000;
off[50] = 0xE1A00000;
return 0;
}
static Result RosalinaMenu_RevertN3dsGspPatch(u32 size)
{
(void)size;
u32 *off = (u32 *)gspPatchAddrN3ds;
off[26] = gspPatchValuesN3ds[0];
off[50] = gspPatchValuesN3ds[1];
return 0;
}
void RosalinaMenu_ChangeScreenBrightness(void)
{
Result patchResult = 0;
if (isN3DS && !gspPatchDoneN3ds)
{
patchResult = PatchProcessByName("gsp", RosalinaMenu_PatchN3dsGspForBrightness);
gspPatchDoneN3ds = R_SUCCEEDED(patchResult);
}
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
do
{
// Assume the current brightness for both screens are the same.
s32 brightness = (s32)(LCD_TOP_BRIGHTNESS & 0xFF);
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu");
u32 posY = 30;
posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current brightness (0..255): %3lu\n\n", brightness);
if (R_SUCCEEDED(patchResult))
{
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Up/Down for +-1, Right/Left for +-10.\n");
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Y to revert the GSP patch and exit.\n\n");
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n");
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * avoid using values far higher than the presets.\n");
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * normal brightness mngmt. is now broken on N3DS.\nYou'll need to press Y to revert");
}
else
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Failed to patch GSP (0x%08lx).", (u32)patchResult);
Draw_FlushFramebuffer();
Draw_Unlock();
u32 pressed = waitInputWithTimeout(1000);
if ((pressed & DIRECTIONAL_KEYS) && R_SUCCEEDED(patchResult))
{
if (pressed & KEY_UP)
brightness += 1;
else if (pressed & KEY_DOWN)
brightness -= 1;
else if (pressed & KEY_RIGHT)
brightness += 10;
else if (pressed & KEY_LEFT)
brightness -= 10;
brightness = brightness < 0 ? 0 : brightness;
brightness = brightness > 255 ? 255 : brightness;
LCD_TOP_BRIGHTNESS = (u32)brightness;
LCD_BOT_BRIGHTNESS = (u32)brightness;
}
else if ((pressed & KEY_Y) && gspPatchDoneN3ds)
{
patchResult = PatchProcessByName("gsp", RosalinaMenu_RevertN3dsGspPatch);
gspPatchDoneN3ds = !R_SUCCEEDED(patchResult);
return;
}
else if (pressed & KEY_B)
return;
}
while (!menuShouldExit);
}
void RosalinaMenu_PowerOff(void) // Soft shutdown.
@@ -138,25 +275,64 @@ void RosalinaMenu_PowerOff(void) // Soft shutdown.
u32 pressed = waitInputWithTimeout(1000);
if(pressed & BUTTON_A)
if(pressed & KEY_A)
{
menuLeave();
srvPublishToSubscriber(0x203, 0);
return;
}
else if(pressed & BUTTON_B)
else if(pressed & KEY_B)
return;
}
while(!terminationRequest);
while(!menuShouldExit);
}
extern u8 framebufferCache[FB_BOTTOM_SIZE];
void RosalinaMenu_TakeScreenshot(void)
{
#define TRY(expr) if(R_FAILED(res = (expr))) goto end;
static s64 timeSpentConvertingScreenshot = 0;
static s64 timeSpentWritingScreenshot = 0;
static Result RosalinaMenu_WriteScreenshot(IFile *file, bool top, bool left)
{
u64 total;
Result res = 0;
u32 dimX = top ? 400 : 320;
u32 lineSize = 3 * dimX;
u32 remaining = lineSize * 240;
u8 *framebufferCache = (u8 *)Draw_GetFramebufferCache();
u8 *framebufferCacheEnd = framebufferCache + Draw_GetFramebufferCacheSize();
u8 *buf = framebufferCache;
Draw_CreateBitmapHeader(framebufferCache, dimX, 240);
buf += 54;
u32 y = 0;
// Our buffer might be smaller than the size of the screenshot...
while (remaining != 0)
{
s64 t0 = svcGetSystemTick();
u32 available = (u32)(framebufferCacheEnd - buf);
u32 size = available < remaining ? available : remaining;
u32 nlines = size / lineSize;
Draw_ConvertFrameBufferLines(buf, y, nlines, top, left);
s64 t1 = svcGetSystemTick();
timeSpentConvertingScreenshot += t1 - t0;
TRY(IFile_Write(file, &total, framebufferCache, (y == 0 ? 54 : 0) + lineSize * nlines, 0)); // don't forget to write the header
timeSpentWritingScreenshot += svcGetSystemTick() - t1;
y += nlines;
remaining -= lineSize * nlines;
buf = framebufferCache;
}
end: return res;
}
void RosalinaMenu_TakeScreenshot(void)
{
IFile file;
Result res;
Result res = 0;
char filename[64];
@@ -165,6 +341,9 @@ void RosalinaMenu_TakeScreenshot(void)
s64 out;
bool isSdMode;
timeSpentConvertingScreenshot = 0;
timeSpentWritingScreenshot = 0;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
isSdMode = (bool)out;
@@ -228,49 +407,19 @@ void RosalinaMenu_TakeScreenshot(void)
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
Draw_CreateBitmapHeader(framebufferCache, 400, 240);
for(u32 y = 0; y < 120; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 54 + 3 * 400 * y, true, true, y);
TRY(IFile_Write(&file, &total, framebufferCache, 54 + 3 * 400 * 120, 0));
for(u32 y = 120; y < 240; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 3 * 400 * (y - 120), true, true, y);
TRY(IFile_Write(&file, &total, framebufferCache, 3 * 400 * 120, 0));
TRY(RosalinaMenu_WriteScreenshot(&file, true, true));
TRY(IFile_Close(&file));
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_bot.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
Draw_CreateBitmapHeader(framebufferCache, 320, 240);
for(u32 y = 0; y < 120; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 54 + 3 * 320 * y, false, true, y);
TRY(IFile_Write(&file, &total, framebufferCache, 54 + 3 * 320 * 120, 0));
for(u32 y = 120; y < 240; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 3 * 320 * (y - 120), false, true, y);
TRY(IFile_Write(&file, &total, framebufferCache, 3 * 320 * 120, 0));
TRY(RosalinaMenu_WriteScreenshot(&file, false, true));
TRY(IFile_Close(&file));
if((GPU_FB_TOP_FMT & 0x20) && (Draw_GetCurrentFramebufferAddress(true, true) != Draw_GetCurrentFramebufferAddress(true, false)))
{
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top_right.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
Draw_CreateBitmapHeader(framebufferCache, 400, 240);
for(u32 y = 0; y < 120; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 54 + 3 * 400 * y, true, false, y);
TRY(IFile_Write(&file, &total, framebufferCache, 54 + 3 * 400 * 120, 0));
for(u32 y = 120; y < 240; y++)
Draw_ConvertFrameBufferLine(framebufferCache + 3 * 400 * (y - 120), true, false, y);
TRY(IFile_Write(&file, &total, framebufferCache, 3 * 400 * 120, 0));
TRY(RosalinaMenu_WriteScreenshot(&file, true, false));
TRY(IFile_Close(&file));
}
@@ -278,8 +427,6 @@ end:
IFile_Close(&file);
svcFlushEntireDataCache();
Draw_SetupFramebuffer();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
do
@@ -289,12 +436,19 @@ end:
if(R_FAILED(res))
Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Operation failed (0x%08lx).", (u32)res);
else
Draw_DrawString(10, 30, COLOR_WHITE, "Operation succeeded.");
{
u32 t1 = (u32)(1000 * timeSpentConvertingScreenshot / SYSCLOCK_ARM11);
u32 t2 = (u32)(1000 * timeSpentWritingScreenshot / SYSCLOCK_ARM11);
u32 posY = 30;
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Operation succeeded.\n\n");
posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Time spent converting: %5lums\n", t1);
posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Time spent writing files: %5lums\n", t2);
}
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
#undef TRY
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,16 +33,11 @@
#include "utils.h"
#include "fmt.h"
#include "ifile.h"
#include "pmdbgext.h"
#define MAKE_QWORD(hi,low) \
((u64) ((((u64)(hi)) << 32) | (low)))
typedef struct CheatProcessInfo
{
u32 pid;
u64 titleId;
} CheatProcessInfo;
typedef struct CheatDescription
{
struct {
@@ -70,36 +65,6 @@ CheatDescription* cheats[1024] = { 0 };
u8 cheatBuffer[32768] = { 0 };
u8 cheatPage[0x1000] = { 0 };
static CheatProcessInfo cheatinfo[0x40] = { 0 };
static s32 Cheats_FetchProcessInfo(void)
{
u32 pidList[0x40];
s32 processAmount;
s64 sa, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize;
svcGetProcessList(&processAmount, pidList, 0x40);
for (s32 i = 0; i < processAmount; i++)
{
Handle processHandle;
Result res = svcOpenProcess(&processHandle, pidList[i]);
if (R_FAILED(res)) continue;
cheatinfo[i].pid = pidList[i];
svcGetProcessInfo((s64 *) &cheatinfo[i].titleId, processHandle, 0x10001);
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002);
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003);
svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004);
svcGetProcessInfo(&sa, processHandle, 0x10005);
svcCloseHandle(processHandle);
}
return processAmount;
}
typedef struct CheatState
{
u32 index;
@@ -131,6 +96,7 @@ typedef struct CheatState
CheatState cheat_state = { 0 };
u8 cheatCount = 0;
u64 cheatTitleInfo = -1ULL;
u64 cheatRngState = 0;
static inline u32* activeOffset()
{
@@ -149,6 +115,12 @@ static inline u32* activeStorage(CheatDescription* desc)
char failureReason[64];
static u32 Cheat_GetRandomNumber(void)
{
cheatRngState = 0x5D588B656C078965ULL * cheatRngState + 0x0000000000269EC3ULL;
return (u32)(cheatRngState >> 32);
}
static bool Cheat_IsValidAddress(const Handle processHandle, u32 address, u32 size)
{
MemInfo info;
@@ -168,7 +140,7 @@ static u8 ReadWriteBuffer8 = 0;
static bool Cheat_Write8(const Handle processHandle, u32 offset, u8 value)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 1 < 0x01E82000)
if (addr >= 0x01E81000 && addr < 0x01E82000)
{
cheatPage[addr - 0x01E81000] = value;
return true;
@@ -184,7 +156,7 @@ static bool Cheat_Write8(const Handle processHandle, u32 offset, u8 value)
static bool Cheat_Write16(const Handle processHandle, u32 offset, u16 value)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 2 < 0x01E82000)
if (addr >= 0x01E81000 && addr + 1 < 0x01E82000)
{
*(u16*)(cheatPage + addr - 0x01E81000) = value;
return true;
@@ -200,7 +172,7 @@ static bool Cheat_Write16(const Handle processHandle, u32 offset, u16 value)
static bool Cheat_Write32(const Handle processHandle, u32 offset, u32 value)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 4 < 0x01E82000)
if (addr >= 0x01E81000 && addr + 3 < 0x01E82000)
{
*(u32*)(cheatPage + addr - 0x01E81000) = value;
return true;
@@ -216,7 +188,7 @@ static bool Cheat_Write32(const Handle processHandle, u32 offset, u32 value)
static bool Cheat_Read8(const Handle processHandle, u32 offset, u8* retValue)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 1 < 0x01E82000)
if (addr >= 0x01E81000 && addr < 0x01E82000)
{
*retValue = cheatPage[addr - 0x01E81000];
return true;
@@ -233,7 +205,7 @@ static bool Cheat_Read8(const Handle processHandle, u32 offset, u8* retValue)
static bool Cheat_Read16(const Handle processHandle, u32 offset, u16* retValue)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 2 < 0x01E82000)
if (addr >= 0x01E81000 && addr + 1 < 0x01E82000)
{
*retValue = *(u16*)(cheatPage + addr - 0x01E81000);
return true;
@@ -250,7 +222,7 @@ static bool Cheat_Read16(const Handle processHandle, u32 offset, u16* retValue)
static bool Cheat_Read32(const Handle processHandle, u32 offset, u32* retValue)
{
u32 addr = *activeOffset() + offset;
if (addr >= 0x01E81000 && addr + 4 < 0x01E82000)
if (addr >= 0x01E81000 && addr + 3 < 0x01E82000)
{
*retValue = *(u32*)(cheatPage + addr - 0x01E81000);
return true;
@@ -1512,7 +1484,7 @@ static u32 Cheat_ApplyCheat(const Handle processHandle, CheatDescription* const
case 0xF:
{
u32 range = arg1 - (arg0 & 0xFFFFFF);
u32 number = rand() % range;
u32 number = Cheat_GetRandomNumber() % range;
*activeData() = (arg0 & 0xFFFFFF) + number;
}
break;
@@ -1886,33 +1858,24 @@ static void Cheat_LoadCheatsIntoMemory(u64 titleId)
memset(cheatPage, 0, 0x1000);
}
static u32 Cheat_GetCurrentPID(u64* titleId)
static u32 Cheat_GetCurrentProcessAndTitleId(u64* titleId)
{
s32 processAmount = Cheats_FetchProcessInfo();
s32 index = -1;
for (s32 i = 0; i < processAmount; i++)
{
if (((u32) (cheatinfo[i].titleId >> 32)) == 0x00040010 || ((u32) (cheatinfo[i].titleId >> 32) == 0x00040000))
{
index = i;
break;
}
}
if (index != -1)
{
*titleId = cheatinfo[index].titleId;
return cheatinfo[index].pid;
}
else
{
FS_ProgramInfo programInfo;
u32 pid;
u32 launchFlags;
Result res = PMDBG_GetCurrentAppInfo(&programInfo, &pid, &launchFlags);
if (R_FAILED(res)) {
*titleId = 0;
return 0xFFFFFFFF;
}
*titleId = programInfo.programId;
return pid;
}
void Cheat_SeedRng(u64 seed)
{
cheatRngState = seed;
}
void Cheat_ApplyCheats(void)
@@ -1923,7 +1886,7 @@ void Cheat_ApplyCheats(void)
}
u64 titleId = 0;
u32 pid = Cheat_GetCurrentPID(&titleId);
u32 pid = Cheat_GetCurrentProcessAndTitleId(&titleId);
if (!titleId)
{
@@ -1949,7 +1912,7 @@ void Cheat_ApplyCheats(void)
void RosalinaMenu_Cheats(void)
{
u64 titleId = 0;
u32 pid = Cheat_GetCurrentPID(&titleId);
u32 pid = Cheat_GetCurrentProcessAndTitleId(&titleId);
if (titleId != 0)
{
@@ -1981,7 +1944,7 @@ void RosalinaMenu_Cheats(void)
Draw_FlushFramebuffer();
Draw_Unlock();
} while (!(waitInput() & BUTTON_B) && !terminationRequest);
} while (!(waitInput() & KEY_B) && !menuShouldExit);
}
else
{
@@ -2019,18 +1982,18 @@ void RosalinaMenu_Cheats(void)
Draw_FlushFramebuffer();
Draw_Unlock();
if (terminationRequest) break;
if (menuShouldExit) break;
u32 pressed;
do
{
pressed = waitInputWithTimeout(50);
if (pressed != 0) break;
} while (pressed == 0 && !terminationRequest);
} while (pressed == 0 && !menuShouldExit);
if (pressed & BUTTON_B)
if (pressed & KEY_B)
break;
else if ((pressed & BUTTON_A) && R_SUCCEEDED(r))
else if ((pressed & KEY_A) && R_SUCCEEDED(r))
{
if (cheats[selected]->active)
{
@@ -2041,13 +2004,13 @@ void RosalinaMenu_Cheats(void)
r = Cheat_MapMemoryAndApplyCheat(pid, cheats[selected]);
}
}
else if (pressed & BUTTON_DOWN)
else if (pressed & KEY_DOWN)
selected++;
else if (pressed & BUTTON_UP)
else if (pressed & KEY_UP)
selected--;
else if (pressed & BUTTON_LEFT)
else if (pressed & KEY_LEFT)
selected -= CHEATS_PER_MENU_PAGE;
else if (pressed & BUTTON_RIGHT)
else if (pressed & KEY_RIGHT)
{
if (selected + CHEATS_PER_MENU_PAGE < cheatCount)
selected += CHEATS_PER_MENU_PAGE;
@@ -2062,7 +2025,7 @@ void RosalinaMenu_Cheats(void)
pagePrev = page;
page = selected / CHEATS_PER_MENU_PAGE;
} while (!terminationRequest);
} while (!menuShouldExit);
}
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,11 +38,11 @@
Menu debuggerMenu = {
"Debugger options menu",
.nbItems = 3,
{
{ "Enable debugger", METHOD, .method = &DebuggerMenu_EnableDebugger },
{ "Disable debugger", METHOD, .method = &DebuggerMenu_DisableDebugger },
{ "Force-debug next application at launch", METHOD, .method = &DebuggerMenu_DebugNextApplicationByForce },
{},
}
};
@@ -84,6 +84,30 @@ void debuggerFetchAndSetNextApplicationDebugHandleTask(void *argdata)
GDB_UnlockAllContexts(&gdbServer);
}
Result debuggerDisable(s64 timeout)
{
Result res = 0;
bool initialized = gdbServer.referenceCount != 0;
if(initialized)
{
svcSignalEvent(gdbServer.super.shall_terminate_event);
server_kill_connections(&gdbServer.super);
res = MyThread_Join(&debuggerDebugThread, timeout);
if(res == 0)
res = MyThread_Join(&debuggerSocketThread, timeout);
Handle dummy = 0;
PMDBG_RunQueuedProcess(&dummy);
svcCloseHandle(dummy);
PMDBG_DebugNextApplicationByForce(false);
nextApplicationGdbCtx = NULL;
svcKernelSetState(0x10000, 2);
}
return res;
}
void DebuggerMenu_EnableDebugger(void)
{
bool done = false, alreadyEnabled = gdbServer.super.running;
@@ -115,16 +139,18 @@ void DebuggerMenu_EnableDebugger(void)
if(!done)
{
res = GDB_InitializeServer(&gdbServer);
Handle handles[3] = { gdbServer.super.started_event, gdbServer.super.shall_terminate_event, preTerminationEvent };
s32 idx;
if(R_SUCCEEDED(res))
{
debuggerCreateSocketThread();
debuggerCreateDebugThread();
res = svcWaitSynchronization(gdbServer.super.started_event, 10 * 1000 * 1000 * 1000LL);
res = svcWaitSynchronizationN(&idx, handles, 3, false, 5 * 1000 * 1000 * 1000LL);
if(res == 0) res = gdbServer.super.init_result;
}
if(res != 0)
sprintf(buf, "Starting debugger... failed (0x%08lx).", (u32)res);
done = true;
}
if(res == 0)
@@ -136,33 +162,16 @@ void DebuggerMenu_EnableDebugger(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void DebuggerMenu_DisableDebugger(void)
{
bool initialized = gdbServer.referenceCount != 0;
Result res = 0;
Result res = initialized ? debuggerDisable(2 * 1000 * 1000 * 1000LL) : 0;
char buf[65];
if(initialized)
{
svcSignalEvent(gdbServer.super.shall_terminate_event);
server_kill_connections(&gdbServer.super);
//server_set_should_close_all(&gdbServer.super);
res = MyThread_Join(&debuggerDebugThread, 2 * 1000 * 1000 * 1000LL);
if(res == 0)
res = MyThread_Join(&debuggerSocketThread, 2 * 1000 * 1000 * 1000LL);
Handle dummy = 0;
PMDBG_RunQueuedProcess(&dummy);
svcCloseHandle(dummy);
PMDBG_DebugNextApplicationByForce(false);
nextApplicationGdbCtx = NULL;
svcKernelSetState(0x10000, 2);
}
if(res != 0)
sprintf(buf, "Failed to disable debugger (0x%08lx).", (u32)res);
@@ -174,7 +183,7 @@ void DebuggerMenu_DisableDebugger(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void DebuggerMenu_DebugNextApplicationByForce(void)
@@ -223,7 +232,7 @@ void DebuggerMenu_DebugNextApplicationByForce(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void debuggerSocketThreadMain(void)

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,36 +33,37 @@
#include "hbloader.h"
#include "plgloader.h"
#include "fmt.h"
#include "utils.h" // for makeARMBranch
#include "utils.h" // for makeArmBranch
#include "minisoc.h"
#include "ifile.h"
#include "pmdbgext.h"
Menu miscellaneousMenu = {
"Miscellaneous options menu",
.nbItems = 5,
{
{ "Switch the hb. title to the current app.", METHOD, .method = &MiscellaneousMenu_SwitchBoot3dsxTargetTitle },
{ "Change the menu combo", METHOD, .method = &MiscellaneousMenu_ChangeMenuCombo },
{ "Start InputRedirection", METHOD, .method = &MiscellaneousMenu_InputRedirection },
{ "Sync time and date via NTP", METHOD, .method = &MiscellaneousMenu_SyncTimeDate },
{ "Save settings", METHOD, .method = &MiscellaneousMenu_SaveSettings },
{},
}
};
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
{
Result res;
u64 titleId = 0;
char failureReason[64];
if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID)
{
FS_ProgramInfo progInfo;
u32 pid;
res = PMDBG_GetCurrentAppTitleIdAndPid(&titleId, &pid);
u32 launchFlags;
res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags);
if(R_SUCCEEDED(res))
{
HBLDR_3DSX_TID = titleId;
HBLDR_3DSX_TID = progInfo.programId;
miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader";
}
else
@@ -95,13 +96,25 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
static void MiscellaneousMenu_ConvertComboToString(char *out, u32 combo)
{
static const char *keys[] = { "A", "B", "Select", "Start", "Right", "Left", "Up", "Down", "R", "L", "X", "Y" };
for(s32 i = 11; i >= 0; i--)
static const char *keys[] = {
"A", "B", "Select", "Start", "Right", "Left", "Up", "Down", "R", "L", "X", "Y",
"?", "?",
"ZL", "ZR",
"?", "?", "?", "?",
"Touch",
"?", "?", "?",
"CStick Right", "CStick Left", "CStick Up", "CStick Down",
"CPad Right", "CPad Left", "CPad Up", "CPad Down",
};
char *outOrig = out;
out[0] = 0;
for(s32 i = 31; i >= 0; i--)
{
if(combo & (1 << i))
{
@@ -111,12 +124,13 @@ static void MiscellaneousMenu_ConvertComboToString(char *out, u32 combo)
}
}
out[-1] = 0;
if (out != outOrig)
out[-1] = 0;
}
void MiscellaneousMenu_ChangeMenuCombo(void)
{
char comboStrOrig[64], comboStr[64];
char comboStrOrig[128], comboStr[128];
u32 posY;
Draw_Lock();
@@ -132,9 +146,6 @@ void MiscellaneousMenu_ChangeMenuCombo(void)
posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "The current menu combo is: %s", comboStrOrig);
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Please enter the new combo:");
Draw_FlushFramebuffer();
Draw_Unlock();
menuCombo = waitCombo();
MiscellaneousMenu_ConvertComboToString(comboStr, menuCombo);
@@ -151,7 +162,7 @@ void MiscellaneousMenu_ChangeMenuCombo(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
Result SaveSettings(void)
@@ -228,12 +239,11 @@ void MiscellaneousMenu_SaveSettings(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void MiscellaneousMenu_InputRedirection(void)
{
static MyThread *inputRedirectionThread = NULL;
bool done = false;
Result res;
@@ -243,11 +253,7 @@ void MiscellaneousMenu_InputRedirection(void)
if(wasEnabled)
{
res = InputRedirection_DoOrUndoPatches();
inputRedirectionEnabled = false;
res = MyThread_Join(inputRedirectionThread, 5 * 1000 * 1000 * 1000LL);
svcCloseHandle(inputRedirectionThreadStartedEvent);
res = InputRedirection_Disable(5 * 1000 * 1000 * 1000LL);
if(res != 0)
sprintf(buf, "Failed to stop InputRedirection (0x%08lx).", (u32)res);
else
@@ -294,13 +300,18 @@ void MiscellaneousMenu_InputRedirection(void)
res = svcCreateEvent(&inputRedirectionThreadStartedEvent, RESET_STICKY);
if(R_SUCCEEDED(res))
{
inputRedirectionThread = inputRedirectionCreateThread();
inputRedirectionCreateThread();
res = svcWaitSynchronization(inputRedirectionThreadStartedEvent, 10 * 1000 * 1000 * 1000LL);
if(res == 0)
res = (Result)inputRedirectionStartResult;
if(res != 0)
{
svcCloseHandle(inputRedirectionThreadStartedEvent);
InputRedirection_DoOrUndoPatches();
inputRedirectionEnabled = false;
}
inputRedirectionStartResult = 0;
}
}
@@ -328,7 +339,7 @@ void MiscellaneousMenu_InputRedirection(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
}
void MiscellaneousMenu_SyncTimeDate(void)
@@ -342,12 +353,12 @@ void MiscellaneousMenu_SyncTimeDate(void)
bool isSocURegistered;
time_t t;
struct tm localt = {0};
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
cantStart = R_FAILED(res) || !isSocURegistered;
int utcOffset = 12;
int utcOffsetMinute = 0;
int absOffset;
do
{
@@ -356,20 +367,21 @@ void MiscellaneousMenu_SyncTimeDate(void)
absOffset = utcOffset - 12;
absOffset = absOffset < 0 ? -absOffset : absOffset;
posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Current UTC offset: %c%02d", utcOffset < 12 ? '-' : '+', absOffset);
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Use DPAD Left/Right to change offset.\nPress A when done.") + SPACING_Y;
posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Current UTC offset: %c%02d%02d", utcOffset < 12 ? '-' : '+', absOffset, utcOffsetMinute);
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Use DPAD Left/Right to change hour offset.\nUse DPAD Up/Down to change minute offset.\nPress A when done.") + SPACING_Y;
input = waitInput();
if(input & BUTTON_LEFT) utcOffset = (24 + utcOffset - 1) % 24; // ensure utcOffset >= 0
if(input & BUTTON_RIGHT) utcOffset = (utcOffset + 1) % 24;
if(input & KEY_LEFT) utcOffset = (24 + utcOffset - 1) % 24; // ensure utcOffset >= 0
if(input & KEY_RIGHT) utcOffset = (utcOffset + 1) % 24;
if(input & KEY_UP) utcOffsetMinute = (utcOffsetMinute + 1) % 60;
if(input & KEY_DOWN) utcOffsetMinute = (60 + utcOffsetMinute - 1) % 60;
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(input & (BUTTON_A | BUTTON_B)) && !terminationRequest);
while(!(input & (KEY_A | KEY_B)) && !menuShouldExit);
if (input & BUTTON_B)
if (input & KEY_B)
return;
utcOffset -= 12;
@@ -383,8 +395,8 @@ void MiscellaneousMenu_SyncTimeDate(void)
if(R_SUCCEEDED(res))
{
t += 3600 * utcOffset;
gmtime_r(&t, &localt);
res = ntpSetTimeDate(&localt);
t += 60 * utcOffsetMinute;
res = ntpSetTimeDate(t);
}
}
@@ -408,6 +420,6 @@ void MiscellaneousMenu_SyncTimeDate(void)
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(input & BUTTON_B) && !terminationRequest);
while(!(input & KEY_B) && !menuShouldExit);
}
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,10 +34,10 @@ static char clkRateBuf[128 + 1];
Menu N3DSMenu = {
"New 3DS menu",
.nbItems = 2,
{
{ "Enable L2 cache", METHOD, .method = &N3DSMenu_EnableDisableL2Cache },
{ clkRateBuf, METHOD, .method = &N3DSMenu_ChangeClockRate }
{ clkRateBuf, METHOD, .method = &N3DSMenu_ChangeClockRate },
{},
}
};

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#include <3ds.h>
#include "menus/process_list.h"
#include "process_patches.h"
#include "memory.h"
#include "csvc.h"
#include "draw.h"
@@ -104,7 +105,7 @@ static void ProcessListMenu_DumpMemory(const char *name, void *start, u32 size)
IFile file;
Result res;
char filename[64] = {0};
char filename[100] = {0};
FS_Archive archive;
FS_ArchiveID archiveId;
@@ -197,7 +198,7 @@ end:
Draw_FlushFramebuffer();
Draw_Unlock();
}
while(!(waitInput() & BUTTON_B) && !terminationRequest);
while(!(waitInput() & KEY_B) && !menuShouldExit);
#undef TRY
}
@@ -493,21 +494,21 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
u32 pressed = waitInputWithTimeout(1000);
if(pressed & BUTTON_A)
if(pressed & KEY_A)
editing = !editing;
else if(pressed & BUTTON_X)
else if(pressed & KEY_X)
{
if(checkMode(MENU_MODE_GOTO))
finishJumping();
else
gotoAddress = __builtin_bswap32(((u32)menus[MENU_MODE_NORMAL].buf) + menus[MENU_MODE_NORMAL].selected);
}
else if(pressed & BUTTON_Y)
else if(pressed & KEY_Y)
{
if(checkMode(MENU_MODE_SEARCH))
finishSearching();
}
else if(pressed & BUTTON_SELECT)
else if(pressed & KEY_SELECT)
{
clearMenu();
ProcessListMenu_DumpMemory(info->name, menus[MENU_MODE_NORMAL].buf, menus[MENU_MODE_NORMAL].max);
@@ -517,35 +518,35 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
if(editing)
{
// Edit the highlighted byte
if(pressed & BUTTON_LEFT)
if(pressed & KEY_LEFT)
selectedByteAdd0x10();
else if(pressed & BUTTON_RIGHT)
else if(pressed & KEY_RIGHT)
selectedByteSub0x10();
else if(pressed & BUTTON_UP)
else if(pressed & KEY_UP)
selectedByteIncrement();
else if(pressed & BUTTON_DOWN)
else if(pressed & KEY_DOWN)
selectedByteDecrement();
}
else
{
// Move the cursor
if(pressed & BUTTON_LEFT)
if(pressed & KEY_LEFT)
selectedMoveLeft();
else if(pressed & BUTTON_RIGHT)
else if(pressed & KEY_RIGHT)
selectedMoveRight();
else if(pressed & BUTTON_UP)
else if(pressed & KEY_UP)
selectedMoveUp();
else if(pressed & BUTTON_DOWN)
else if(pressed & KEY_DOWN)
selectedMoveDown();
else if(pressed & BUTTON_L1)
else if(pressed & KEY_L)
{
if(menuMode == MENU_MODE_NORMAL)
viewHeap();
else if(menuMode == MENU_MODE_SEARCH)
searchPatternReduce();
}
else if(pressed & BUTTON_R1)
else if(pressed & KEY_R)
{
if(menuMode == MENU_MODE_NORMAL)
viewCode();
@@ -554,7 +555,7 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
}
}
if(pressed & BUTTON_B) // go back to the list, or the simple viewer
if(pressed & KEY_B) // go back to the list, or the simple viewer
{
if(menuMode != MENU_MODE_NORMAL)
{
@@ -568,7 +569,7 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
if(menus[menuMode].selected >= menus[menuMode].max)
menus[menuMode].selected = menus[menuMode].max - 1;
}
while(!terminationRequest);
while(!menuShouldExit);
clearMenu();
}
@@ -666,7 +667,7 @@ void RosalinaMenu_ProcessList(void)
if(gdbServer.super.running)
{
char ipBuffer[17];
u32 ip = gethostid();
u32 ip = socGethostid();
u8 *addr = (u8 *)&ip;
int n = sprintf(ipBuffer, "%hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]);
Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, ipBuffer);
@@ -685,7 +686,7 @@ void RosalinaMenu_ProcessList(void)
Draw_FlushFramebuffer();
Draw_Unlock();
if(terminationRequest)
if(menuShouldExit)
break;
u32 pressed;
@@ -698,19 +699,19 @@ void RosalinaMenu_ProcessList(void)
if(memcmp(infos, infosPrev, sizeof(infos)) != 0)
break;
}
while(pressed == 0 && !terminationRequest);
while(pressed == 0 && !menuShouldExit);
if(pressed & BUTTON_B)
if(pressed & KEY_B)
break;
else if(pressed & BUTTON_A)
else if(pressed & KEY_A)
ProcessListMenu_HandleSelected(&infos[selected]);
else if(pressed & BUTTON_DOWN)
else if(pressed & KEY_DOWN)
selected++;
else if(pressed & BUTTON_UP)
else if(pressed & KEY_UP)
selected--;
else if(pressed & BUTTON_LEFT)
else if(pressed & KEY_LEFT)
selected -= PROCESSES_PER_MENU_PAGE;
else if(pressed & BUTTON_RIGHT)
else if(pressed & KEY_RIGHT)
{
if(selected + PROCESSES_PER_MENU_PAGE < processAmount)
selected += PROCESSES_PER_MENU_PAGE;
@@ -728,5 +729,5 @@ void RosalinaMenu_ProcessList(void)
pagePrev = page;
page = selected / PROCESSES_PER_MENU_PAGE;
}
while(!terminationRequest);
while(!menuShouldExit);
}

View File

@@ -55,42 +55,42 @@ typedef struct {
u8 z;
} Pixel;
static u16 g_c[0x600];
static Pixel g_px[0x400];
void applyColorSettings(color_setting_t* cs)
{
u16 c[0x600];
Pixel px[0x400];
u8 i = 0;
memset(c, 0, sizeof(c));
memset(px, 0, sizeof(px));
memset(g_c, 0, sizeof(g_c));
memset(g_px, 0, sizeof(g_px));
do {
px[i].r = i;
px[i].g = i;
px[i].b = i;
px[i].z = 0;
g_px[i].r = i;
g_px[i].g = i;
g_px[i].b = i;
g_px[i].z = 0;
} while(++i);
do {
*(c + i + 0x000) = px[i].r | (px[i].r << 8);
*(c + i + 0x100) = px[i].g | (px[i].g << 8);
*(c + i + 0x200) = px[i].b | (px[i].b << 8);
*(g_c + i + 0x000) = g_px[i].r | (g_px[i].r << 8);
*(g_c + i + 0x100) = g_px[i].g | (g_px[i].g << 8);
*(g_c + i + 0x200) = g_px[i].b | (g_px[i].b << 8);
} while(++i);
colorramp_fill(c + 0x000, c + 0x100, c + 0x200, 0x100, cs);
colorramp_fill(g_c + 0x000, g_c + 0x100, g_c + 0x200, 0x100, cs);
do {
px[i].r = *(c + i + 0x000) >> 8;
px[i].g = *(c + i + 0x100) >> 8;
px[i].b = *(c + i + 0x200) >> 8;
g_px[i].r = *(g_c + i + 0x000) >> 8;
g_px[i].g = *(g_c + i + 0x100) >> 8;
g_px[i].b = *(g_c + i + 0x200) >> 8;
} while(++i);
writeLut((u32*)px);
writeLut((u32*)g_px);
}
Menu screenFiltersMenu = {
"Screen filters menu",
.nbItems = 6,
{
{ "Disable", METHOD, .method = &screenFiltersSetDisabled },
{ "Reduce blue light (level 1)", METHOD, .method = &screenFiltersReduceBlueLevel1 },
@@ -98,6 +98,7 @@ Menu screenFiltersMenu = {
{ "Reduce blue light (level 3)", METHOD, .method = &screenFiltersReduceBlueLevel3 },
{ "Reduce blue light (level 4)", METHOD, .method = &screenFiltersReduceBlueLevel4 },
{ "Reduce blue light (level 5)", METHOD, .method = &screenFiltersReduceBlueLevel5 },
{},
}
};
@@ -143,10 +144,10 @@ void screenFiltersSetTemperature(int temperature)
memset(&cs, 0, sizeof(cs));
cs.temperature = temperature;
cs.gamma[0] = 1.0F;
/*cs.gamma[0] = 1.0F;
cs.gamma[1] = 1.0F;
cs.gamma[2] = 1.0F;
cs.brightness = 1.0F;
cs.brightness = 1.0F;*/
applyColorSettings(&cs);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,13 +34,17 @@
Menu sysconfigMenu = {
"System configuration menu",
.nbItems = 2,
{
{ "Toggle LEDs", METHOD, .method = &SysConfigMenu_ToggleLEDs },
{ "Toggle Wireless", METHOD, .method = &SysConfigMenu_ToggleWireless },
{ "Toggle Power Button", METHOD, .method=&SysConfigMenu_TogglePowerButton },
{ "Control Wireless connection", METHOD, .method = &SysConfigMenu_ControlWifi },
{},
}
};
bool isConnectionForced = false;
void SysConfigMenu_ToggleLEDs(void)
{
Draw_Lock();
@@ -62,7 +66,7 @@ void SysConfigMenu_ToggleLEDs(void)
u32 pressed = waitInputWithTimeout(1000);
if(pressed & BUTTON_A)
if(pressed & KEY_A)
{
mcuHwcInit();
u8 result;
@@ -71,10 +75,10 @@ void SysConfigMenu_ToggleLEDs(void)
MCUHWC_WriteRegister(0x28, &result, 1);
mcuHwcExit();
}
else if(pressed & BUTTON_B)
else if(pressed & KEY_B)
return;
}
while(!terminationRequest);
while(!menuShouldExit);
}
void SysConfigMenu_ToggleWireless(void)
@@ -135,14 +139,221 @@ void SysConfigMenu_ToggleWireless(void)
u32 pressed = waitInputWithTimeout(1000);
if(pressed & BUTTON_A && nwmRunning)
if(pressed & KEY_A && nwmRunning)
{
nwmExtInit();
NWMEXT_ControlWirelessEnabled(!wireless);
nwmExtExit();
}
else if(pressed & BUTTON_B)
else if(pressed & KEY_B)
return;
}
while(!terminationRequest);
while(!menuShouldExit);
}
void SysConfigMenu_UpdateStatus(bool control)
{
MenuItem *item = &sysconfigMenu.items[3];
if(control)
{
item->title = "Control Wireless connection";
item->method = &SysConfigMenu_ControlWifi;
}
else
{
item->title = "Disable forced wireless connection";
item->method = &SysConfigMenu_DisableForcedWifiConnection;
}
}
static bool SysConfigMenu_ForceWifiConnection(int slot)
{
char ssid[0x20 + 1] = {0};
isConnectionForced = false;
if(R_FAILED(acInit()))
return false;
acuConfig config = {0};
ACU_CreateDefaultConfig(&config);
ACU_SetNetworkArea(&config, 2);
ACU_SetAllowApType(&config, 1 << slot);
ACU_SetRequestEulaVersion(&config);
Handle connectEvent = 0;
svcCreateEvent(&connectEvent, RESET_ONESHOT);
bool forcedConnection = false;
if(R_SUCCEEDED(ACU_ConnectAsync(&config, connectEvent)))
{
if(R_SUCCEEDED(svcWaitSynchronization(connectEvent, -1)) && R_SUCCEEDED(ACU_GetSSID(ssid)))
forcedConnection = true;
}
svcCloseHandle(connectEvent);
if(forcedConnection)
{
isConnectionForced = true;
SysConfigMenu_UpdateStatus(false);
}
else
acExit();
char infoString[80] = {0};
u32 infoStringColor = forcedConnection ? COLOR_GREEN : COLOR_RED;
if(forcedConnection)
sprintf(infoString, "Succesfully forced a connection to: %s", ssid);
else
sprintf(infoString, "Failed to connect to slot %d", slot + 1);
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
Draw_DrawString(10, 30, infoStringColor, infoString);
Draw_DrawString(10, 40, COLOR_WHITE, "Press B to go back.");
Draw_FlushFramebuffer();
Draw_Unlock();
u32 pressed = waitInputWithTimeout(1000);
if(pressed & KEY_B)
break;
}
while(!menuShouldExit);
return forcedConnection;
}
void SysConfigMenu_TogglePowerButton(void)
{
u32 mcuIRQMask;
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
mcuHwcInit();
MCUHWC_ReadRegister(0x18, (u8*)&mcuIRQMask, 4);
mcuHwcExit();
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to toggle, press B to go back.");
Draw_DrawString(10, 50, COLOR_WHITE, "Current status:");
Draw_DrawString(100, 50, (((mcuIRQMask & 0x00000001) == 0x00000001) ? COLOR_RED : COLOR_GREEN), (((mcuIRQMask & 0x00000001) == 0x00000001) ? " DISABLED" : " ENABLED "));
Draw_FlushFramebuffer();
Draw_Unlock();
u32 pressed = waitInputWithTimeout(1000);
if(pressed & KEY_A)
{
mcuHwcInit();
MCUHWC_ReadRegister(0x18, (u8*)&mcuIRQMask, 4);
mcuIRQMask ^= 0x00000001;
MCUHWC_WriteRegister(0x18, (u8*)&mcuIRQMask, 4);
mcuHwcExit();
}
else if(pressed & KEY_B)
return;
}
while(!menuShouldExit);
}
void SysConfigMenu_ControlWifi(void)
{
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
int slot = 0;
char slotString[12] = {0};
sprintf(slotString, ">1< 2 3 ");
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to force a connection to slot:");
Draw_DrawString(10, 40, COLOR_WHITE, slotString);
Draw_DrawString(10, 60, COLOR_WHITE, "Press B to go back.");
Draw_FlushFramebuffer();
Draw_Unlock();
u32 pressed = waitInputWithTimeout(1000);
if(pressed & KEY_A)
{
if(SysConfigMenu_ForceWifiConnection(slot))
{
// Connection successfully forced, return from this menu to prevent ac handle refcount leakage.
break;
}
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
}
else if(pressed & KEY_LEFT)
{
slotString[slot * 4] = ' ';
slotString[(slot * 4) + 2] = ' ';
slot--;
if(slot == -1)
slot = 2;
slotString[slot * 4] = '>';
slotString[(slot * 4) + 2] = '<';
}
else if(pressed & KEY_RIGHT)
{
slotString[slot * 4] = ' ';
slotString[(slot * 4) + 2] = ' ';
slot++;
if(slot == 3)
slot = 0;
slotString[slot * 4] = '>';
slotString[(slot * 4) + 2] = '<';
}
else if(pressed & KEY_B)
return;
}
while(!menuShouldExit);
}
void SysConfigMenu_DisableForcedWifiConnection(void)
{
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_Unlock();
acExit();
SysConfigMenu_UpdateStatus(true);
do
{
Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
Draw_DrawString(10, 30, COLOR_WHITE, "Forced connection successfully disabled.\nNote: auto-connection may remain broken.");
u32 pressed = waitInputWithTimeout(1000);
if(pressed & KEY_B)
return;
}
while(!menuShouldExit);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -10,7 +10,17 @@
#include <3ds/ipc.h>
#include <3ds/os.h>
#include <3ds/synchronization.h>
#include "memory.h"
#include <3ds/result.h>
#include <string.h>
#include "csvc.h"
s32 miniSocRefCount = 0;
static u32 socContextAddr = 0x08000000;
static u32 socContextSize = 0x60000;
static Handle miniSocHandle;
static Handle miniSocMemHandle;
bool miniSocEnabled = false;
s32 _net_convert_error(s32 sock_retval);
@@ -25,7 +35,7 @@ static Result SOCU_Initialize(Handle memhandle, u32 memsize)
cmdbuf[4] = IPC_Desc_SharedHandles(1);
cmdbuf[5] = memhandle;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0)
return ret;
@@ -39,22 +49,14 @@ static Result SOCU_Shutdown(void)
cmdbuf[0] = IPC_MakeHeader(0x19,0,0); // 0x190000
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0)
return ret;
return cmdbuf[1];
}
static s32 miniSocRefCount = 0;
static u32 socContextAddr = 0x08000000;
static u32 socContextSize = 0x60000;
// SOCU_handle from ctrulib
// socMemhandle from ctrulib
bool miniSocEnabled = false;
Result miniSocInit()
Result miniSocInit(void)
{
if(AtomicPostIncrement(&miniSocRefCount))
return 0;
@@ -71,20 +73,20 @@ Result miniSocInit()
goto cleanup;
}
ret = srvGetServiceHandle(&SOCU_handle, "soc:U");
ret = srvGetServiceHandle(&miniSocHandle, "soc:U");
if(ret != 0) goto cleanup;
ret = svcControlMemory(&tmp, socContextAddr, 0, socContextSize, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
ret = svcControlMemoryEx(&tmp, socContextAddr, 0, socContextSize, MEMOP_ALLOC, MEMREGION_SYSTEM | MEMPERM_READ | MEMPERM_WRITE, true);
if(ret != 0) goto cleanup;
socContextAddr = tmp;
ret = svcCreateMemoryBlock(&socMemhandle, (u32)socContextAddr, socContextSize, 0, 3);
ret = svcCreateMemoryBlock(&miniSocMemHandle, (u32)socContextAddr, socContextSize, 0, 3);
if(ret != 0) goto cleanup;
ret = SOCU_Initialize(socMemhandle, socContextSize);
ret = SOCU_Initialize(miniSocMemHandle, socContextSize);
if(ret != 0) goto cleanup;
svcKernelSetState(0x10000, 2);
@@ -94,17 +96,17 @@ Result miniSocInit()
cleanup:
AtomicDecrement(&miniSocRefCount);
if(socMemhandle != 0)
if(miniSocMemHandle != 0)
{
svcCloseHandle(socMemhandle);
socMemhandle = 0;
svcCloseHandle(miniSocMemHandle);
miniSocMemHandle = 0;
}
if(SOCU_handle != 0)
if(miniSocHandle != 0)
{
SOCU_Shutdown();
svcCloseHandle(SOCU_handle);
SOCU_handle = 0;
svcCloseHandle(miniSocHandle);
miniSocHandle = 0;
}
if(tmp != 0)
@@ -113,21 +115,19 @@ cleanup:
return ret;
}
Result miniSocExit(void)
Result miniSocExitDirect(void)
{
if(AtomicDecrement(&miniSocRefCount))
return 0;
//if (miniSocRefCount != 0) __builtin_trap();
Result ret = 0;
u32 tmp;
svcCloseHandle(socMemhandle);
socMemhandle = 0;
svcCloseHandle(miniSocMemHandle);
miniSocMemHandle = 0;
ret = SOCU_Shutdown();
svcCloseHandle(SOCU_handle);
SOCU_handle = 0;
svcCloseHandle(miniSocHandle);
miniSocHandle = 0;
svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE);
if(ret == 0)
@@ -138,6 +138,14 @@ Result miniSocExit(void)
return ret;
}
Result miniSocExit(void)
{
if(!miniSocEnabled || AtomicDecrement(&miniSocRefCount))
return 0;
return miniSocExitDirect();
}
int socSocket(int domain, int type, int protocol)
{
int ret = 0;
@@ -163,11 +171,11 @@ int socSocket(int domain, int type, int protocol)
cmdbuf[3] = protocol;
cmdbuf[4] = IPC_Desc_CurProcessId();
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0)
{
//errno = SYNC_ERROR;
return ret;
return R_FAILED(ret) ? ret : -1;
}
ret = (int)cmdbuf[1];
@@ -213,7 +221,7 @@ int socBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
cmdbuf[5] = IPC_Desc_StaticBuffer(tmp_addrlen,0);
cmdbuf[6] = (u32)tmpaddr;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return ret;
@@ -241,7 +249,7 @@ int socListen(int sockfd, int max_connections)
cmdbuf[2] = (u32)max_connections;
cmdbuf[3] = IPC_Desc_CurProcessId();
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0)
{
//errno = SYNC_ERROR;
@@ -283,7 +291,7 @@ int socAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
staticbufs[0] = IPC_Desc_StaticBuffer(tmp_addrlen,0);
staticbufs[1] = (u32)tmpaddr;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
staticbufs[0] = saved_threadstorage[0];
staticbufs[1] = saved_threadstorage[1];
@@ -340,7 +348,7 @@ int socConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
cmdbuf[5] = IPC_Desc_StaticBuffer(tmp_addrlen,0);
cmdbuf[6] = (u32)tmpaddr;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) return -1;
ret = (int)cmdbuf[1];
@@ -383,13 +391,13 @@ int socPoll(struct pollfd *fds, nfds_t nfds, int timeout)
staticbufs[0] = IPC_Desc_StaticBuffer(size,0);
staticbufs[1] = (u32)fds;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
staticbufs[0] = saved_threadstorage[0];
staticbufs[1] = saved_threadstorage[1];
if(ret != 0) {
return ret;
return R_FAILED(ret) ? ret : -1;
}
ret = (int)cmdbuf[1];
@@ -408,7 +416,7 @@ int socClose(int sockfd)
cmdbuf[1] = (u32)sockfd;
cmdbuf[2] = IPC_Desc_CurProcessId();
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return ret;
@@ -440,7 +448,7 @@ int socSetsockopt(int sockfd, int level, int optname, const void *optval, sockle
cmdbuf[7] = IPC_Desc_StaticBuffer(optlen,9);
cmdbuf[8] = (u32)optval;
ret = svcSendSyncRequest(SOCU_handle);
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
return ret;
}
@@ -457,12 +465,262 @@ int socSetsockopt(int sockfd, int level, int optname, const void *optval, sockle
return ret;
}
ssize_t soc_recv(int sockfd, void *buf, size_t len, int flags)
long socGethostid(void)
{
return soc_recvfrom(sockfd, buf, len, flags, NULL, 0);
int ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x16,0,0); // 0x160000
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return -1;
}
ret = (int)cmdbuf[1];
if(ret == 0)
ret = cmdbuf[2];
return ret;
}
ssize_t soc_send(int sockfd, const void *buf, size_t len, int flags)
static ssize_t _socuipc_cmd7(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
return soc_sendto(sockfd, buf, len, flags, NULL, 0);
int ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
u32 tmp_addrlen = 0;
u8 tmpaddr[0x1c];
u32 saved_threadstorage[2];
memset(tmpaddr, 0, 0x1c);
if(src_addr)
tmp_addrlen = 0x1c;
cmdbuf[0] = IPC_MakeHeader(0x7,4,4); // 0x70104
cmdbuf[1] = (u32)sockfd;
cmdbuf[2] = (u32)len;
cmdbuf[3] = (u32)flags;
cmdbuf[4] = (u32)tmp_addrlen;
cmdbuf[5] = IPC_Desc_CurProcessId();
cmdbuf[7] = IPC_Desc_Buffer(len,IPC_BUFFER_W);
cmdbuf[8] = (u32)buf;
u32 * staticbufs = getThreadStaticBuffers();
saved_threadstorage[0] = staticbufs[0];
saved_threadstorage[1] = staticbufs[1];
staticbufs[0] = IPC_Desc_StaticBuffer(tmp_addrlen,0);
staticbufs[1] = (u32)tmpaddr;
ret = svcSendSyncRequest(miniSocHandle);
staticbufs[0] = saved_threadstorage[0];
staticbufs[1] = saved_threadstorage[1];
if(ret != 0) {
//errno = SYNC_ERROR;
return -1;
}
ret = (int)cmdbuf[1];
if(ret == 0)
ret = _net_convert_error(cmdbuf[2]);
if(ret < 0) {
//errno = -ret;
return -1;
}
if(src_addr != NULL) {
src_addr->sa_family = tmpaddr[1];
if(*addrlen > tmpaddr[0])
*addrlen = tmpaddr[0];
memcpy(src_addr->sa_data, &tmpaddr[2], *addrlen - 2);
}
return ret;
}
static ssize_t _socuipc_cmd8(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
int ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
u32 tmp_addrlen = 0;
u8 tmpaddr[0x1c];
u32 saved_threadstorage[4];
if(src_addr)
tmp_addrlen = 0x1c;
memset(tmpaddr, 0, 0x1c);
cmdbuf[0] = 0x00080102;
cmdbuf[1] = (u32)sockfd;
cmdbuf[2] = (u32)len;
cmdbuf[3] = (u32)flags;
cmdbuf[4] = (u32)tmp_addrlen;
cmdbuf[5] = 0x20;
saved_threadstorage[0] = cmdbuf[0x100>>2];
saved_threadstorage[1] = cmdbuf[0x104>>2];
saved_threadstorage[2] = cmdbuf[0x108>>2];
saved_threadstorage[3] = cmdbuf[0x10c>>2];
cmdbuf[0x100>>2] = (((u32)len)<<14) | 2;
cmdbuf[0x104>>2] = (u32)buf;
cmdbuf[0x108>>2] = (tmp_addrlen<<14) | 2;
cmdbuf[0x10c>>2] = (u32)tmpaddr;
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return ret;
}
cmdbuf[0x100>>2] = saved_threadstorage[0];
cmdbuf[0x104>>2] = saved_threadstorage[1];
cmdbuf[0x108>>2] = saved_threadstorage[2];
cmdbuf[0x10c>>2] = saved_threadstorage[3];
ret = (int)cmdbuf[1];
if(ret == 0)
ret = _net_convert_error(cmdbuf[2]);
if(ret < 0) {
//errno = -ret;
return -1;
}
if(src_addr != NULL) {
src_addr->sa_family = tmpaddr[1];
if(*addrlen > tmpaddr[0])
*addrlen = tmpaddr[0];
memcpy(src_addr->sa_data, &tmpaddr[2], *addrlen - 2);
}
return ret;
}
static ssize_t _socuipc_cmd9(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
int ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
u32 tmp_addrlen = 0;
u8 tmpaddr[0x1c];
memset(tmpaddr, 0, 0x1c);
if(dest_addr) {
if(dest_addr->sa_family == AF_INET)
tmp_addrlen = 8;
else
tmp_addrlen = 0x1c;
if(addrlen < tmp_addrlen) {
//errno = EINVAL;
return -1;
}
tmpaddr[0] = tmp_addrlen;
tmpaddr[1] = dest_addr->sa_family;
memcpy(&tmpaddr[2], &dest_addr->sa_data, tmp_addrlen-2);
}
cmdbuf[0] = IPC_MakeHeader(0x9,4,6); // 0x90106
cmdbuf[1] = (u32)sockfd;
cmdbuf[2] = (u32)len;
cmdbuf[3] = (u32)flags;
cmdbuf[4] = (u32)tmp_addrlen;
cmdbuf[5] = IPC_Desc_CurProcessId();
cmdbuf[7] = IPC_Desc_StaticBuffer(tmp_addrlen,1);
cmdbuf[8] = (u32)tmpaddr;
cmdbuf[9] = IPC_Desc_Buffer(len,IPC_BUFFER_R);
cmdbuf[10] = (u32)buf;
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return ret;
}
ret = (int)cmdbuf[1];
if(ret == 0)
ret = _net_convert_error(cmdbuf[2]);
if(ret < 0) {
//errno = -ret;
return -1;
}
return ret;
}
static ssize_t _socuipc_cmda(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
int ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
u32 tmp_addrlen = 0;
u8 tmpaddr[0x1c];
memset(tmpaddr, 0, 0x1c);
if(dest_addr) {
if(dest_addr->sa_family == AF_INET)
tmp_addrlen = 8;
else
tmp_addrlen = 0x1c;
if(addrlen < tmp_addrlen) {
//errno = EINVAL;
return -1;
}
tmpaddr[0] = tmp_addrlen;
tmpaddr[1] = dest_addr->sa_family;
memcpy(&tmpaddr[2], &dest_addr->sa_data, tmp_addrlen-2);
}
cmdbuf[0] = IPC_MakeHeader(0xA,4,6); // 0xA0106
cmdbuf[1] = (u32)sockfd;
cmdbuf[2] = (u32)len;
cmdbuf[3] = (u32)flags;
cmdbuf[4] = (u32)tmp_addrlen;
cmdbuf[5] = IPC_Desc_CurProcessId();
cmdbuf[7] = IPC_Desc_StaticBuffer(len,2);
cmdbuf[8] = (u32)buf;
cmdbuf[9] = IPC_Desc_StaticBuffer(tmp_addrlen,1);
cmdbuf[10] = (u32)tmpaddr;
ret = svcSendSyncRequest(miniSocHandle);
if(ret != 0) {
//errno = SYNC_ERROR;
return ret;
}
ret = (int)cmdbuf[1];
if(ret == 0)
ret = _net_convert_error(cmdbuf[2]);
if(ret < 0) {
//errno = -ret;
return -1;
}
return ret;
}
ssize_t socRecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
if(len < 0x2000)
return _socuipc_cmd8(sockfd, buf, len, flags, src_addr, addrlen);
return _socuipc_cmd7(sockfd, buf, len, flags, src_addr, addrlen);
}
ssize_t socSendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
if(len < 0x2000)
return _socuipc_cmda(sockfd, buf, len, flags, dest_addr, addrlen);
return _socuipc_cmd9(sockfd, buf, len, flags, dest_addr, addrlen);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,25 +30,15 @@
#include "utils.h"
#include "minisoc.h"
#define NUM2BCD(n) ((n<99) ? (((n/10)*0x10)|(n%10)) : 0x99)
#define NUM2BCD(n) ((n<99) ? (((n/10)*0x10)|(n%10)) : 0x99)
#define NTP_TIMESTAMP_DELTA 2208988800ull
#ifndef NTP_IP
#define NTP_IP 0xD8EF2300
#endif
#define MAKE_IPV4(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
typedef struct RtcTime {
// From 3dbrew
u8 seconds;
u8 minutes;
u8 hours;
u8 dayofweek;
u8 dayofmonth;
u8 month;
u8 year;
u8 leapcount;
} RtcTime;
#ifndef NTP_IP
#define NTP_IP MAKE_IPV4(51, 137, 137, 111) // time.windows.com
#endif
// From https://github.com/lettier/ntpclient/blob/master/source/c/main.c
@@ -82,17 +72,6 @@ typedef struct NtpPacket
} NtpPacket; // Total: 384 bits or 48 bytes.
void rtcToBcd(u8 *out, const RtcTime *in)
{
memcpy(out, in, 8);
for (u32 i = 0; i < 8; i++)
{
u8 units = out[i] % 10;
u8 tens = (out[i] - units) / 10;
out[i] = (tens << 4) | units;
}
}
Result ntpGetTimeStamp(time_t *outTimestamp)
{
Result res = 0;
@@ -102,6 +81,11 @@ Result ntpGetTimeStamp(time_t *outTimestamp)
return res;
int sock = socSocket(AF_INET, SOCK_DGRAM, 0);
if (sock < -10000) {
// Socket services broken
return sock;
}
struct sockaddr_in servAddr = {0}; // Server address data structure.
NtpPacket packet = {0};
@@ -113,7 +97,7 @@ Result ntpGetTimeStamp(time_t *outTimestamp)
// Copy the server's IP address to the server address structure.
servAddr.sin_addr.s_addr = htonl(NTP_IP); // 216.239.35.0 time1.google.com
servAddr.sin_addr.s_addr = htonl(NTP_IP);
// Convert the port number integer to network big-endian style and save it to the server address structure.
servAddr.sin_port = htons(123);
@@ -123,10 +107,10 @@ Result ntpGetTimeStamp(time_t *outTimestamp)
if(socConnect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) < 0)
goto cleanup;
if(soc_send(sock, &packet, sizeof(NtpPacket), 0) < 0)
if(socSend(sock, &packet, sizeof(NtpPacket), 0) < 0)
goto cleanup;
if(soc_recv(sock, &packet, sizeof(NtpPacket), 0) < 0)
if(socRecv(sock, &packet, sizeof(NtpPacket), 0) < 0)
goto cleanup;
res = 0;
@@ -155,45 +139,33 @@ cleanup:
return res;
}
Result ntpSetTimeDate(const struct tm *localt)
Result ntpSetTimeDate(time_t timestamp)
{
Result res = mcuHwcInit();
Result res = ptmSysmInit();
if (R_FAILED(res)) return res;
res = cfguInit();
if (R_FAILED(res)) goto cleanup;
if (R_FAILED(res))
{
ptmSysmExit();
return res;
}
// First, set the config RTC offset to 0
u8 rtcOff = 0;
u8 rtcOff2[8] = {0};
res = CFG_SetConfigInfoBlk4(1, 0x10000, &rtcOff);
if (R_FAILED(res)) goto cleanup;
res = CFG_SetConfigInfoBlk4(8, 0x30001, rtcOff2);
u8 rtcOff[8] = {0};
res = CFG_SetConfigInfoBlk4(8, 0x30001, rtcOff);
if (R_FAILED(res)) goto cleanup;
u8 yr = (u8)(localt->tm_year - 100);
// Update the RTC
u8 bcd[8];
RtcTime lt = {
.seconds = (u8)localt->tm_sec,
.minutes = (u8)localt->tm_min,
.hours = (u8)localt->tm_hour,
.dayofweek = (u8)localt->tm_wday,
.dayofmonth = (u8)localt->tm_mday,
.month = (u8)(localt->tm_mon + 1),
.year = yr,
.leapcount = 0,
};
rtcToBcd(bcd, &lt);
res = MCUHWC_WriteRegister(0x30, bcd, 7);
// 946684800 is the timestamp of 01/01/2000 00:00 relative to the Unix Epoch
s64 msY2k = (timestamp - 946684800) * 1000;
res = PTMSYSM_SetRtcTime(msY2k);
if (R_FAILED(res)) goto cleanup;
// Save the config changes
res = CFG_UpdateConfigSavegame();
cleanup:
mcuHwcExit();
ptmSysmExit();
cfguExit();
return res;
}

View File

@@ -1,5 +1,5 @@
// License for this file: ctrulib's license
// Copyright AuroraWright, TuxSH 2019
// Copyright AuroraWright, TuxSH 2019-2020
#include <string.h>
#include <3ds/types.h>
@@ -10,15 +10,16 @@
#include <3ds/services/pmdbg.h>
#include <3ds/ipc.h>
Result PMDBG_GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid)
Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags)
{
Result ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x100, 0, 0);
if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret;
memcpy(outTitleId, cmdbuf + 2, 8);
*outPid = cmdbuf[4];
memcpy(outProgramInfo, cmdbuf + 2, sizeof(FS_ProgramInfo));
*outPid = cmdbuf[6];
*outLaunchFlags = cmdbuf[7];
return cmdbuf[1];
}
@@ -47,3 +48,16 @@ Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInf
*outDebug = cmdbuf[3];
return (Result)cmdbuf[1];
}
Result PMDBG_PrepareToChainloadHomebrew(u64 titleId)
{
Result ret = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x103, 2, 0);
memcpy(&cmdbuf[1], &titleId, 8);
if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret;
return (Result)cmdbuf[1];
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,48 +25,11 @@
*/
#include <3ds.h>
#include <string.h>
#include "csvc.h"
#include "menus/process_patches.h"
#include "memory.h"
#include "draw.h"
#include "hbloader.h"
#include "fmt.h"
#include "process_patches.h"
#include "utils.h"
static Result ProcessPatchesMenu_DoPatchUnpatchFS(u32 textTotalRoundedSize)
{
static bool patched = false;
static u16 *off;
static u16 origData[2];
static const u16 pattern[2] = {
0x7401, // strb r1, [r0, #16]
0x2000, // movs r0, #0
};
if(patched)
{
memcpy(off, &origData, sizeof(origData));
patched = false;
}
else
{
off = (u16 *)memsearch((u8 *)0x00100000, &pattern, textTotalRoundedSize, sizeof(pattern));
if(off == NULL)
return -1;
for(; (*off & 0xFF00) != 0xB500; off++); // Find function start
memcpy(origData, off, 4);
off[0] = 0x2001; // mov r0, #1
off[1] = 0x4770; // bx lr
patched = true;
}
//processPatchesMenu.items[1].title = patched ? "Unpatch FS for the archive checks" : "Patch FS for the archive checks";
return 0;
}
Result OpenProcessByName(const char *name, Handle *h)
{
u32 pidList[0x40];
@@ -96,7 +59,7 @@ Result OpenProcessByName(const char *name, Handle *h)
return 0;
}
static u32 ProcessPatchesMenu_PatchUnpatchProcessByName(const char *name, Result (*func)(u32 size))
Result PatchProcessByName(const char *name, Result (*func)(u32 size))
{
Result res;
Handle processHandle;
@@ -113,8 +76,3 @@ static u32 ProcessPatchesMenu_PatchUnpatchProcessByName(const char *name, Result
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, textTotalRoundedSize);
return res;
}
void ProcessPatchesMenu_PatchUnpatchFSDirectly(void)
{
ProcessPatchesMenu_PatchUnpatchProcessByName("fs", &ProcessPatchesMenu_DoPatchUnpatchFS);
}

View File

@@ -19,7 +19,7 @@
*/
#include <stdint.h>
#include <math.h>
//#include <math.h>
#include "redshift/redshift.h"
@@ -282,8 +282,10 @@ interpolate_color(float a, const float *c1, const float *c2, float *c)
}
/* Helper macro used in the fill functions */
#define F(Y, C) pow((Y) * setting->brightness * \
white_point[C], 1.0/setting->gamma[C])
#define F(Y, C) ((Y) * white_point[C])
/*#define F(Y, C) pow((Y) * setting->brightness * \
white_point[C], 1.0/setting->gamma[C])*/
void
colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b,
@@ -324,4 +326,4 @@ colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b,
}
}
#undef F
#undef F

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS.
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
*/
@@ -16,8 +16,8 @@
#include "sock_util.h"
#include "sleep.h"
extern Handle terminationRequestEvent;
extern bool terminationRequest;
extern Handle preTerminationEvent;
extern bool preTerminationRequested;
// soc's poll function is odd, and doesn't like -1 as fd.
// so this compacts everything together
@@ -103,29 +103,36 @@ Result server_init(struct sock_server *serv)
return svcCreateEvent(&serv->shall_terminate_event, RESET_STICKY);
}
void server_bind(struct sock_server *serv, u16 port)
Result server_bind(struct sock_server *serv, u16 port)
{
int server_sockfd;
Handle handles[2] = { terminationRequestEvent, serv->shall_terminate_event };
Handle handles[2] = { preTerminationEvent, serv->shall_terminate_event };
s32 idx = -1;
server_sockfd = socSocket(AF_INET, SOCK_STREAM, 0);
int res;
while(server_sockfd == -1)
int res;
u32 tries = 15;
while(server_sockfd == -1 && --tries > 0)
{
if(svcWaitSynchronizationN(&idx, handles, 2, false, 100 * 1000 * 1000LL) == 0)
return;
return -1;
server_sockfd = socSocket(AF_INET, SOCK_STREAM, 0);
}
if (server_sockfd < -10000 || tries == 0) {
// Socket services broken
serv->init_result = -1;
svcSignalEvent(serv->shall_terminate_event);
return -1;
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = gethostid();
saddr.sin_addr.s_addr = socGethostid();
res = socBind(server_sockfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));
if(res == 0)
{
res = socListen(server_sockfd, 2);
@@ -145,11 +152,20 @@ void server_bind(struct sock_server *serv, u16 port)
serv->ctx_ptrs[idx] = new_ctx;
}
}
if (res != 0) {
// Socket services broken
serv->init_result = res;
svcSignalEvent(serv->shall_terminate_event);
return res;
}
return 0;
}
static bool server_should_exit(struct sock_server *serv)
{
return svcWaitSynchronization(serv->shall_terminate_event, 0) == 0 || svcWaitSynchronization(terminationRequestEvent, 0) == 0;
return svcWaitSynchronization(serv->shall_terminate_event, 0) == 0 || svcWaitSynchronization(preTerminationEvent, 0) == 0;
}
void server_run(struct sock_server *serv)
@@ -158,7 +174,7 @@ void server_run(struct sock_server *serv)
serv->running = true;
svcSignalEvent(serv->started_event);
while(serv->running && !terminationRequest)
while(serv->running && !preTerminationRequested)
{
if(server_should_exit(serv))
goto abort_connections;
@@ -181,7 +197,7 @@ void server_run(struct sock_server *serv)
int pollres = socPoll(fds, serv->nfds, 50);
if(server_should_exit(serv))
if(server_should_exit(serv) || pollres < -10000)
goto abort_connections;
for(nfds_t i = 0; pollres > 0 && i < serv->nfds; i++)
@@ -266,6 +282,7 @@ abort_connections:
server_kill_connections(serv);
serv->running = false;
svcClearEvent(serv->started_event);
svcSignalEvent(serv->shall_terminate_event);
}
void server_set_should_close_all(struct sock_server *serv)
@@ -294,7 +311,8 @@ void server_kill_connections(struct sock_server *serv)
socClose(fds[i].fd);
fds[i].fd = -1;
serv->ctx_ptrs[i]->should_close = true;
if(serv->ctx_ptrs[i] != NULL)
serv->ctx_ptrs[i]->should_close = true;
}
}

View File

@@ -7,10 +7,15 @@ TaskRunner g_taskRunner;
static MyThread taskRunnerThread;
static u8 ALIGN(8) taskRunnerThreadStack[0x1000];
static void taskRunnerNoOpFunction(void *args)
{
(void)args;
}
MyThread *taskRunnerCreateThread(void)
{
TaskRunner_Init();
MyThread_Create(&taskRunnerThread, TaskRunner_HandleTasks, taskRunnerThreadStack, THREAD_STACK_SIZE, 0x20, 1);
MyThread_Create(&taskRunnerThread, TaskRunner_HandleTasks, taskRunnerThreadStack, THREAD_STACK_SIZE, 58, 1);
return &taskRunnerThread;
}
@@ -30,9 +35,15 @@ void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsi
LightEvent_Signal(&g_taskRunner.parametersSetEvent);
}
void TaskRunner_Terminate(void)
{
g_taskRunner.shouldTerminate = true;
TaskRunner_RunTask(taskRunnerNoOpFunction, NULL, 0);
}
void TaskRunner_HandleTasks(void)
{
for (;;) {
while (!g_taskRunner.shouldTerminate) {
LightEvent_Signal(&g_taskRunner.readyEvent);
LightEvent_Wait(&g_taskRunner.parametersSetEvent);
g_taskRunner.task(g_taskRunner.argStorage);
@@ -42,4 +53,4 @@ void TaskRunner_HandleTasks(void)
void TaskRunner_WaitReady(void)
{
LightEvent_Wait(&g_taskRunner.readyEvent);
}
}

View File

@@ -0,0 +1,110 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "utils.h"
#include "csvc.h"
#include <string.h>
#include <stdio.h>
void formatMemoryPermission(char *outbuf, MemPerm perm)
{
if (perm == MEMPERM_DONTCARE)
{
strcpy(outbuf, "???");
return;
}
outbuf[0] = perm & MEMPERM_READ ? 'r' : '-';
outbuf[1] = perm & MEMPERM_WRITE ? 'w' : '-';
outbuf[2] = perm & MEMPERM_EXECUTE ? 'x' : '-';
outbuf[3] = '\0';
}
void formatUserMemoryState(char *outbuf, MemState state)
{
static const char *states[12] =
{
"Free",
"Reserved",
"IO",
"Static",
"Code",
"Private",
"Shared",
"Continuous",
"Aliased",
"Alias",
"AliasCode",
"Locked"
};
strcpy(outbuf, state > 11 ? "Unknown" : states[state]);
}
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle)
{
u32 maxLineSize = 35 + (handle == CUR_PROCESS_HANDLE ? 15 : 0);
u32 address = 0;
u32 posInBuffer = 0;
u32 maxPosInBuffer = bufLen - maxLineSize; // 35 is the maximum length of a formatted region
MemInfo memi;
PageInfo pagei;
char pabuf[32];
char permbuf[8];
char statebuf[16];
s64 TTBCR;
svcGetSystemInfo(&TTBCR, 0x10002, 0);
while (address < (1u << (32 - (u32)TTBCR)) // Limit to check for regions
&& posInBuffer < maxPosInBuffer
&& R_SUCCEEDED(svcQueryProcessMemory(&memi, &pagei, handle, address)))
{
// Update the address for next region
address = memi.base_addr + memi.size;
// If region isn't FREE then add it to the list
if (memi.state != MEMSTATE_FREE)
{
if (handle == CUR_PROCESS_HANDLE)
{
u32 pa = svcConvertVAToPA((void *)memi.base_addr, false);
sprintf(pabuf, " (PA %08lx)", pa);
}
else
pabuf[0] = '\0';
formatMemoryPermission(permbuf, memi.perm);
formatUserMemoryState(statebuf, memi.state);
posInBuffer += sprintf(outbuf + posInBuffer, "%08lx - %08lx%s %s %s\n",
memi.base_addr, address, pabuf, permbuf, statebuf);
}
}
svcCloseHandle(handle);
return posInBuffer;
}