Move hb:ldr from Rosalina to Loader
Let's not pretend in 2022 that it needed things from rosalina sysmodule - it did not. This moves 3DSX loading from Rosalina to Loader, and also removes all the dependencies Loader had to other Luma3DS components (if kernel ext. is missing, a default config will be used). This means that, as long as you replace Loader to the one in here, you will be able to properly load 3DSX files. Changes: - hb:ldr is now hosted in loader - hb:ldr LoadProcess, PatchExHeaderInfo, DebugNextApplicationByForce: all removed - fix a bug where some malformed 3DSX files were not rejected - grant access to CONFIG11 registers to 3DSX homebrew - move dirty homebrew chainload (when HM. isn't loaded nor loadable) to pm - pm:dbg (ext.) PrepareToChainloadHomebrew: removed
This commit is contained in:
parent
6fa80c959d
commit
7074ac1166
@ -25,7 +25,7 @@ AccessControlInfo:
|
||||
|
||||
DisableDebug : true
|
||||
EnableForceDebug : false
|
||||
CanWriteSharedPage : false
|
||||
CanWriteSharedPage : true
|
||||
CanUsePrivilegedPriority : false
|
||||
CanUseNonAlphabetAndNumber : false
|
||||
PermitMainFunctionArgument : false
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <3ds.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include <3ds.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/* 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);
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user