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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(¤tMenu->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(¤tMenu->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(¤tMenu->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";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
{},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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, <);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
110
sysmodules/rosalina/source/utils.c
Normal file
110
sysmodules/rosalina/source/utils.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user