diff --git a/sysmodules/loader/loader.rsf b/sysmodules/loader/loader.rsf
index 2d29c93..8ef52a7 100644
--- a/sysmodules/loader/loader.rsf
+++ b/sysmodules/loader/loader.rsf
@@ -25,7 +25,7 @@ AccessControlInfo:
DisableDebug : true
EnableForceDebug : false
- CanWriteSharedPage : false
+ CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : false
PermitMainFunctionArgument : false
diff --git a/sysmodules/rosalina/source/3dsx.c b/sysmodules/loader/source/3dsx.c
similarity index 100%
rename from sysmodules/rosalina/source/3dsx.c
rename to sysmodules/loader/source/3dsx.c
diff --git a/sysmodules/rosalina/include/3dsx.h b/sysmodules/loader/source/3dsx.h
similarity index 100%
rename from sysmodules/rosalina/include/3dsx.h
rename to sysmodules/loader/source/3dsx.h
diff --git a/sysmodules/loader/source/hbldr.c b/sysmodules/loader/source/hbldr.c
index db222c8..5529236 100644
--- a/sysmodules/loader/source/hbldr.c
+++ b/sysmodules/loader/source/hbldr.c
@@ -1,97 +1,352 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2016-2020, 2022 Aurora Wright, TuxSH, fincs
+*
+* 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 <3ds.h>
#include
+#include
+#include "util.h"
#include "hbldr.h"
+#include "3dsx.h"
-static u32 hbldrRefcount = 0;
-static Handle hbldrHandle = 0;
-
-Result hbldrInit(void)
+static const char serviceList[32][8] =
{
- Result res;
- if (AtomicPostIncrement(&hbldrRefcount)) return 0;
+ "APT:U",
+ "ac:u",
+ "am:net",
+ "boss:P",
+ "cam:u",
+ "cfg:nor",
+ "cfg:u",
+ "csnd:SND",
+ "dsp::DSP",
+ "fs:USER",
+ "gsp::Lcd",
+ "gsp::Gpu",
+ "hid:USER",
+ "http:C",
+ "ir:USER",
+ "ir:rst",
+ "ir:u",
+ "ldr:ro",
+ "mic:u",
+ "ndm:u",
+ "news:s",
+ "nim:s",
+ "ns:s",
+ "nwm::UDS",
+ "nwm::EXT",
+ "ptm:u",
+ "ptm:sysm",
+ "pxi:dev",
+ "qtm:u",
+ "soc:U",
+ "ssl:C",
+ "y2r:u",
+};
- for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) {
- res = svcConnectToPort(&hbldrHandle, "hb:ldr");
- if(R_FAILED(res) && res != (Result)0xD88007FA) {
- AtomicDecrement(&hbldrRefcount);
- return res;
+static const u64 dependencyListNativeFirm[] =
+{
+ 0x0004013000002402LL, //ac
+ 0x0004013000001502LL, //am
+ 0x0004013000001702LL, //cfg
+ 0x0004013000001802LL, //codec
+ 0x0004013000002702LL, //csnd
+ 0x0004013000001A02LL, //dsp
+ 0x0004013000001B02LL, //gpio
+ 0x0004013000001C02LL, //gsp
+ 0x0004013000001D02LL, //hid
+ 0x0004013000002902LL, //http
+ 0x0004013000001E02LL, //i2c
+ 0x0004013000003302LL, //ir
+ 0x0004013000001F02LL, //mcu
+ 0x0004013000002C02LL, //nim
+ 0x0004013000002D02LL, //nwm
+ 0x0004013000002102LL, //pdn
+ 0x0004013000003102LL, //ps
+ 0x0004013000002202LL, //ptm
+ 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 is necessary for using the new linear mapping. Modified below.
+ 0xFF81FF50, // RW static range mapping: 0x1FF50000 (DSP Shared Mem 1, start)
+ 0xFF81FF58, // RW static range mapping: 0x1FF58000 (DSP Shared Mem 1, end)
+ 0xFF81FF70, // RW static range mapping: 0x1FF70000 (DSP Shared Mem 2, start)
+ 0xFF81FF78, // RW static range mapping: 0x1FF78000 (DSP Shared Mem 2, end)
+ 0xFF91F000, // RO static range mapping: 0x1F000000 (VRAM, start)
+ 0xFF91F600, // RO static range mapping: 0x1F600000 (VRAM, end)
+ 0xFF002109, // Exflags: APPLICATION memtype + "Shared page writing" + "Allow debug" + "Access core2"
+ 0xFE000200, // Handle table size: 0x200
+
+ // In case kernel ext isn't loaded:
+ 0xFFE1EC40, // RW I/O page mapping: 0x1EC40000 (CONFIG11, for kernel takeover)
+ 0xF0FFFFFF, // SVC ACL 0 to 0x7F (even if some SVC numbers don't exist)...
+ 0xF1FFFFFF,
+ 0xF2FFFFFF,
+ 0xF3FFFFFF,
+ 0xF4FFFFFF,
+ 0xF5FFFFFF,
+ 0xF6FFFFFF,
+ 0xF7FFFFFF,
+};
+
+static u16 hbldrTarget[PATH_MAX+1];
+
+static inline void error(u32* cmdbuf, Result rc)
+{
+ cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
+ cmdbuf[1] = rc;
+}
+
+static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size)
+{
+ u32 i;
+ for (i = 0; i < size && src[i] != 0; i++)
+ dest[i] = src[i];
+ while (i < size)
+ dest[i++] = 0;
+
+ return dest;
+}
+
+void hbldrPatchExHeaderInfo(ExHeader_Info *exhi)
+{
+ u32 stacksize = 4096; // 3dsx/libctru don't require anymore than this
+ 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));
+
+ u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
+ if (coreVer == 2)
+ memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
+ else if (coreVer == 3)
+ memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm));
+
+ ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps;
+
+ localcaps0->core_info.core_version = coreVer;
+ localcaps0->core_info.use_cpu_clockrate_804MHz = false;
+ localcaps0->core_info.enable_l2c = false;
+ localcaps0->core_info.ideal_processor = 0;
+ localcaps0->core_info.affinity_mask = BIT(0);
+ localcaps0->core_info.priority = 0x30;
+
+ u32 appmemtype = OS_KernelConfig->app_memtype;
+ 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));
+
+ // 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.no_romfs = true;
+ localcaps0->storage_info.use_extended_savedata_access = true; // Whatever
+
+ // We have a patched SM, so whatever...
+ memset(localcaps0->service_access, 0, sizeof(localcaps0->service_access));
+ memcpy(localcaps0->service_access, serviceList, sizeof(serviceList));
+
+ localcaps0->reslimit_category = RESLIMIT_CATEGORY_APPLICATION;
+
+ ExHeader_Arm11KernelCapabilities* kcaps0 = &exhi->aci.kernel_caps;
+ memset(kcaps0->descriptors, 0xFF, sizeof(kcaps0->descriptors));
+ memcpy(kcaps0->descriptors, kernelCaps, sizeof(kernelCaps));
+
+ // Set kernel release version to the current kernel version
+ kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16);
+
+ if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && coreVer == 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;
+ bool isN3DS = svcGetSystemInfo(&dummy, 0x10001, 0) == 0;
+ if (isN3DS)
+ {
+ exhi->sci.dependencies[lastdep++] = 0x0004013020004102ULL; // mvd
+ strncpy((char*)&localcaps0->service_access[0x21], "mvd:STD", 8);
}
}
-
- return 0;
}
-void hbldrExit(void)
+Result hbldrLoadProcess(Handle *outProcessHandle, const ExHeader_Info *exhi)
{
- if (AtomicDecrement(&hbldrRefcount)) return;
- svcCloseHandle(hbldrHandle);
+ IFile file;
+ Result res;
+
+ const ExHeader_CodeSetInfo *csi = &exhi->sci.codeset_info;
+
+ u32 region = 0;
+ u32 count;
+ for (count = 0; count < 28; count++)
+ {
+ u32 desc = exhi->aci.kernel_caps.descriptors[count];
+ if (0x1FE == desc >> 23)
+ region = desc & 0xF00;
+ }
+ if (region == 0)
+ return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2);
+
+
+ if (hbldrTarget[0] == 0)
+ {
+ u16_strncpy(hbldrTarget, u"/boot.3dsx", PATH_MAX);
+ ldrArgvBuf[0] = 1;
+ strncpy((char*)&ldrArgvBuf[1], "sdmc:/boot.3dsx", sizeof(ldrArgvBuf)-4);
+ }
+
+ res = IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_UTF16, hbldrTarget), FS_OPEN_READ);
+ hbldrTarget[0] = 0;
+ if (R_FAILED(res))
+ return res;
+
+ u32 totalSize = 0;
+ if (!Ldr_Get3dsxSize(&totalSize, &file))
+ {
+ IFile_Close(&file);
+ return (Result)-1;
+ }
+
+ u32 tmp = 0;
+ u32 addr = 0x10000000;
+ res = svcControlMemory(&tmp, addr, 0, totalSize, MEMOP_ALLOC | region, MEMPERM_READ | MEMPERM_WRITE);
+ if (R_FAILED(res))
+ {
+ IFile_Close(&file);
+ return res;
+ }
+
+ Handle hCodeset = Ldr_CodesetFrom3dsx(csi->name, (u32 *)addr, csi->text.address, &file, exhi->aci.local_caps.title_id);
+ IFile_Close(&file);
+
+ if (hCodeset != 0)
+ {
+ // There are always 28 descriptors
+ res = svcCreateProcess(outProcessHandle, hCodeset, exhi->aci.kernel_caps.descriptors, count);
+ svcCloseHandle(hCodeset);
+ }
+ else
+ res = MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_LDR, RD_NOT_FOUND);
+
+ svcControlMemory(&tmp, addr, 0, totalSize, MEMOP_FREE, 0);
+ return res;
}
-Result HBLDR_LoadProcess(Handle *outCodeSet, u32 textAddr, u32 kernelFlags, u64 titleId, const char *name)
+void hbldrHandleCommands(void *ctx)
{
- u32* cmdbuf = getThreadCommandBuffer(); // 0x11800
- cmdbuf[0] = IPC_MakeHeader(1, 6, 0);
- cmdbuf[1] = textAddr;
- cmdbuf[2] = kernelFlags & 0xF00;
- memcpy(&cmdbuf[3], &titleId, 8);
- strncpy((char *)&cmdbuf[5], name, 8);
- Result rc = svcSendSyncRequest(hbldrHandle);
- if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
+ (void)ctx;
+ u32 *cmdbuf = getThreadCommandBuffer();
+ switch (cmdbuf[0] >> 16)
+ {
+ case 2: // SetTarget
+ {
+ if (cmdbuf[0] != IPC_MakeHeader(2, 0, 2) || (cmdbuf[1] & 0x3FFF) != 0x0002)
+ {
+ error(cmdbuf, 0xD9001830);
+ break;
+ }
+ size_t inSize = cmdbuf[1] >> 14;
+ inSize = inSize > PATH_MAX ? inSize : PATH_MAX;
+ ssize_t units = utf8_to_utf16(hbldrTarget, (const uint8_t*)cmdbuf[2], inSize);
+ if (units < 0 || units > PATH_MAX)
+ {
+ hbldrTarget[0] = 0;
+ error(cmdbuf, 0xD9001830);
+ break;
+ }
- *outCodeSet = R_SUCCEEDED(rc) ? cmdbuf[3] : 0;
- return rc;
+ hbldrTarget[units] = 0;
+ cmdbuf[0] = IPC_MakeHeader(2, 1, 0);
+ cmdbuf[1] = 0;
+ break;
+ }
+ case 3: // SetArgv
+ {
+ if (cmdbuf[0] != IPC_MakeHeader(3, 0, 2) || (cmdbuf[1] & 0x3FFF) != (0x2 | (1<<10)))
+ {
+ error(cmdbuf, 0xD9001830);
+ break;
+ }
+ size_t inSize = cmdbuf[1] >> 14;
+ inSize = inSize > ARGVBUF_SIZE ? inSize : ARGVBUF_SIZE;
+ memcpy(ldrArgvBuf, (const u8 *)cmdbuf[2], inSize);
+ cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
+ cmdbuf[1] = 0;
+ break;
+ }
+ case 1: // LoadProcess (removed)
+ case 4: // PatchExHeaderInfo (removed)
+ case 5: // DebugNextApplicationByForce (removed)
+ default:
+ {
+ error(cmdbuf, 0xD900182F);
+ break;
+ }
+ }
}
-
-Result HBLDR_SetTarget(const char* path)
-{
- u32 pathLen = strlen(path) + 1;
- u32* cmdbuf = getThreadCommandBuffer();
-
- cmdbuf[0] = IPC_MakeHeader(2, 0, 2); // 0x20002
- cmdbuf[1] = IPC_Desc_StaticBuffer(pathLen, 0);
- cmdbuf[2] = (u32)path;
-
- Result rc = svcSendSyncRequest(hbldrHandle);
- if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
- return rc;
-}
-
-Result HBLDR_SetArgv(const void* buffer, size_t size)
-{
- u32* cmdbuf = getThreadCommandBuffer();
-
- cmdbuf[0] = IPC_MakeHeader(3, 0, 2); // 0x30002
- cmdbuf[1] = IPC_Desc_StaticBuffer(size, 1);
- cmdbuf[2] = (u32)buffer;
-
- Result rc = svcSendSyncRequest(hbldrHandle);
- if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
- return rc;
-}
-
-Result HBLDR_PatchExHeaderInfo(ExHeader_Info *exheaderInfo)
-{
- u32* cmdbuf = getThreadCommandBuffer();
-
- cmdbuf[0] = IPC_MakeHeader(4, 0, 2); // 0x40002
- cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheaderInfo), IPC_BUFFER_RW);
- cmdbuf[2] = (u32)exheaderInfo;
-
- Result rc = svcSendSyncRequest(hbldrHandle);
- if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
-
- return rc;
-}
-
-Result HBLDR_DebugNextApplicationByForce(bool dryRun)
-{
- u32* cmdbuf = getThreadCommandBuffer();
-
- cmdbuf[0] = IPC_MakeHeader(5, 1, 0); // 0x50040
- cmdbuf[1] = dryRun ? 1 : 0;
-
- Result rc = svcSendSyncRequest(hbldrHandle);
- if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
-
- return rc;
-}
\ No newline at end of file
diff --git a/sysmodules/loader/source/hbldr.h b/sysmodules/loader/source/hbldr.h
index 4da0c12..f6fe40f 100644
--- a/sysmodules/loader/source/hbldr.h
+++ b/sysmodules/loader/source/hbldr.h
@@ -1,12 +1,42 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2022 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.
+*/
+
#pragma once
-#include <3ds/exheader.h>
+#include <3ds.h>
+#include "luma_shared_config.h"
-Result hbldrInit(void);
-void hbldrExit(void);
+Result hbldrLoadProcess(Handle *outProcessHandle, const ExHeader_Info *exhi);
+void hbldrPatchExHeaderInfo(ExHeader_Info *exhi);
+void hbldrHandleCommands(void *ctx);
-Result HBLDR_LoadProcess(Handle *outCodeSet, u32 textAddr, u32 kernelFlags, u64 titleId, const char *name);
-Result HBLDR_SetTarget(const char* path);
-Result HBLDR_SetArgv(const void* buffer, size_t size);
-Result HBLDR_PatchExHeaderInfo(ExHeader_Info *exheaderInfo);
-Result HBLDR_DebugNextApplicationByForce(bool dryRun);
+static inline bool hbldrIs3dsxTitle(u64 tid)
+{
+ return Luma_SharedConfig->use_hbldr && tid == Luma_SharedConfig->hbldr_3dsx_tid;
+}
+
+void HBLDR_RestartHbApplication(void *p);
+void HBLDR_HandleCommands(void *ctx);
diff --git a/sysmodules/loader/source/loader.c b/sysmodules/loader/source/loader.c
index cb98d57..1a9eae5 100644
--- a/sysmodules/loader/source/loader.c
+++ b/sysmodules/loader/source/loader.c
@@ -13,7 +13,15 @@ static u8 g_ret_buf[sizeof(ExHeader_Info)];
static u64 g_cached_programHandle;
static ExHeader_Info g_exheaderInfo;
-const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00};
+typedef struct ContentPath {
+ u32 contentType;
+ char fileName[8]; // for exefs
+} ContentPath;
+
+static const ContentPath codeContentPath = {
+ .contentType = 1, // ExeFS (with code)
+ .fileName = ".code", // last 3 bytes have to be 0, but this is guaranteed here.s
+};
typedef struct prog_addrs_t
{
@@ -92,12 +100,7 @@ static int lzss_decompress(u8 *end)
return ret;
}
-static inline bool hbldrIs3dsxTitle(u64 tid)
-{
- return Luma_SharedConfig->use_hbldr && tid == Luma_SharedConfig->hbldr_3dsx_tid;
-}
-
-static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags)
+static Result allocateSharedMem(prog_addrs_t *shared, const prog_addrs_t *vaddr, int flags)
{
u32 dummy;
@@ -108,7 +111,7 @@ static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int f
return svcControlMemory(&dummy, shared->text_addr, 0, shared->total_size << 12, (flags & 0xF00) | MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
}
-static Result loadCode(u64 titleId, prog_addrs_t *shared, u64 programHandle, int isCompressed)
+static Result loadCode(const ExHeader_Info *exhi, u64 programHandle, const prog_addrs_t *shared)
{
IFile file;
FS_Path archivePath;
@@ -116,17 +119,22 @@ static Result loadCode(u64 titleId, prog_addrs_t *shared, u64 programHandle, int
u64 size;
u64 total;
+ u64 titleId = exhi->aci.local_caps.title_id;
+ const ExHeader_CodeSetInfo *csi = &exhi->sci.codeset_info;
+ bool isCompressed = csi->flags.compress_exefs_code;
+
if(!CONFIG(PATCHGAMES) || !loadTitleCodeSection(titleId, (u8 *)shared->text_addr, (u64)shared->total_size << 12))
{
archivePath.type = PATH_BINARY;
archivePath.data = &programHandle;
- archivePath.size = 8;
+ archivePath.size = sizeof(programHandle);
filePath.type = PATH_BINARY;
- filePath.data = CODE_PATH;
- filePath.size = sizeof(CODE_PATH);
- if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
- svcBreak(USERBREAK_ASSERT);
+ filePath.data = &codeContentPath;
+ filePath.size = sizeof(codeContentPath);
+ Result res;
+ if (R_FAILED(res = IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
+ *(u64 *)0x1238 = programHandle;//panic(programHandle);//svcBreak(USERBREAK_ASSERT);
// get file size
assertSuccess(IFile_GetSize(&file, &size));
@@ -147,8 +155,6 @@ static Result loadCode(u64 titleId, prog_addrs_t *shared, u64 programHandle, int
lzss_decompress((u8 *)shared->text_addr + size);
}
- ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info;
-
patchCode(titleId, csi->flags.remaster_version, (u8 *)shared->text_addr, shared->total_size << 12, csi->text.size, csi->rodata.size, csi->data.size, csi->rodata.address, csi->data.address);
return 0;
@@ -173,70 +179,40 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
// Tweak 3dsx placeholder title exheaderInfo
if (hbldrIs3dsxTitle(exheaderInfo->aci.local_caps.title_id))
{
- assertSuccess(hbldrInit());
- HBLDR_PatchExHeaderInfo(exheaderInfo);
- hbldrExit();
+ hbldrPatchExHeaderInfo(exheaderInfo);
}
else
{
- u64 originaltitleId = exheaderInfo->aci.local_caps.title_id;
+ u64 originalTitleId = exheaderInfo->aci.local_caps.title_id;
if(CONFIG(PATCHGAMES) && loadTitleExheaderInfo(exheaderInfo->aci.local_caps.title_id, exheaderInfo))
- exheaderInfo->aci.local_caps.title_id = originaltitleId;
+ exheaderInfo->aci.local_caps.title_id = originalTitleId;
}
return res;
}
-static Result LoadProcess(Handle *process, u64 programHandle)
+static Result LoadProcessImpl(Handle *outProcessHandle, const ExHeader_Info *exhi, u64 programHandle)
{
- Result res;
- int count;
- u32 flags;
- u32 desc;
+ const ExHeader_CodeSetInfo *csi = &exhi->sci.codeset_info;
+
+ Result res = 0;
u32 dummy;
prog_addrs_t sharedAddr;
prog_addrs_t vaddr;
Handle codeset;
CodeSetInfo codesetinfo;
u32 dataMemSize;
- u64 titleId;
- // make sure the cached info corrosponds to the current programHandle
- if (g_cached_programHandle != programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
- {
- res = GetProgramInfo(&g_exheaderInfo, programHandle);
- g_cached_programHandle = programHandle;
- if (R_FAILED(res))
- {
- g_cached_programHandle = 0;
- return res;
- }
- }
-
- // get kernel flags
- flags = 0;
+ u32 region = 0;
+ u32 count;
for (count = 0; count < 28; count++)
{
- desc = g_exheaderInfo.aci.kernel_caps.descriptors[count];
+ u32 desc = exhi->aci.kernel_caps.descriptors[count];
if (0x1FE == desc >> 23)
- flags = desc & 0xF00;
- }
- if (flags == 0)
- return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2);
-
- // check for 3dsx process
- titleId = g_exheaderInfo.aci.local_caps.title_id;
- ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info;
-
- if (hbldrIs3dsxTitle(titleId))
- {
- assertSuccess(hbldrInit());
- assertSuccess(HBLDR_LoadProcess(&codeset, csi->text.address, flags & 0xF00, titleId, csi->name));
- res = svcCreateProcess(process, codeset, g_exheaderInfo.aci.kernel_caps.descriptors, count);
- svcCloseHandle(codeset);
- hbldrExit();
- return res;
+ region = desc & 0xF00;
}
+ if (region == 0)
+ return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2);
// allocate process memory
vaddr.text_addr = csi->text.address;
@@ -247,10 +223,11 @@ static Result LoadProcess(Handle *process, u64 programHandle)
vaddr.data_size = (csi->data.size + 4095) >> 12;
dataMemSize = (csi->data.size + csi->bss_size + 4095) >> 12;
vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size;
- TRY(allocateSharedMem(&sharedAddr, &vaddr, flags));
+ TRY(allocateSharedMem(&sharedAddr, &vaddr, region));
// load code
- if (R_SUCCEEDED(res = loadCode(titleId, &sharedAddr, programHandle, csi->flags.compress_exefs_code)))
+ u64 titleId = exhi->aci.local_caps.title_id;
+ if (R_SUCCEEDED(res = loadCode(exhi, programHandle, &sharedAddr)))
{
memcpy(&codesetinfo.name, csi->name, 8);
codesetinfo.program_id = titleId;
@@ -266,7 +243,8 @@ static Result LoadProcess(Handle *process, u64 programHandle)
res = svcCreateCodeSet(&codeset, &codesetinfo, (void *)sharedAddr.text_addr, (void *)sharedAddr.ro_addr, (void *)sharedAddr.data_addr);
if (R_SUCCEEDED(res))
{
- res = svcCreateProcess(process, codeset, g_exheaderInfo.aci.kernel_caps.descriptors, count);
+ // There are always 28 descriptors
+ res = svcCreateProcess(outProcessHandle, codeset, exhi->aci.kernel_caps.descriptors, count);
svcCloseHandle(codeset);
res = R_SUCCEEDED(res) ? 0 : res;
}
@@ -276,6 +254,28 @@ static Result LoadProcess(Handle *process, u64 programHandle)
return res;
}
+static Result LoadProcess(Handle *process, u64 programHandle)
+{
+ Result res;
+
+ // make sure the cached info corresponds to the current programHandle
+ if (g_cached_programHandle != programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
+ {
+ res = GetProgramInfo(&g_exheaderInfo, programHandle);
+ g_cached_programHandle = programHandle;
+ if (R_FAILED(res))
+ {
+ g_cached_programHandle = 0;
+ return res;
+ }
+ }
+
+ if (hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
+ return hbldrLoadProcess(process, &g_exheaderInfo);
+ else
+ return LoadProcessImpl(process, &g_exheaderInfo, programHandle);
+}
+
static Result RegisterProgram(u64 *programHandle, FS_ProgramInfo *title, FS_ProgramInfo *update)
{
Result res;
diff --git a/sysmodules/loader/source/luma_shared_config.h b/sysmodules/loader/source/luma_shared_config.h
index f956a83..31cb490 100644
--- a/sysmodules/loader/source/luma_shared_config.h
+++ b/sysmodules/loader/source/luma_shared_config.h
@@ -18,10 +18,13 @@
#include <3ds/types.h>
+/// Default TitleID for 3DSX loading
+#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
+
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
- bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
+ bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true).
} LumaSharedConfig;
/// Luma shared config.
diff --git a/sysmodules/loader/source/main.c b/sysmodules/loader/source/main.c
index 7b91768..17f3458 100644
--- a/sysmodules/loader/source/main.c
+++ b/sysmodules/loader/source/main.c
@@ -1,10 +1,13 @@
#include <3ds.h>
+#include
#include "memory.h"
#include "patcher.h"
#include "ifile.h"
#include "util.h"
#include "loader.h"
#include "service_manager.h"
+#include "3dsx.h"
+#include "hbldr.h"
u32 config, multiConfig, bootConfig;
bool isN3DS, isSdMode;
@@ -28,20 +31,43 @@ static Result fsldrPatchPermissions(void)
static inline void loadCFWInfo(void)
{
s64 out;
+ u64 hbldrTid = 0;
- if(svcGetSystemInfo(&out, 0x20000, 0) != 1) panic(0xDEADCAFE);
+ bool isLumaWithKext = svcGetSystemInfo(&out, 0x20000, 0) == 1;
+ if (isLumaWithKext)
+ {
+ svcGetSystemInfo(&out, 0x10000, 3);
+ config = (u32)out;
+ svcGetSystemInfo(&out, 0x10000, 4);
+ multiConfig = (u32)out;
+ svcGetSystemInfo(&out, 0x10000, 5);
+ bootConfig = (u32)out;
- svcGetSystemInfo(&out, 0x10000, 3);
- config = (u32)out;
- svcGetSystemInfo(&out, 0x10000, 4);
- multiConfig = (u32)out;
- svcGetSystemInfo(&out, 0x10000, 5);
- bootConfig = (u32)out;
+ svcGetSystemInfo(&out, 0x10000, 0x100);
+ hbldrTid = (u64)out;
+ svcGetSystemInfo(&out, 0x10000, 0x201);
+ isN3DS = (bool)out;
+ svcGetSystemInfo(&out, 0x10000, 0x203);
+ isSdMode = (bool)out;
+ }
+ else
+ {
+ // Try to support non-Luma or builds where kext is disabled
+ s64 numKips = 0;
+ svcGetSystemInfo(&numKips, 26, 0);
- svcGetSystemInfo(&out, 0x10000, 0x201);
- isN3DS = (bool)out;
- svcGetSystemInfo(&out, 0x10000, 0x203);
- isSdMode = (bool)out;
+ if (numKips >= 6)
+ panic(0xDEADCAFE);
+
+ config = 0; // all options 0
+ multiConfig = 0;
+ bootConfig = 0;
+ isN3DS = OS_KernelConfig->app_memtype >= 6;
+ isSdMode = true;
+ }
+
+ Luma_SharedConfig->hbldr_3dsx_tid = hbldrTid == 0 ? HBLDR_DEFAULT_3DSX_TID : hbldrTid;
+ Luma_SharedConfig->use_hbldr = true;
}
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
@@ -88,6 +114,7 @@ void initSystem(void)
static const ServiceManagerServiceEntry services[] = {
{ "Loader", 1, loaderHandleCommands, false },
+ { "hb:ldr", 2, hbldrHandleCommands, true },
{ NULL },
};
@@ -95,9 +122,18 @@ static const ServiceManagerNotificationEntry notifications[] = {
{ 0x000, NULL },
};
+static u8 ALIGN(4) staticBufferForHbldr[0x400];
+static_assert(ARGVBUF_SIZE > 2 * PATH_MAX, "Wrong 3DSX argv buffer size");
+
int main(void)
{
- loadCFWInfo();
+ // Loader doesn't use any input static buffer, so we should be fine
+ u32 *sbuf = getThreadStaticBuffers();
+ sbuf[0] = IPC_Desc_StaticBuffer(sizeof(staticBufferForHbldr), 0);
+ sbuf[1] = (u32)staticBufferForHbldr;
+ sbuf[2] = IPC_Desc_StaticBuffer(sizeof(staticBufferForHbldr), 1);
+ sbuf[3] = (u32)staticBufferForHbldr;
+
assertSuccess(ServiceManager_Run(services, notifications, NULL));
return 0;
}
diff --git a/sysmodules/pm/source/launch.c b/sysmodules/pm/source/launch.c
index efc40a4..30c9b2b 100644
--- a/sysmodules/pm/source/launch.c
+++ b/sysmodules/pm/source/launch.c
@@ -290,7 +290,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
return res;
}
-static Result launchTitleImplWrapper(Handle *outDebug, u32 *outPid, const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags)
+Result launchTitleImplWrapper(Handle *outDebug, u32 *outPid, const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags)
{
ExHeader_Info *exheaderInfo = ExHeaderInfoHeap_New();
if (exheaderInfo == NULL) {
@@ -389,18 +389,18 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla
Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags)
{
- ProcessList_Lock(&g_manager.processList);
if (g_manager.preparingForReboot) {
return 0xC8A05801;
}
- if (g_manager.runningApplicationData != NULL) {
- ProcessList_Unlock(&g_manager.processList);
- return 0xC8A05BF0;
- }
if (!(launchFlags & ~PMLAUNCHFLAG_NORMAL_APPLICATION)) {
return 0xD8E05802;
}
- ProcessList_Unlock(&g_manager.processList);
+
+ ProcessList_Lock(&g_manager.processList);
+ if (g_manager.runningApplicationData != NULL) {
+ ProcessList_Unlock(&g_manager.processList);
+ return 0xC8A05BF0;
+ }
bool originallyDebugged = launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION;
diff --git a/sysmodules/pm/source/launch.h b/sysmodules/pm/source/launch.h
index e0ff125..c982655 100644
--- a/sysmodules/pm/source/launch.h
+++ b/sysmodules/pm/source/launch.h
@@ -20,3 +20,5 @@ Result autolaunchSysmodules(void);
// Custom
Result DebugNextApplicationByForce(bool debug);
Result LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags);
+
+Result launchTitleImplWrapper(Handle *outDebug, u32 *outPid, const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags);
diff --git a/sysmodules/pm/source/main.c b/sysmodules/pm/source/main.c
index 187d7ca..9b7fedc 100644
--- a/sysmodules/pm/source/main.c
+++ b/sysmodules/pm/source/main.c
@@ -4,6 +4,7 @@
#include "reslimit.h"
#include "launch.h"
#include "firmlaunch.h"
+#include "termination.h"
#include "exheader_info_heap.h"
#include "task_runner.h"
#include "process_monitor.h"
@@ -57,8 +58,19 @@ static const ServiceManagerServiceEntry services[] = {
{ NULL },
};
+static void handleRestartHbAppNotification(u32 notificationId)
+{
+ // Dirty workaround to support hbmenu on SAFE_FIRM
+ // Cleaning up dependencies would mean terminating most sysmodules,
+ // and letting app term. notif. go through would cause NS to svcBreak,
+ // this is not what we want.
+ (void)notificationId;
+ ChainloadHomebrewDirty();
+}
+
static const ServiceManagerNotificationEntry notifications[] = {
- { 0x000, NULL },
+ { 0x3000, handleRestartHbAppNotification },
+ { 0x0000, NULL },
};
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
diff --git a/sysmodules/pm/source/manager.c b/sysmodules/pm/source/manager.c
index b527db6..deacd64 100644
--- a/sysmodules/pm/source/manager.c
+++ b/sysmodules/pm/source/manager.c
@@ -90,27 +90,3 @@ Result UnregisterProcess(u64 titleId)
ProcessList_Unlock(&g_manager.processList);
return 0;
}
-
-Result PrepareToChainloadHomebrew(u64 titleId)
-{
- // Note: I'm allowing this command to be called for non-applications, maybe that'll be useful
- // in the future...
-
- ProcessData *foundProcess = NULL;
- Result res;
- ProcessList_Lock(&g_manager.processList);
- foundProcess = ProcessList_FindProcessByTitleId(&g_manager.processList, titleId & ~N3DS_TID_MASK);
- if (foundProcess != NULL) {
- // Clear the "notify on termination, don't cleanup" flag, so that for ex. APT isn't notified & no need for UnregisterProcess,
- // and the "dependencies loaded" flag, so that the dependencies aren't killed (for ex. when
- // booting hbmenu instead of Home Menu, in which case the same title is going to be launched...)
-
- foundProcess->flags &= ~(PROCESSFLAG_DEPENDENCIES_LOADED | PROCESSFLAG_NOTIFY_TERMINATION);
- res = 0;
- } else {
- res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
- }
-
- ProcessList_Unlock(&g_manager.processList);
- return res;
-}
diff --git a/sysmodules/pm/source/manager.h b/sysmodules/pm/source/manager.h
index ca71db4..82346dd 100644
--- a/sysmodules/pm/source/manager.h
+++ b/sysmodules/pm/source/manager.h
@@ -21,4 +21,3 @@ extern Manager g_manager;
void Manager_Init(void *procBuf, size_t numProc);
void Manager_RegisterKips(void);
Result UnregisterProcess(u64 titleId);
-Result PrepareToChainloadHomebrew(u64 titleId);
diff --git a/sysmodules/pm/source/pmdbg.c b/sysmodules/pm/source/pmdbg.c
index 6e88ded..53338b4 100644
--- a/sysmodules/pm/source/pmdbg.c
+++ b/sysmodules/pm/source/pmdbg.c
@@ -12,7 +12,6 @@ void pmDbgHandleCommands(void *ctx)
u32 cmdhdr = cmdbuf[0];
FS_ProgramInfo programInfo;
- u64 titleId;
Handle debug;
u32 pid;
u32 launchFlags;
@@ -59,11 +58,7 @@ void pmDbgHandleCommands(void *ctx)
cmdbuf[2] = IPC_Desc_MoveHandles(1);
cmdbuf[3] = debug;
break;
- case 0x103:
- memcpy(&titleId, cmdbuf + 1, 8);
- cmdbuf[1] = PrepareToChainloadHomebrew(titleId);
- cmdbuf[0] = IPC_MakeHeader(0x103, 1, 0);
- break;
+ case 0x103: // PrepareToChainloadHomebrew (removed)
default:
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
cmdbuf[1] = 0xD900182F;
diff --git a/sysmodules/pm/source/termination.c b/sysmodules/pm/source/termination.c
index 156109c..72a8dee 100644
--- a/sysmodules/pm/source/termination.c
+++ b/sysmodules/pm/source/termination.c
@@ -5,6 +5,7 @@
#include "util.h"
#include "exheader_info_heap.h"
#include "task_runner.h"
+#include "launch.h"
void forceMountSdCard(void)
{
@@ -387,3 +388,78 @@ Result PrepareForReboot(u32 pid, s64 timeout)
TaskRunner_RunTask(PrepareForRebootAsync, &args, sizeof(args));
return 0;
}
+
+static void ChainloadHomebrewDirtyAsync(void *argdata)
+{
+ (void)argdata;
+ Result res = 0;
+ ProcessData *app = NULL;
+ u32 launchFlags;
+ FS_ProgramInfo programInfo;
+
+ ExHeader_Info *exheaderInfo = ExHeaderInfoHeap_New();
+ if (exheaderInfo == NULL) {
+ panic(0);
+ }
+
+ assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent));
+ g_manager.waitingForTermination = true;
+
+ ProcessList_Lock(&g_manager.processList);
+ app = g_manager.runningApplicationData;
+ if (app != NULL) {
+ // Clear the "notify on termination, don't cleanup" flag, so that for ex. APT isn't notified & no need for
+ // UnregisterProcess, and the "dependencies loaded" flag, so that the dependencies aren't killed (for ex. when
+ // booting hbmenu instead of Home Menu, in which case the same title is going to be launched...)
+ launchFlags = app->launchFlags;
+ programInfo.programId = app->titleId;
+ programInfo.mediaType = app->mediaType;
+ app->flags &= ~(PROCESSFLAG_DEPENDENCIES_LOADED | PROCESSFLAG_NOTIFY_TERMINATION);
+ terminateProcessImpl(app, exheaderInfo);
+ }
+ ProcessList_Unlock(&g_manager.processList);
+
+ res = commitPendingTerminations(3 * 1000 * 1000 * 1000LL); // 3s, what NS is using
+ ExHeaderInfoHeap_Delete(exheaderInfo);
+ g_manager.waitingForTermination = false;
+
+ if (app == NULL) {
+ res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
+ } else if (R_SUCCEEDED(res)) {
+ // Wait for process monitor thread to clean the terminated process up
+ app = NULL;
+ do {
+ svcSleepThread(100 * 1000 * 1000LL);
+ ProcessList_Lock(&g_manager.processList);
+ app = g_manager.runningApplicationData;
+ ProcessList_Unlock(&g_manager.processList);
+ } while (app != NULL);
+
+ // Since this is a dirty workaround for hb support on SAFE_FIRM, we can opt not to support
+ // launch-from-gamecard/update support.
+ launchFlags &= ~PMLAUNCHFLAG_USE_UPDATE_TITLE;
+ launchFlags |= PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING;
+ res = launchTitleImplWrapper(NULL, NULL, &programInfo, NULL, launchFlags);
+ }
+}
+
+Result ChainloadHomebrewDirty(void) {
+ ProcessData *app = NULL;
+ Result res = 0;
+
+ if (g_manager.preparingForReboot) {
+ return 0xC8A05801;
+ }
+ ProcessList_Lock(&g_manager.processList);
+ app = g_manager.runningApplicationData;
+ ProcessList_Unlock(&g_manager.processList);
+
+ if (app == NULL) {
+ res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
+ } else {
+ TaskRunner_RunTask(ChainloadHomebrewDirtyAsync, NULL, 0);
+ res = 0;
+ }
+
+ return res;
+}
diff --git a/sysmodules/pm/source/termination.h b/sysmodules/pm/source/termination.h
index e726b24..54577f3 100644
--- a/sysmodules/pm/source/termination.h
+++ b/sysmodules/pm/source/termination.h
@@ -10,3 +10,5 @@ Result TerminateApplication(s64 timeout);
Result TerminateTitle(u64 titleId, s64 timeout);
Result TerminateProcess(u32 pid, s64 timeout);
Result PrepareForReboot(u32 pid, s64 timeout);
+
+Result ChainloadHomebrewDirty(void);
diff --git a/sysmodules/rosalina/include/hbloader.h b/sysmodules/rosalina/include/hbloader.h
deleted file mode 100644
index b2fbcca..0000000
--- a/sysmodules/rosalina/include/hbloader.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-* 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.
-*/
-
-/* File mainly written by fincs */
-#pragma once
-
-#include <3ds/types.h>
-#include "MyThread.h"
-
-#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
-
-void HBLDR_RestartHbApplication(void *p);
-void HBLDR_HandleCommands(void *ctx);
diff --git a/sysmodules/rosalina/include/luma_shared_config.h b/sysmodules/rosalina/include/luma_shared_config.h
index b63c433..222af23 100644
--- a/sysmodules/rosalina/include/luma_shared_config.h
+++ b/sysmodules/rosalina/include/luma_shared_config.h
@@ -18,12 +18,13 @@
#include <3ds/types.h>
-#include <3ds/types.h>
+/// Default TitleID for 3DSX loading
+#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
- bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
+ bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true).
} LumaSharedConfig;
/// Luma shared config.
diff --git a/sysmodules/rosalina/include/pmdbgext.h b/sysmodules/rosalina/include/pmdbgext.h
index 64491e8..89f8d89 100644
--- a/sysmodules/rosalina/include/pmdbgext.h
+++ b/sysmodules/rosalina/include/pmdbgext.h
@@ -14,4 +14,3 @@ enum {
Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags);
Result PMDBG_DebugNextApplicationByForce(bool debug);
Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags);
-Result PMDBG_PrepareToChainloadHomebrew(u64 titleId);
diff --git a/sysmodules/rosalina/source/hbloader.c b/sysmodules/rosalina/source/hbloader.c
deleted file mode 100644
index f645b0c..0000000
--- a/sysmodules/rosalina/source/hbloader.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
-* 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.
-*/
-
-/* This file was mostly written by fincs */
-
-#include <3ds.h>
-#include "hbloader.h"
-#include "3dsx.h"
-#include "menu.h"
-#include "csvc.h"
-#include "memory.h"
-
-#include "gdb/server.h"
-#include "pmdbgext.h"
-
-extern GDBContext *nextApplicationGdbCtx;
-extern GDBServer gdbServer;
-
-static const char serviceList[32][8] =
-{
- "APT:U",
- "ac:u",
- "am:net",
- "boss:P",
- "cam:u",
- "cfg:nor",
- "cfg:u",
- "csnd:SND",
- "dsp::DSP",
- "fs:USER",
- "gsp::Lcd",
- "gsp::Gpu",
- "hid:USER",
- "http:C",
- "ir:USER",
- "ir:rst",
- "ir:u",
- "ldr:ro",
- "mic:u",
- "ndm:u",
- "news:s",
- "nim:s",
- "ns:s",
- "nwm::UDS",
- "nwm::EXT",
- "ptm:u",
- "ptm:sysm",
- "pxi:dev",
- "qtm:u",
- "soc:U",
- "ssl:C",
- "y2r:u",
-};
-
-static const u64 dependencyListNativeFirm[] =
-{
- 0x0004013000002402LL, //ac
- 0x0004013000001502LL, //am
- 0x0004013000001702LL, //cfg
- 0x0004013000001802LL, //codec
- 0x0004013000002702LL, //csnd
- 0x0004013000001A02LL, //dsp
- 0x0004013000001B02LL, //gpio
- 0x0004013000001C02LL, //gsp
- 0x0004013000001D02LL, //hid
- 0x0004013000002902LL, //http
- 0x0004013000001E02LL, //i2c
- 0x0004013000003302LL, //ir
- 0x0004013000001F02LL, //mcu
- 0x0004013000002C02LL, //nim
- 0x0004013000002D02LL, //nwm
- 0x0004013000002102LL, //pdn
- 0x0004013000003102LL, //ps
- 0x0004013000002202LL, //ptm
- 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 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
- 0xFF81FF78, // RW static mapping: 0x1FF78000
- 0xFF91F000, // RO static mapping: 0x1F000000
- 0xFF91F600, // RO static mapping: 0x1F600000
- 0xFF002109, // Exflags: APPLICATION memtype + "Shared page writing" + "Allow debug" + "Access core2"
- 0xFE000200, // Handle table size: 0x200
-};
-
-static inline void assertSuccess(Result res)
-{
- if(R_FAILED(res))
- svcBreak(USERBREAK_PANIC);
-}
-
-static u16 hbldrTarget[PATH_MAX+1];
-
-static inline void error(u32* cmdbuf, Result rc)
-{
- cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
- cmdbuf[1] = rc;
-}
-
-static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size)
-{
- u32 i;
- for (i = 0; i < size && src[i] != 0; i++)
- dest[i] = src[i];
- while (i < size)
- dest[i++] = 0;
-
- 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;
- Result res = 0;
- IFile file;
- u32 *cmdbuf = getThreadCommandBuffer();
- switch (cmdbuf[0] >> 16)
- {
- case 1: // LoadProcess
- {
- if (cmdbuf[0] != IPC_MakeHeader(1, 6, 0))
- {
- error(cmdbuf, 0xD9001830);
- break;
- }
-
- u32 baseAddr = cmdbuf[1];
- u32 flags = cmdbuf[2] & 0xF00;
- u64 tid = (u64)cmdbuf[3] | ((u64)cmdbuf[4]<<32);
- char name[8];
- memcpy(name, &cmdbuf[5], sizeof(name));
-
- if (hbldrTarget[0] == 0)
- {
- u16_strncpy(hbldrTarget, u"/boot.3dsx", PATH_MAX);
- ldrArgvBuf[0] = 1;
- strncpy((char*)&ldrArgvBuf[1], "sdmc:/boot.3dsx", sizeof(ldrArgvBuf)-4);
- }
-
- res = IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_UTF16, hbldrTarget), FS_OPEN_READ);
- hbldrTarget[0] = 0;
- if (R_FAILED(res))
- {
- error(cmdbuf, res);
- break;
- }
-
- u32 totalSize = 0;
- res = Ldr_Get3dsxSize(&totalSize, &file);
- if (R_FAILED(res))
- {
- IFile_Close(&file);
- error(cmdbuf, res);
- break;
- }
-
- // note: mappableFree doesn't do anything
- u32 tmp = 0;
- 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);
- error(cmdbuf, res);
- break;
- }
-
- Handle hCodeset = Ldr_CodesetFrom3dsx(name, addr, baseAddr, &file, tid);
- IFile_Close(&file);
-
- if (!hCodeset)
- {
- svcControlMemory(&tmp, (u32)addr, 0, totalSize, MEMOP_FREE, 0);
- error(cmdbuf, MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_LDR, RD_NOT_FOUND));
- break;
- }
-
- cmdbuf[0] = IPC_MakeHeader(1, 1, 2);
- cmdbuf[1] = 0;
- cmdbuf[2] = IPC_Desc_MoveHandles(1);
- cmdbuf[3] = hCodeset;
- break;
- }
- case 2: // SetTarget
- {
- if (cmdbuf[0] != IPC_MakeHeader(2, 0, 2) || (cmdbuf[1] & 0x3FFF) != 0x0002)
- {
- error(cmdbuf, 0xD9001830);
- break;
- }
- ssize_t units = utf8_to_utf16(hbldrTarget, (const uint8_t*)cmdbuf[2], PATH_MAX);
- if (units < 0 || units > PATH_MAX)
- {
- hbldrTarget[0] = 0;
- error(cmdbuf, 0xD9001830);
- break;
- }
-
- hbldrTarget[units] = 0;
- cmdbuf[0] = IPC_MakeHeader(2, 1, 0);
- cmdbuf[1] = 0;
- break;
- }
- case 3: // SetArgv
- {
- if (cmdbuf[0] != IPC_MakeHeader(3, 0, 2) || (cmdbuf[1] & 0x3FFF) != (0x2 | (1<<10)))
- {
- error(cmdbuf, 0xD9001830);
- break;
- }
- // No need to do anything - the kernel already copied the data to our buffer
- cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
- cmdbuf[1] = 0;
- break;
- }
- case 4: // PatchExHeaderInfo
- {
- if (cmdbuf[0] != IPC_MakeHeader(4, 0, 2) || cmdbuf[1] != IPC_Desc_Buffer(sizeof(ExHeader_Info), IPC_BUFFER_RW))
- {
- error(cmdbuf, 0xD9001830);
- break;
- }
-
- // Perform ExHeader patches
- ExHeader_Info* exhi = (ExHeader_Info*)cmdbuf[2];
- u32 stacksize = 4096; // 3dsx/libctru don't require anymore than this
- 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));
-
- u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
- if (coreVer == 2)
- memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
- else if (coreVer == 3)
- memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm));
-
- ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps;
-
- localcaps0->core_info.core_version = coreVer;
- localcaps0->core_info.use_cpu_clockrate_804MHz = false;
- localcaps0->core_info.enable_l2c = false;
- localcaps0->core_info.ideal_processor = 0;
- localcaps0->core_info.affinity_mask = BIT(0);
- localcaps0->core_info.priority = 0x30;
-
- u32 appmemtype = OS_KernelConfig->app_memtype;
- 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));
-
- // 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.no_romfs = true;
- localcaps0->storage_info.use_extended_savedata_access = true; // Whatever
-
- // We have a patched SM, so whatever...
- memset(localcaps0->service_access, 0, sizeof(localcaps0->service_access));
- memcpy(localcaps0->service_access, serviceList, sizeof(serviceList));
-
- localcaps0->reslimit_category = RESLIMIT_CATEGORY_APPLICATION;
-
- ExHeader_Arm11KernelCapabilities* kcaps0 = &exhi->aci.kernel_caps;
- memset(kcaps0->descriptors, 0xFF, sizeof(kcaps0->descriptors));
- memcpy(kcaps0->descriptors, kernelCaps, sizeof(kernelCaps));
-
- // Set kernel release version to the current kernel version
- kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16);
-
- if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && coreVer == 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;
- bool isN3DS = svcGetSystemInfo(&dummy, 0x10001, 0) == 0;
- if (isN3DS)
- {
- exhi->sci.dependencies[lastdep++] = 0x0004013020004102ULL; // mvd
- strncpy((char*)&localcaps0->service_access[0x21], "mvd:STD", 8);
- }
- }
-
- cmdbuf[0] = IPC_MakeHeader(4, 1, 2);
- cmdbuf[1] = 0;
- cmdbuf[2] = IPC_Desc_Buffer(sizeof(ExHeader_Info), IPC_BUFFER_RW);
- cmdbuf[3] = (u32)exhi;
- break;
- }
- case 5: // DebugNextApplicationByForce
- {
- res = 0;
- if (gdbServer.referenceCount == 0)
- res = MAKERESULT(RL_PERMANENT, RS_INVALIDSTATE, RM_LDR, RD_NOT_INITIALIZED);
- else if (cmdbuf[1] == 0)
- {
- GDB_LockAllContexts(&gdbServer);
- if (nextApplicationGdbCtx != NULL)
- res = MAKERESULT(RL_PERMANENT, RS_NOP, RM_LDR, RD_ALREADY_DONE);
- else
- {
- nextApplicationGdbCtx = GDB_SelectAvailableContext(&gdbServer, GDB_PORT_BASE + 3, GDB_PORT_BASE + 4);
- if (nextApplicationGdbCtx != NULL)
- {
- nextApplicationGdbCtx->debug = 0;
- nextApplicationGdbCtx->pid = 0xFFFFFFFF;
- res = PMDBG_DebugNextApplicationByForce(true);
- if (R_FAILED(res))
- {
- nextApplicationGdbCtx->flags = 0;
- nextApplicationGdbCtx->localPort = 0;
- nextApplicationGdbCtx = NULL;
- }
- }
- else
- res = MAKERESULT(RL_PERMANENT, RS_OUTOFRESOURCE, RM_LDR, RD_OUT_OF_RANGE);
- }
- GDB_UnlockAllContexts(&gdbServer);
- }
- cmdbuf[1] = res;
- cmdbuf[0] = IPC_MakeHeader(5, 1, 0);
- break;
- }
- default:
- {
- error(cmdbuf, 0xD900182F);
- break;
- }
- }
-}
diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c
index 2357821..eb54331 100644
--- a/sysmodules/rosalina/source/main.c
+++ b/sysmodules/rosalina/source/main.c
@@ -29,8 +29,6 @@
#include "menu.h"
#include "service_manager.h"
#include "errdisp.h"
-#include "hbloader.h"
-#include "3dsx.h"
#include "utils.h"
#include "MyThread.h"
#include "menus/miscellaneous.h"
@@ -81,9 +79,6 @@ void initSystem(void)
mappableInit(0x10000000, 0x14000000);
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
- svcGetSystemInfo(&out, 0x10000, 0x100);
- Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out;
- Luma_SharedConfig->use_hbldr = true;
svcGetSystemInfo(&out, 0x10000, 0x101);
menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out;
@@ -216,14 +211,15 @@ static void handleNextApplicationDebuggedByForce(u32 notificationId)
TaskRunner_RunTask(debuggerFetchAndSetNextApplicationDebugHandleTask, NULL, 0);
}
+#if 0
static void handleRestartHbAppNotification(u32 notificationId)
{
(void)notificationId;
TaskRunner_RunTask(HBLDR_RestartHbApplication, NULL, 0);
}
+#endif
static const ServiceManagerServiceEntry services[] = {
- { "hb:ldr", 2, HBLDR_HandleCommands, true },
{ NULL },
};
@@ -240,22 +236,11 @@ static const ServiceManagerNotificationEntry notifications[] = {
{ 0x214, handleShellNotification },
{ 0x1000, handleNextApplicationDebuggedByForce },
{ 0x2000, handlePreTermNotification },
- { 0x3000, handleRestartHbAppNotification },
{ 0x000, NULL },
};
int main(void)
{
- static u8 ipcBuf[0x100] = {0}; // used by both err:f and hb:ldr
-
- // Set up static buffers for IPC
- u32* bufPtrs = getThreadStaticBuffers();
- memset(bufPtrs, 0, 16 * 2 * 4);
- bufPtrs[0] = IPC_Desc_StaticBuffer(sizeof(ipcBuf), 0);
- bufPtrs[1] = (u32)ipcBuf;
- bufPtrs[2] = IPC_Desc_StaticBuffer(sizeof(ldrArgvBuf), 1);
- bufPtrs[3] = (u32)ldrArgvBuf;
-
if(R_FAILED(svcCreateEvent(&preTerminationEvent, RESET_STICKY)))
svcBreak(USERBREAK_ASSERT);
diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c
index 5c81a51..9dc055c 100644
--- a/sysmodules/rosalina/source/menus/miscellaneous.c
+++ b/sysmodules/rosalina/source/menus/miscellaneous.c
@@ -30,7 +30,6 @@
#include "ntp.h"
#include "memory.h"
#include "draw.h"
-#include "hbloader.h"
#include "fmt.h"
#include "utils.h" // for makeArmBranch
#include "minisoc.h"
diff --git a/sysmodules/rosalina/source/pmdbgext.c b/sysmodules/rosalina/source/pmdbgext.c
index 48af096..7085014 100644
--- a/sysmodules/rosalina/source/pmdbgext.c
+++ b/sysmodules/rosalina/source/pmdbgext.c
@@ -48,16 +48,3 @@ 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];
-}