mirror of
https://github.com/XorTroll/uLaunch
synced 2024-11-26 05:40:20 +00:00
New hb-related stuff
This commit is contained in:
parent
d1088de4f5
commit
10075da16c
12 changed files with 1332 additions and 0 deletions
14
Common/Include/hb/hb_Target.hpp
Normal file
14
Common/Include/hb/hb_Target.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
#pragma once
|
||||
#include <q_Include.hpp>
|
||||
|
||||
namespace hb
|
||||
{
|
||||
struct TargetInput
|
||||
{
|
||||
char nro_path[2048];
|
||||
char argv[2048];
|
||||
};
|
||||
|
||||
void Target(TargetInput input, bool once);
|
||||
}
|
15
Common/Source/hb/hb_Target.cpp
Normal file
15
Common/Source/hb/hb_Target.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <hb/hb_Target.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void hb_hbl_Target(const char *path, const char *argv, int counter);
|
||||
}
|
||||
|
||||
namespace hb
|
||||
{
|
||||
void Target(TargetInput input, bool once)
|
||||
{
|
||||
int ctr = once ? 1 : -1;
|
||||
hb_hbl_Target(input.nro_path, input.argv, ctr);
|
||||
}
|
||||
}
|
462
Common/Source/hb/hb_hbl.c
Normal file
462
Common/Source/hb/hb_hbl.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
#include <switch.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const char g_noticeText[] =
|
||||
"HbTarget impl (thanks nx-hbloader)\0"
|
||||
"Do you mean to tell me that you're thinking seriously of building that way, when and if you are an architect?";
|
||||
|
||||
static char g_argv[2048];
|
||||
static char g_nextArgv[2048];
|
||||
static char g_nextNroPath[512];
|
||||
u64 g_nroAddr = 0;
|
||||
static u64 g_nroSize = 0;
|
||||
static NroHeader g_nroHeader;
|
||||
static bool g_isApplication = 0;
|
||||
|
||||
static NsApplicationControlData g_applicationControlData;
|
||||
static bool g_isAutomaticGameplayRecording = 0;
|
||||
static bool g_smCloseWorkaround = false;
|
||||
|
||||
static u64 g_appletHeapSize = 0;
|
||||
static u64 g_appletHeapReservationSize = 0;
|
||||
|
||||
static u128 g_userIdStorage;
|
||||
|
||||
static u8 g_savedTls[0x100];
|
||||
|
||||
// Special HbTarget stuff
|
||||
static char g_basePath[2048];
|
||||
static char g_baseArgv[2048];
|
||||
static int g_targetCounter = 0;
|
||||
|
||||
// Used by trampoline.s
|
||||
Result g_lastRet = 0;
|
||||
|
||||
extern void* __stack_top;//Defined in libnx.
|
||||
#define STACK_SIZE 0x100000 //Change this if main-thread stack size ever changes.
|
||||
|
||||
void __libnx_initheap(void)
|
||||
{
|
||||
static char g_innerheap[0x20000];
|
||||
|
||||
extern char* fake_heap_start;
|
||||
extern char* fake_heap_end;
|
||||
|
||||
fake_heap_start = &g_innerheap[0];
|
||||
fake_heap_end = &g_innerheap[sizeof g_innerheap];
|
||||
}
|
||||
|
||||
void __appInit(void)
|
||||
{
|
||||
Result rc;
|
||||
|
||||
rc = smInitialize();
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 1));
|
||||
|
||||
rc = setsysInitialize();
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
SetSysFirmwareVersion fw;
|
||||
rc = setsysGetFirmwareVersion(&fw);
|
||||
if (R_SUCCEEDED(rc))
|
||||
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
|
||||
setsysExit();
|
||||
}
|
||||
|
||||
rc = fsInitialize();
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 2));
|
||||
|
||||
fsdevMountSdmc();
|
||||
}
|
||||
|
||||
void __wrap_exit(void)
|
||||
{
|
||||
// exit() effectively never gets called, so let's stub it out.
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 39));
|
||||
}
|
||||
|
||||
static void* g_heapAddr;
|
||||
static size_t g_heapSize;
|
||||
|
||||
static u64 calculateMaxHeapSize(void)
|
||||
{
|
||||
u64 size = 0;
|
||||
u64 mem_available = 0, mem_used = 0;
|
||||
|
||||
svcGetInfo(&mem_available, InfoType_TotalMemorySize, CUR_PROCESS_HANDLE, 0);
|
||||
svcGetInfo(&mem_used, InfoType_UsedMemorySize, CUR_PROCESS_HANDLE, 0);
|
||||
|
||||
if (mem_available > mem_used+0x200000)
|
||||
size = (mem_available - mem_used - 0x200000) & ~0x1FFFFF;
|
||||
if (size == 0)
|
||||
size = 0x2000000*16;
|
||||
if (size > 0x6000000 && g_isAutomaticGameplayRecording)
|
||||
size -= 0x6000000;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void setupHbHeap(void)
|
||||
{
|
||||
void* addr = NULL;
|
||||
u64 size = calculateMaxHeapSize();
|
||||
|
||||
if (!g_isApplication) {
|
||||
if (g_appletHeapSize) {
|
||||
u64 requested_size = (g_appletHeapSize + 0x1FFFFF) &~ 0x1FFFFF;
|
||||
if (requested_size < size)
|
||||
size = requested_size;
|
||||
}
|
||||
else if (g_appletHeapReservationSize) {
|
||||
u64 reserved_size = (g_appletHeapReservationSize + 0x1FFFFF) &~ 0x1FFFFF;
|
||||
if (reserved_size < size)
|
||||
size -= reserved_size;
|
||||
}
|
||||
}
|
||||
|
||||
Result rc = svcSetHeapSize(&addr, size);
|
||||
|
||||
if (R_FAILED(rc) || addr==NULL)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 9));
|
||||
|
||||
g_heapAddr = addr;
|
||||
g_heapSize = size;
|
||||
}
|
||||
|
||||
static Handle g_procHandle;
|
||||
|
||||
static void procHandleReceiveThread(void* arg)
|
||||
{
|
||||
Handle session = (Handle)(uintptr_t)arg;
|
||||
Result rc;
|
||||
|
||||
u32* tls = (u32*)armGetTls();
|
||||
tls[0] = 0;
|
||||
tls[1] = 0;
|
||||
|
||||
s32 idx = 0;
|
||||
rc = svcReplyAndReceive(&idx, &session, 1, INVALID_HANDLE, UINT64_MAX);
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 15));
|
||||
|
||||
IpcParsedCommand ipc;
|
||||
rc = ipcParse(&ipc);
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 16));
|
||||
|
||||
if (ipc.NumHandles != 1)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 17));
|
||||
|
||||
g_procHandle = ipc.Handles[0];
|
||||
svcCloseHandle(session);
|
||||
}
|
||||
|
||||
//Gets the PID of the process with application_type==APPLICATION in the NPDM, then sets g_isApplication if it matches the current PID.
|
||||
static void getIsApplication(void) {
|
||||
Result rc=0;
|
||||
u64 cur_pid=0, app_pid=0;
|
||||
|
||||
g_isApplication = 0;
|
||||
|
||||
rc = svcGetProcessId(&cur_pid, CUR_PROCESS_HANDLE);
|
||||
if (R_FAILED(rc)) return;
|
||||
|
||||
rc = pmshellInitialize();
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = pmshellGetApplicationPid(&app_pid);
|
||||
pmshellExit();
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc) && cur_pid == app_pid) g_isApplication = 1;
|
||||
}
|
||||
|
||||
//Gets the control.nacp for the current title id, and then sets g_isAutomaticGameplayRecording if less memory should be allocated.
|
||||
static void getIsAutomaticGameplayRecording(void) {
|
||||
if (hosversionAtLeast(5,0,0) && g_isApplication) {
|
||||
Result rc=0;
|
||||
u64 cur_tid=0;
|
||||
|
||||
rc = svcGetInfo(&cur_tid, InfoType_TitleId, CUR_PROCESS_HANDLE, 0);
|
||||
if (R_FAILED(rc)) return;
|
||||
|
||||
g_isAutomaticGameplayRecording = 0;
|
||||
|
||||
rc = nsInitialize();
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
size_t dummy;
|
||||
rc = nsGetApplicationControlData(0x1, cur_tid, &g_applicationControlData, sizeof(g_applicationControlData), &dummy);
|
||||
nsExit();
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc) && g_applicationControlData.nacp.videoCaptureMode == 2) g_isAutomaticGameplayRecording = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void getOwnProcessHandle(void)
|
||||
{
|
||||
static Thread t;
|
||||
Result rc;
|
||||
|
||||
Handle server_handle, client_handle;
|
||||
rc = svcCreateSession(&server_handle, &client_handle, 0, 0);
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 12));
|
||||
|
||||
rc = threadCreate(&t, &procHandleReceiveThread, (void*)(uintptr_t)server_handle, 0x1000, 0x20, 0);
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 10));
|
||||
|
||||
rc = threadStart(&t);
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 13));
|
||||
|
||||
IpcCommand ipc;
|
||||
ipcInitialize(&ipc);
|
||||
ipcSendHandleCopy(&ipc, CUR_PROCESS_HANDLE);
|
||||
ipcPrepareHeader(&ipc, 0);
|
||||
|
||||
ipcDispatch(client_handle);
|
||||
svcCloseHandle(client_handle);
|
||||
|
||||
threadWaitForExit(&t);
|
||||
threadClose(&t);
|
||||
}
|
||||
|
||||
void loadNro(void)
|
||||
{
|
||||
if(g_targetCounter >= 0)
|
||||
{
|
||||
if(g_targetCounter == 0) exit(0);
|
||||
g_targetCounter--;
|
||||
}
|
||||
|
||||
NroHeader* header = NULL;
|
||||
size_t rw_size=0;
|
||||
Result rc=0;
|
||||
|
||||
if (g_smCloseWorkaround) {
|
||||
// For old applications, wait for SM to handle closing the SM session from this process.
|
||||
// If we don't do this, smInitialize will fail once eventually used later.
|
||||
// This is caused by a bug in old versions of libnx that was fixed in commit 68a77ac950.
|
||||
g_smCloseWorkaround = false;
|
||||
svcSleepThread(1000000000);
|
||||
}
|
||||
|
||||
memcpy((u8*)armGetTls() + 0x100, g_savedTls, 0x100);
|
||||
|
||||
if (g_nroSize > 0)
|
||||
{
|
||||
// Unmap previous NRO.
|
||||
header = &g_nroHeader;
|
||||
rw_size = header->segments[2].size + header->bss_size;
|
||||
rw_size = (rw_size+0xFFF) & ~0xFFF;
|
||||
|
||||
// .text
|
||||
rc = svcUnmapProcessCodeMemory(
|
||||
g_procHandle, g_nroAddr + header->segments[0].file_off, ((u64) g_heapAddr) + header->segments[0].file_off, header->segments[0].size);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 24));
|
||||
|
||||
// .rodata
|
||||
rc = svcUnmapProcessCodeMemory(
|
||||
g_procHandle, g_nroAddr + header->segments[1].file_off, ((u64) g_heapAddr) + header->segments[1].file_off, header->segments[1].size);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 25));
|
||||
|
||||
// .data + .bss
|
||||
rc = svcUnmapProcessCodeMemory(
|
||||
g_procHandle, g_nroAddr + header->segments[2].file_off, ((u64) g_heapAddr) + header->segments[2].file_off, rw_size);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 26));
|
||||
|
||||
g_nroAddr = g_nroSize = 0;
|
||||
}
|
||||
|
||||
if (strlen(g_nextNroPath) == 0)
|
||||
{
|
||||
strcpy(g_nextNroPath, g_basePath);
|
||||
strcpy(g_nextArgv, g_baseArgv);
|
||||
}
|
||||
|
||||
memcpy(g_argv, g_nextArgv, sizeof g_argv);
|
||||
|
||||
uint8_t *nrobuf = (uint8_t*) g_heapAddr;
|
||||
|
||||
NroStart* start = (NroStart*) (nrobuf + 0);
|
||||
header = (NroHeader*) (nrobuf + sizeof(NroStart));
|
||||
uint8_t* rest = (uint8_t*) (nrobuf + sizeof(NroStart) + sizeof(NroHeader));
|
||||
|
||||
FILE* f = fopen(g_nextNroPath, "rb");
|
||||
if (f == NULL)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 3));
|
||||
|
||||
// Reset NRO path to load hbmenu by default next time.
|
||||
g_nextNroPath[0] = '\0';
|
||||
|
||||
if (fread(start, sizeof(*start), 1, f) != 1)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 4));
|
||||
|
||||
if (fread(header, sizeof(*header), 1, f) != 1)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 4));
|
||||
|
||||
if(header->magic != NROHEADER_MAGIC)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 5));
|
||||
|
||||
size_t rest_size = header->size - (sizeof(NroStart) + sizeof(NroHeader));
|
||||
if (fread(rest, rest_size, 1, f) != 1)
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 7));
|
||||
|
||||
fclose(f);
|
||||
|
||||
size_t total_size = header->size + header->bss_size;
|
||||
total_size = (total_size+0xFFF) & ~0xFFF;
|
||||
|
||||
rw_size = header->segments[2].size + header->bss_size;
|
||||
rw_size = (rw_size+0xFFF) & ~0xFFF;
|
||||
|
||||
bool has_mod0 = false;
|
||||
if (start->mod_offset > 0 && start->mod_offset <= (total_size-0x24)) // Validate MOD0 offset
|
||||
has_mod0 = *(uint32_t*)(nrobuf + start->mod_offset) == 0x30444F4D; // Validate MOD0 header
|
||||
|
||||
int i;
|
||||
for (i=0; i<3; i++)
|
||||
{
|
||||
if (header->segments[i].file_off >= header->size || header->segments[i].size > header->size ||
|
||||
(header->segments[i].file_off + header->segments[i].size) > header->size)
|
||||
{
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 6));
|
||||
}
|
||||
}
|
||||
|
||||
// todo: Detect whether NRO fits into heap or not.
|
||||
|
||||
// Copy header to elsewhere because we're going to unmap it next.
|
||||
memcpy(&g_nroHeader, header, sizeof(g_nroHeader));
|
||||
header = &g_nroHeader;
|
||||
|
||||
u64 map_addr;
|
||||
|
||||
do {
|
||||
map_addr = randomGet64() & 0xFFFFFF000ull;
|
||||
rc = svcMapProcessCodeMemory(g_procHandle, map_addr, (u64)nrobuf, total_size);
|
||||
|
||||
} while (rc == 0xDC01 || rc == 0xD401);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 18));
|
||||
|
||||
// .text
|
||||
rc = svcSetProcessMemoryPermission(
|
||||
g_procHandle, map_addr + header->segments[0].file_off, header->segments[0].size, Perm_R | Perm_X);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 19));
|
||||
|
||||
// .rodata
|
||||
rc = svcSetProcessMemoryPermission(
|
||||
g_procHandle, map_addr + header->segments[1].file_off, header->segments[1].size, Perm_R);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 20));
|
||||
|
||||
// .data + .bss
|
||||
rc = svcSetProcessMemoryPermission(
|
||||
g_procHandle, map_addr + header->segments[2].file_off, rw_size, Perm_Rw);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_HomebrewLoader, 21));
|
||||
|
||||
u64 nro_size = header->segments[2].file_off + rw_size;
|
||||
u64 nro_heap_start = ((u64) g_heapAddr) + nro_size;
|
||||
u64 nro_heap_size = g_heapSize + (u64) g_heapAddr - (u64) nro_heap_start;
|
||||
|
||||
#define M EntryFlag_IsMandatory
|
||||
|
||||
static ConfigEntry entries[] = {
|
||||
{ EntryType_MainThreadHandle, 0, {0, 0} },
|
||||
{ EntryType_ProcessHandle, 0, {0, 0} },
|
||||
{ EntryType_AppletType, 0, {AppletType_LibraryApplet, 0} },
|
||||
{ EntryType_OverrideHeap, M, {0, 0} },
|
||||
{ EntryType_Argv, 0, {0, 0} },
|
||||
{ EntryType_NextLoadPath, 0, {0, 0} },
|
||||
{ EntryType_LastLoadResult, 0, {0, 0} },
|
||||
{ EntryType_SyscallAvailableHint, 0, {0xffffffffffffffff, 0x9fc1fff0007ffff} },
|
||||
{ EntryType_RandomSeed, 0, {0, 0} },
|
||||
{ EntryType_UserIdStorage, 0, {(u64)(uintptr_t)&g_userIdStorage, 0} },
|
||||
{ EntryType_HosVersion, 0, {0, 0} },
|
||||
{ EntryType_EndOfList, 0, {(u64)(uintptr_t)g_noticeText, sizeof(g_noticeText)} }
|
||||
};
|
||||
|
||||
ConfigEntry *entry_AppletType = &entries[2];
|
||||
|
||||
if (g_isApplication) {
|
||||
entry_AppletType->Value[0] = AppletType_SystemApplication;
|
||||
entry_AppletType->Value[1] = EnvAppletFlags_ApplicationOverride;
|
||||
}
|
||||
|
||||
// MainThreadHandle
|
||||
entries[0].Value[0] = envGetMainThreadHandle();
|
||||
// ProcessHandle
|
||||
entries[1].Value[0] = g_procHandle;
|
||||
// OverrideHeap
|
||||
entries[3].Value[0] = nro_heap_start;
|
||||
entries[3].Value[1] = nro_heap_size;
|
||||
// Argv
|
||||
entries[4].Value[1] = (u64) &g_argv[0];
|
||||
// NextLoadPath
|
||||
entries[5].Value[0] = (u64) &g_nextNroPath[0];
|
||||
entries[5].Value[1] = (u64) &g_nextArgv[0];
|
||||
// LastLoadResult
|
||||
entries[6].Value[0] = g_lastRet;
|
||||
// RandomSeed
|
||||
entries[8].Value[0] = randomGet64();
|
||||
entries[8].Value[1] = randomGet64();
|
||||
// HosVersion
|
||||
entries[10].Value[0] = hosversionGet();
|
||||
|
||||
u64 entrypoint = map_addr;
|
||||
|
||||
g_nroAddr = map_addr;
|
||||
g_nroSize = nro_size;
|
||||
|
||||
memset(__stack_top - STACK_SIZE, 0, STACK_SIZE);
|
||||
|
||||
if (!has_mod0) {
|
||||
// Apply sm-close workaround to NROs which do not contain a valid MOD0 header.
|
||||
// This heuristic is based on the fact that MOD0 support was added very shortly after
|
||||
// the fix for the sm-close bug (in fact, two commits later).
|
||||
g_smCloseWorkaround = true;
|
||||
}
|
||||
|
||||
extern NORETURN void hbTargetImpl(u64 entries_ptr, u64 handle, u64 entrypoint);
|
||||
hbTargetImpl((u64) entries, -1, entrypoint);
|
||||
}
|
||||
|
||||
static void InnerTarget(const char *path, const char *argv)
|
||||
{
|
||||
memcpy(g_savedTls, (u8*)armGetTls() + 0x100, 0x100);
|
||||
strcpy(g_basePath, path);
|
||||
strcpy(g_baseArgv, argv);
|
||||
|
||||
getIsApplication();
|
||||
getIsAutomaticGameplayRecording();
|
||||
smExit(); // Close SM as we don't need it anymore.
|
||||
setupHbHeap();
|
||||
getOwnProcessHandle();
|
||||
|
||||
loadNro();
|
||||
}
|
||||
|
||||
void hb_hbl_Target(const char *path, const char *argv, int counter)
|
||||
{
|
||||
g_targetCounter = counter;
|
||||
InnerTarget(path, argv);
|
||||
}
|
51
Common/Source/hb/hb_hbl_trampoline.s
Normal file
51
Common/Source/hb/hb_hbl_trampoline.s
Normal file
|
@ -0,0 +1,51 @@
|
|||
.section .text.hbTargetImpl, "ax", %progbits
|
||||
|
||||
.global hbTargetImpl
|
||||
.type hbTargetImpl, %function
|
||||
.align 2
|
||||
|
||||
.global __libnx_exception_entry
|
||||
.type __libnx_exception_entry, %function
|
||||
|
||||
.cfi_startproc
|
||||
|
||||
hbTargetImpl:
|
||||
|
||||
// Reset stack pointer.
|
||||
adrp x8, __stack_top //Defined in libnx.
|
||||
ldr x8, [x8, #:lo12:__stack_top]
|
||||
mov sp, x8
|
||||
|
||||
// Call NRO.
|
||||
blr x2
|
||||
|
||||
// Save retval
|
||||
adrp x1, g_lastRet
|
||||
str w0, [x1, #:lo12:g_lastRet]
|
||||
|
||||
// Reset stack pointer and load next NRO.
|
||||
adrp x8, __stack_top
|
||||
ldr x8, [x8, #:lo12:__stack_top]
|
||||
mov sp, x8
|
||||
|
||||
b loadNro
|
||||
|
||||
.cfi_endproc
|
||||
|
||||
.section .text.__libnx_exception_entry, "ax", %progbits
|
||||
.align 2
|
||||
|
||||
.cfi_startproc
|
||||
|
||||
__libnx_exception_entry:
|
||||
adrp x7, g_nroAddr
|
||||
ldr x7, [x7, #:lo12:g_nroAddr]
|
||||
cbz x7, __libnx_exception_entry_fail
|
||||
br x7
|
||||
|
||||
__libnx_exception_entry_fail:
|
||||
mov w0, #0xf801
|
||||
bl svcReturnFromException
|
||||
b .
|
||||
|
||||
.cfi_endproc
|
163
LibraryAppletQHbTarget/LibraryAppletQHbTarget.json
Normal file
163
LibraryAppletQHbTarget/LibraryAppletQHbTarget.json
Normal file
|
@ -0,0 +1,163 @@
|
|||
{
|
||||
"name": "QHbTarget",
|
||||
"title_id": "0xFFFFFFFFFFFFFFFF",
|
||||
"title_id_range_min": "0xFFFFFFFFFFFFFFFF",
|
||||
"title_id_range_max": "0xFFFFFFFFFFFFFFFF",
|
||||
"main_thread_stack_size": "0x100000",
|
||||
"main_thread_priority": 44,
|
||||
"default_cpu_id": 0,
|
||||
"process_category": 0,
|
||||
"pool_partition": 0,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 1,
|
||||
"is_retail": true,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
"service_host": [
|
||||
"*"
|
||||
],
|
||||
"service_access": [
|
||||
"*"
|
||||
],
|
||||
"kernel_capabilities": [
|
||||
{
|
||||
"type": "kernel_flags",
|
||||
"value": {
|
||||
"highest_thread_priority": 59,
|
||||
"lowest_thread_priority": 28,
|
||||
"highest_cpu_id": 2,
|
||||
"lowest_cpu_id": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
"svcUnknown00": "0x00",
|
||||
"svcSetHeapSize": "0x01",
|
||||
"svcSetMemoryPermission": "0x02",
|
||||
"svcSetMemoryAttribute": "0x03",
|
||||
"svcMapMemory": "0x04",
|
||||
"svcUnmapMemory": "0x05",
|
||||
"svcQueryMemory": "0x06",
|
||||
"svcExitProcess": "0x07",
|
||||
"svcCreateThread": "0x08",
|
||||
"svcStartThread": "0x09",
|
||||
"svcExitThread": "0x0A",
|
||||
"svcSleepThread": "0x0B",
|
||||
"svcGetThreadPriority": "0x0C",
|
||||
"svcSetThreadPriority": "0x0D",
|
||||
"svcGetThreadCoreMask": "0x0E",
|
||||
"svcSetThreadCoreMask": "0x0F",
|
||||
"svcGetCurrentProcessorNumber": "0x10",
|
||||
"svcSignalEvent": "0x11",
|
||||
"svcClearEvent": "0x12",
|
||||
"svcMapSharedMemory": "0x13",
|
||||
"svcUnmapSharedMemory": "0x14",
|
||||
"svcCreateTransferMemory": "0x15",
|
||||
"svcCloseHandle": "0x16",
|
||||
"svcResetSignal": "0x17",
|
||||
"svcWaitSynchronization": "0x18",
|
||||
"svcCancelSynchronization": "0x19",
|
||||
"svcArbitrateLock": "0x1A",
|
||||
"svcArbitrateUnlock": "0x1B",
|
||||
"svcWaitProcessWideKeyAtomic": "0x1C",
|
||||
"svcSignalProcessWideKey": "0x1D",
|
||||
"svcGetSystemTick": "0x1E",
|
||||
"svcConnectToNamedPort": "0x1F",
|
||||
"svcSendSyncRequestLight": "0x20",
|
||||
"svcSendSyncRequest": "0x21",
|
||||
"svcSendSyncRequestWithUserBuffer": "0x22",
|
||||
"svcSendAsyncRequestWithUserBuffer": "0x23",
|
||||
"svcGetProcessId": "0x24",
|
||||
"svcGetThreadId": "0x25",
|
||||
"svcBreak": "0x26",
|
||||
"svcOutputDebugString": "0x27",
|
||||
"svcReturnFromException": "0x28",
|
||||
"svcGetInfo": "0x29",
|
||||
"svcFlushEntireDataCache": "0x2A",
|
||||
"svcFlushDataCache": "0x2B",
|
||||
"svcMapPhysicalMemory": "0x2C",
|
||||
"svcUnmapPhysicalMemory": "0x2D",
|
||||
"svcGetFutureThreadInfo": "0x2E",
|
||||
"svcGetLastThreadInfo": "0x2F",
|
||||
"svcGetResourceLimitLimitValue": "0x30",
|
||||
"svcGetResourceLimitCurrentValue": "0x31",
|
||||
"svcSetThreadActivity": "0x32",
|
||||
"svcGetThreadContext3": "0x33",
|
||||
"svcWaitForAddress": "0x34",
|
||||
"svcSignalToAddress": "0x35",
|
||||
"svcUnknown36": "0x36",
|
||||
"svcUnknown37": "0x37",
|
||||
"svcUnknown38": "0x38",
|
||||
"svcUnknown39": "0x39",
|
||||
"svcUnknown3a": "0x3A",
|
||||
"svcUnknown3b": "0x3B",
|
||||
"svcDumpInfo": "0x3C",
|
||||
"svcDumpInfoNew": "0x3D",
|
||||
"svcUnknown3e": "0x3E",
|
||||
"svcUnknown3f": "0x3F",
|
||||
"svcCreateSession": "0x40",
|
||||
"svcAcceptSession": "0x41",
|
||||
"svcReplyAndReceiveLight": "0x42",
|
||||
"svcReplyAndReceive": "0x43",
|
||||
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
||||
"svcCreateEvent": "0x45",
|
||||
"svcUnknown46": "0x46",
|
||||
"svcUnknown47": "0x47",
|
||||
"svcMapPhysicalMemoryUnsafe": "0x48",
|
||||
"svcUnmapPhysicalMemoryUnsafe": "0x49",
|
||||
"svcSetUnsafeLimit": "0x4A",
|
||||
"svcCreateCodeMemory": "0x4B",
|
||||
"svcControlCodeMemory": "0x4C",
|
||||
"svcSleepSystem": "0x4D",
|
||||
"svcReadWriteRegister": "0x4E",
|
||||
"svcSetProcessActivity": "0x4F",
|
||||
"svcCreateSharedMemory": "0x50",
|
||||
"svcMapTransferMemory": "0x51",
|
||||
"svcUnmapTransferMemory": "0x52",
|
||||
"svcDebugActiveProcess": "0x60",
|
||||
"svcBreakDebugProcess": "0x61",
|
||||
"svcTerminateDebugProcess": "0x62",
|
||||
"svcGetDebugEvent": "0x63",
|
||||
"svcContinueDebugEvent": "0x64",
|
||||
"svcGetProcessList": "0x65",
|
||||
"svcGetThreadList": "0x66",
|
||||
"svcGetDebugThreadContext": "0x67",
|
||||
"svcSetDebugThreadContext": "0x68",
|
||||
"svcQueryDebugProcessMemory": "0x69",
|
||||
"svcReadDebugProcessMemory": "0x6A",
|
||||
"svcWriteDebugProcessMemory": "0x6B",
|
||||
"svcSetHardwareBreakPoint": "0x6C",
|
||||
"svcGetDebugThreadParam": "0x6D",
|
||||
"svcConnectToPort": "0x72",
|
||||
"svcSetProcessMemoryPermission": "0x73",
|
||||
"svcMapProcessMemory": "0x74",
|
||||
"svcUnmapProcessMemory": "0x75",
|
||||
"svcQueryProcessMemory": "0x76",
|
||||
"svcMapProcessCodeMemory": "0x77",
|
||||
"svcUnmapProcessCodeMemory": "0x78",
|
||||
"svcCallSecureMonitor": "0x7F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "application_type",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"type": "min_kernel_version",
|
||||
"value": "0x30"
|
||||
},
|
||||
{
|
||||
"type": "handle_table_size",
|
||||
"value": 512
|
||||
},
|
||||
{
|
||||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": true,
|
||||
"force_debug": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
183
LibraryAppletQHbTarget/Makefile
Normal file
183
LibraryAppletQHbTarget/Makefile
Normal file
|
@ -0,0 +1,183 @@
|
|||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := ../Common/Source ../Common/Source/am ../Common/Source/cfg ../Common/Source/db ../Common/Source/fs ../Common/Source/hb ../Common/Source/os ../Common/Source/util Source Source/ui
|
||||
DATA := data
|
||||
INCLUDES := ../Common/Include Include
|
||||
EXEFS_SRC := exefs_src
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||
|
||||
ifeq ($(strip $(CONFIG_JSON)),)
|
||||
jsons := $(wildcard *.json)
|
||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||
else
|
||||
ifneq (,$(findstring config.json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/config.json
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@rm -rf $(CURDIR)/Out
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
@mkdir -p $(CURDIR)/Out
|
||||
@cp $(OUTPUT).nsp $(CURDIR)/Out/exefs.nsp
|
||||
@touch $(CURDIR)/Out/fsmitm.flag
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(CURDIR)/Out $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
all : $(OUTPUT).nsp
|
||||
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso
|
||||
else
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||
endif
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
48
LibraryAppletQHbTarget/Source/Main.cpp
Normal file
48
LibraryAppletQHbTarget/Source/Main.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include <hb/hb_Target.hpp>
|
||||
#include <am/am_QCommunications.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
u32 __nx_applet_type = AppletType_LibraryApplet;
|
||||
u32 __nx_applet_exit_mode = 2;
|
||||
}
|
||||
|
||||
hb::TargetInput hb_input;
|
||||
bool target_once = true; // Library applet targets once
|
||||
|
||||
int main()
|
||||
{
|
||||
hb_input = {};
|
||||
|
||||
hb_input.nro_path[0] = '\0';
|
||||
hb_input.argv[0] = '\0';
|
||||
|
||||
// Initialize applet, read stuff, close applet
|
||||
appletInitialize();
|
||||
LibAppletArgs largs;
|
||||
auto rc = am::QLibraryAppletReadStorage(&largs, sizeof(largs));
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
if(largs.LaVersion == am::Magic)
|
||||
{
|
||||
hb::TargetInput ipt = {};
|
||||
rc = am::QLibraryAppletReadStorage(&ipt, sizeof(ipt));
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
if(strlen(ipt.nro_path))
|
||||
{
|
||||
strcpy(hb_input.nro_path, ipt.nro_path);
|
||||
if(strlen(ipt.argv)) strcpy(hb_input.argv, ipt.argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appletExit();
|
||||
|
||||
if(hb_input.nro_path[0] == '\0') strcpy(hb_input.nro_path, "sdmc:/hbmenu.nro");
|
||||
if(hb_input.argv[0] == '\0') strcpy(hb_input.argv, hb_input.nro_path);
|
||||
|
||||
hb::Target(hb_input, target_once);
|
||||
|
||||
return 0;
|
||||
}
|
7
LibraryAppletQMenu/RomFs/default/theme/Manifest.json
Normal file
7
LibraryAppletQMenu/RomFs/default/theme/Manifest.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "Default theme",
|
||||
"format_version": 0,
|
||||
"release": "Dev",
|
||||
"description": "Default <qlaunch reimpl> theme",
|
||||
"author": "XorTroll"
|
||||
}
|
3
LibraryAppletQMenu/RomFs/default/ui/UI.json
Normal file
3
LibraryAppletQMenu/RomFs/default/ui/UI.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"suspended_final_alpha": 80
|
||||
}
|
183
SystemApplicationQHbTarget/Makefile
Normal file
183
SystemApplicationQHbTarget/Makefile
Normal file
|
@ -0,0 +1,183 @@
|
|||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := ../Common/Source ../Common/Source/am ../Common/Source/cfg ../Common/Source/db ../Common/Source/fs ../Common/Source/hb ../Common/Source/os ../Common/Source/util Source Source/ui
|
||||
DATA := data
|
||||
INCLUDES := ../Common/Include Include
|
||||
EXEFS_SRC := exefs_src
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||
|
||||
ifeq ($(strip $(CONFIG_JSON)),)
|
||||
jsons := $(wildcard *.json)
|
||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||
else
|
||||
ifneq (,$(findstring config.json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/config.json
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@rm -rf $(CURDIR)/Out
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
@mkdir -p $(CURDIR)/Out
|
||||
@cp $(OUTPUT).nsp $(CURDIR)/Out/exefs.nsp
|
||||
@touch $(CURDIR)/Out/fsmitm.flag
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(CURDIR)/Out $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
all : $(OUTPUT).nsp
|
||||
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso
|
||||
else
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||
endif
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
40
SystemApplicationQHbTarget/Source/Main.cpp
Normal file
40
SystemApplicationQHbTarget/Source/Main.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include <hb/hb_Target.hpp>
|
||||
#include <am/am_QCommunications.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
u32 __nx_applet_type = AppletType_SystemApplication;
|
||||
u32 __nx_applet_exit_mode = 2;
|
||||
}
|
||||
|
||||
hb::TargetInput hb_input;
|
||||
bool target_once = false; // The application system allows classic hbl-ish system to exit to hbmenu
|
||||
|
||||
int main()
|
||||
{
|
||||
hb_input = {};
|
||||
|
||||
hb_input.nro_path[0] = '\0';
|
||||
hb_input.argv[0] = '\0';
|
||||
|
||||
// Initialize applet, read stuff, close applet
|
||||
appletInitialize();
|
||||
hb::TargetInput ipt = {};
|
||||
auto rc = am::QApplicationReadStorage(&ipt, sizeof(ipt));
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
if(strlen(ipt.nro_path))
|
||||
{
|
||||
strcpy(hb_input.nro_path, ipt.nro_path);
|
||||
if(strlen(ipt.argv)) strcpy(hb_input.argv, ipt.argv);
|
||||
}
|
||||
}
|
||||
appletExit();
|
||||
|
||||
if(hb_input.nro_path[0] == '\0') strcpy(hb_input.nro_path, "sdmc:/hbmenu.nro");
|
||||
if(hb_input.argv[0] == '\0') strcpy(hb_input.argv, hb_input.nro_path);
|
||||
|
||||
hb::Target(hb_input, target_once);
|
||||
|
||||
return 0;
|
||||
}
|
163
SystemApplicationQHbTarget/SystemApplicationQHbTarget.json
Normal file
163
SystemApplicationQHbTarget/SystemApplicationQHbTarget.json
Normal file
|
@ -0,0 +1,163 @@
|
|||
{
|
||||
"name": "QHbTarget",
|
||||
"title_id": "0xFFFFFFFFFFFFFFFF",
|
||||
"title_id_range_min": "0xFFFFFFFFFFFFFFFF",
|
||||
"title_id_range_max": "0xFFFFFFFFFFFFFFFF",
|
||||
"main_thread_stack_size": "0x100000",
|
||||
"main_thread_priority": 44,
|
||||
"default_cpu_id": 0,
|
||||
"process_category": 0,
|
||||
"pool_partition": 0,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 1,
|
||||
"is_retail": true,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
"service_host": [
|
||||
"*"
|
||||
],
|
||||
"service_access": [
|
||||
"*"
|
||||
],
|
||||
"kernel_capabilities": [
|
||||
{
|
||||
"type": "kernel_flags",
|
||||
"value": {
|
||||
"highest_thread_priority": 59,
|
||||
"lowest_thread_priority": 28,
|
||||
"highest_cpu_id": 2,
|
||||
"lowest_cpu_id": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
"svcUnknown00": "0x00",
|
||||
"svcSetHeapSize": "0x01",
|
||||
"svcSetMemoryPermission": "0x02",
|
||||
"svcSetMemoryAttribute": "0x03",
|
||||
"svcMapMemory": "0x04",
|
||||
"svcUnmapMemory": "0x05",
|
||||
"svcQueryMemory": "0x06",
|
||||
"svcExitProcess": "0x07",
|
||||
"svcCreateThread": "0x08",
|
||||
"svcStartThread": "0x09",
|
||||
"svcExitThread": "0x0A",
|
||||
"svcSleepThread": "0x0B",
|
||||
"svcGetThreadPriority": "0x0C",
|
||||
"svcSetThreadPriority": "0x0D",
|
||||
"svcGetThreadCoreMask": "0x0E",
|
||||
"svcSetThreadCoreMask": "0x0F",
|
||||
"svcGetCurrentProcessorNumber": "0x10",
|
||||
"svcSignalEvent": "0x11",
|
||||
"svcClearEvent": "0x12",
|
||||
"svcMapSharedMemory": "0x13",
|
||||
"svcUnmapSharedMemory": "0x14",
|
||||
"svcCreateTransferMemory": "0x15",
|
||||
"svcCloseHandle": "0x16",
|
||||
"svcResetSignal": "0x17",
|
||||
"svcWaitSynchronization": "0x18",
|
||||
"svcCancelSynchronization": "0x19",
|
||||
"svcArbitrateLock": "0x1A",
|
||||
"svcArbitrateUnlock": "0x1B",
|
||||
"svcWaitProcessWideKeyAtomic": "0x1C",
|
||||
"svcSignalProcessWideKey": "0x1D",
|
||||
"svcGetSystemTick": "0x1E",
|
||||
"svcConnectToNamedPort": "0x1F",
|
||||
"svcSendSyncRequestLight": "0x20",
|
||||
"svcSendSyncRequest": "0x21",
|
||||
"svcSendSyncRequestWithUserBuffer": "0x22",
|
||||
"svcSendAsyncRequestWithUserBuffer": "0x23",
|
||||
"svcGetProcessId": "0x24",
|
||||
"svcGetThreadId": "0x25",
|
||||
"svcBreak": "0x26",
|
||||
"svcOutputDebugString": "0x27",
|
||||
"svcReturnFromException": "0x28",
|
||||
"svcGetInfo": "0x29",
|
||||
"svcFlushEntireDataCache": "0x2A",
|
||||
"svcFlushDataCache": "0x2B",
|
||||
"svcMapPhysicalMemory": "0x2C",
|
||||
"svcUnmapPhysicalMemory": "0x2D",
|
||||
"svcGetFutureThreadInfo": "0x2E",
|
||||
"svcGetLastThreadInfo": "0x2F",
|
||||
"svcGetResourceLimitLimitValue": "0x30",
|
||||
"svcGetResourceLimitCurrentValue": "0x31",
|
||||
"svcSetThreadActivity": "0x32",
|
||||
"svcGetThreadContext3": "0x33",
|
||||
"svcWaitForAddress": "0x34",
|
||||
"svcSignalToAddress": "0x35",
|
||||
"svcUnknown36": "0x36",
|
||||
"svcUnknown37": "0x37",
|
||||
"svcUnknown38": "0x38",
|
||||
"svcUnknown39": "0x39",
|
||||
"svcUnknown3a": "0x3A",
|
||||
"svcUnknown3b": "0x3B",
|
||||
"svcDumpInfo": "0x3C",
|
||||
"svcDumpInfoNew": "0x3D",
|
||||
"svcUnknown3e": "0x3E",
|
||||
"svcUnknown3f": "0x3F",
|
||||
"svcCreateSession": "0x40",
|
||||
"svcAcceptSession": "0x41",
|
||||
"svcReplyAndReceiveLight": "0x42",
|
||||
"svcReplyAndReceive": "0x43",
|
||||
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
||||
"svcCreateEvent": "0x45",
|
||||
"svcUnknown46": "0x46",
|
||||
"svcUnknown47": "0x47",
|
||||
"svcMapPhysicalMemoryUnsafe": "0x48",
|
||||
"svcUnmapPhysicalMemoryUnsafe": "0x49",
|
||||
"svcSetUnsafeLimit": "0x4A",
|
||||
"svcCreateCodeMemory": "0x4B",
|
||||
"svcControlCodeMemory": "0x4C",
|
||||
"svcSleepSystem": "0x4D",
|
||||
"svcReadWriteRegister": "0x4E",
|
||||
"svcSetProcessActivity": "0x4F",
|
||||
"svcCreateSharedMemory": "0x50",
|
||||
"svcMapTransferMemory": "0x51",
|
||||
"svcUnmapTransferMemory": "0x52",
|
||||
"svcDebugActiveProcess": "0x60",
|
||||
"svcBreakDebugProcess": "0x61",
|
||||
"svcTerminateDebugProcess": "0x62",
|
||||
"svcGetDebugEvent": "0x63",
|
||||
"svcContinueDebugEvent": "0x64",
|
||||
"svcGetProcessList": "0x65",
|
||||
"svcGetThreadList": "0x66",
|
||||
"svcGetDebugThreadContext": "0x67",
|
||||
"svcSetDebugThreadContext": "0x68",
|
||||
"svcQueryDebugProcessMemory": "0x69",
|
||||
"svcReadDebugProcessMemory": "0x6A",
|
||||
"svcWriteDebugProcessMemory": "0x6B",
|
||||
"svcSetHardwareBreakPoint": "0x6C",
|
||||
"svcGetDebugThreadParam": "0x6D",
|
||||
"svcConnectToPort": "0x72",
|
||||
"svcSetProcessMemoryPermission": "0x73",
|
||||
"svcMapProcessMemory": "0x74",
|
||||
"svcUnmapProcessMemory": "0x75",
|
||||
"svcQueryProcessMemory": "0x76",
|
||||
"svcMapProcessCodeMemory": "0x77",
|
||||
"svcUnmapProcessCodeMemory": "0x78",
|
||||
"svcCallSecureMonitor": "0x7F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "application_type",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"type": "min_kernel_version",
|
||||
"value": "0x30"
|
||||
},
|
||||
{
|
||||
"type": "handle_table_size",
|
||||
"value": 512
|
||||
},
|
||||
{
|
||||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": true,
|
||||
"force_debug": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue