diff --git a/k11_extension/include/globals.h b/k11_extension/include/globals.h
index f197f0f..c8cb4f2 100644
--- a/k11_extension/include/globals.h
+++ b/k11_extension/include/globals.h
@@ -132,6 +132,7 @@ typedef struct CfwInfo
} CfwInfo;
extern CfwInfo cfwInfo;
+extern u32 kextBasePa;
extern vu32 rosalinaState;
extern bool hasStartedRosalinaNetworkFuncsOnce;
diff --git a/k11_extension/source/globals.c b/k11_extension/source/globals.c
index c6e2947..1d8f7fb 100644
--- a/k11_extension/source/globals.c
+++ b/k11_extension/source/globals.c
@@ -108,6 +108,7 @@ void (*mcuReboot)(void);
void (*coreBarrier)(void);
CfwInfo cfwInfo;
+u32 kextBasePa;
vu32 rosalinaState;
bool hasStartedRosalinaNetworkFuncsOnce;
diff --git a/k11_extension/source/main.c b/k11_extension/source/main.c
index 5fcaf0d..c069188 100644
--- a/k11_extension/source/main.c
+++ b/k11_extension/source/main.c
@@ -271,6 +271,7 @@ void main(FcramLayout *layout, KCoreContext *ctxs)
memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16);
exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20));
cfwInfo = p->cfwInfo;
+ kextBasePa = p->basePA;
memcpy(originalHandlers + 1, p->originalHandlers, 16);
void **arm11SvcTable = (void**)originalHandlers[2];
diff --git a/k11_extension/source/svc/GetSystemInfo.c b/k11_extension/source/svc/GetSystemInfo.c
index 5b1cf42..4a5f88f 100644
--- a/k11_extension/source/svc/GetSystemInfo.c
+++ b/k11_extension/source/svc/GetSystemInfo.c
@@ -79,7 +79,7 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
break;
case 0x300: // K11Ext size
- *out = (s64)(__end__ - __start__);
+ *out = (s64)(((u64)kextBasePa << 32) | (u64)(__end__ - __start__));
break;
default:
diff --git a/sysmodules/rosalina/include/menus.h b/sysmodules/rosalina/include/menus.h
index 1764420..88fede1 100644
--- a/sysmodules/rosalina/include/menus.h
+++ b/sysmodules/rosalina/include/menus.h
@@ -39,3 +39,6 @@ void RosalinaMenu_ProcessList(void);
void RosalinaMenu_PowerOff(void);
void RosalinaMenu_Reboot(void);
void RosalinaMenu_Cheats(void);
+
+bool rosalinaMenuShouldShowDebugInfo(void);
+void RosalinaMenu_ShowDebugInfo(void);
diff --git a/sysmodules/rosalina/include/utils.h b/sysmodules/rosalina/include/utils.h
index ae51b9e..8c1a6a1 100644
--- a/sysmodules/rosalina/include/utils.h
+++ b/sysmodules/rosalina/include/utils.h
@@ -62,3 +62,7 @@ static inline bool isServiceUsable(const char *name)
bool r;
return R_SUCCEEDED(srvIsServiceRegistered(&r, name)) && r;
}
+
+void formatMemoryPermission(char *outbuf, MemPerm perm);
+void formatUserMemoryState(char *outbuf, MemState state);
+u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle);
diff --git a/sysmodules/rosalina/source/gdb/remote_command.c b/sysmodules/rosalina/source/gdb/remote_command.c
index 9471f7c..11270d7 100644
--- a/sysmodules/rosalina/source/gdb/remote_command.c
+++ b/sysmodules/rosalina/source/gdb/remote_command.c
@@ -11,6 +11,8 @@
#include "fmt.h"
#include "gdb/breakpoints.h"
+#include "../utils.h"
+
struct
{
const char *name;
@@ -208,84 +210,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);
}
- 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)
- {
- 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);
}
diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c
index 57c4584..1103e3b 100644
--- a/sysmodules/rosalina/source/menus.c
+++ b/sysmodules/rosalina/source/menus.c
@@ -55,10 +55,44 @@ Menu rosalinaMenu = {
{ "Power off", METHOD, .method = &RosalinaMenu_PowerOff },
{ "Reboot", METHOD, .method = &RosalinaMenu_Reboot },
{ "Credits", METHOD, .method = &RosalinaMenu_ShowCredits },
+ { "Debug info", METHOD, .method = &RosalinaMenu_ShowDebugInfo, .visibility = &rosalinaMenuShouldShowDebugInfo },
{},
}
};
+bool rosalinaMenuShouldShowDebugInfo(void)
+{
+ return false;
+}
+
+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();
diff --git a/sysmodules/rosalina/source/utils.c b/sysmodules/rosalina/source/utils.c
new file mode 100644
index 0000000..9719896
--- /dev/null
+++ b/sysmodules/rosalina/source/utils.c
@@ -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 .
+*
+* 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
+#include
+
+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;
+}