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]; -}