mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2025-02-22 16:36:13 +00:00
Improve thread-safety.
This commit is contained in:
parent
d4872ce6d3
commit
2e48a22f8c
11 changed files with 528 additions and 342 deletions
|
@ -31,6 +31,7 @@
|
|||
/* Global variables. */
|
||||
|
||||
static save_ctx_t *g_esCertSaveCtx = NULL;
|
||||
static Mutex g_esCertSaveMutex = 0;
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
|
@ -48,35 +49,49 @@ static void certCopyCertificateChainDataToMemoryBuffer(void *dst, const Certific
|
|||
|
||||
bool certRetrieveCertificateByName(Certificate *dst, const char *name)
|
||||
{
|
||||
mutexLock(&g_esCertSaveMutex);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (!dst || !name || !strlen(name))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!certOpenEsCertSaveFile()) return false;
|
||||
if (!certOpenEsCertSaveFile()) goto exit;
|
||||
|
||||
bool ret = _certRetrieveCertificateByName(dst, name);
|
||||
ret = _certRetrieveCertificateByName(dst, name);
|
||||
|
||||
certCloseEsCertSaveFile();
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_esCertSaveMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst, const char *issuer)
|
||||
{
|
||||
mutexLock(&g_esCertSaveMutex);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (!dst || !issuer || !strlen(issuer) || strncmp(issuer, "Root-", 5) != 0)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!certOpenEsCertSaveFile()) return false;
|
||||
if (!certOpenEsCertSaveFile()) goto exit;
|
||||
|
||||
bool ret = _certRetrieveCertificateChainBySignatureIssuer(dst, issuer);
|
||||
ret = _certRetrieveCertificateChainBySignatureIssuer(dst, issuer);
|
||||
|
||||
certCloseEsCertSaveFile();
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_esCertSaveMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <threads.h>
|
||||
|
||||
#include "gamecard.h"
|
||||
#include "service_guard.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define GAMECARD_HFS0_MAGIC 0x48465330 /* "HFS0" */
|
||||
|
@ -76,6 +75,9 @@ typedef struct {
|
|||
|
||||
/* Global variables. */
|
||||
|
||||
static Mutex g_gamecardMutex = 0;
|
||||
static bool g_gamecardInitialized = false;
|
||||
|
||||
static FsDeviceOperator g_deviceOperator = {0};
|
||||
static FsEventNotifier g_gameCardEventNotifier = {0};
|
||||
static Event g_gameCardKernelEvent = {0};
|
||||
|
@ -83,7 +85,6 @@ static bool g_openDeviceOperator = false, g_openEventNotifier = false, g_loadKer
|
|||
|
||||
static thrd_t g_gameCardDetectionThread;
|
||||
static UEvent g_gameCardDetectionThreadExitEvent = {0};
|
||||
static mtx_t g_gameCardSharedDataMutex;
|
||||
static bool g_gameCardDetectionThreadCreated = false, g_gameCardInserted = false, g_gameCardInfoLoaded = false;
|
||||
|
||||
static FsGameCardHandle g_gameCardHandle = {0};
|
||||
|
@ -126,17 +127,123 @@ NX_INLINE char *gamecardGetHashFileSystemNameTable(void *header);
|
|||
NX_INLINE char *gamecardGetHashFileSystemEntryNameByIndex(void *header, u32 idx);
|
||||
NX_INLINE bool gamecardGetHashFileSystemEntryIndexByName(void *header, const char *name, u32 *out_idx);
|
||||
|
||||
/* Service guard used to generate thread-safe initialize + exit functions. */
|
||||
/* I'm using this here even though this actually isn't a real service but who cares, it gets the job done. */
|
||||
NX_GENERATE_SERVICE_GUARD(gamecard);
|
||||
bool gamecardInitialize(void)
|
||||
{
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
Result rc = 0;
|
||||
|
||||
bool ret = g_gamecardInitialized;
|
||||
if (ret) goto out;
|
||||
|
||||
/* Allocate memory for the gamecard read buffer */
|
||||
g_gameCardReadBuf = malloc(GAMECARD_READ_BUFFER_SIZE);
|
||||
if (!g_gameCardReadBuf)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the gamecard read buffer!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open device operator */
|
||||
rc = fsOpenDeviceOperator(&g_deviceOperator);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenDeviceOperator failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_openDeviceOperator = true;
|
||||
|
||||
/* Open gamecard detection event notifier */
|
||||
rc = fsOpenGameCardDetectionEventNotifier(&g_gameCardEventNotifier);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenGameCardDetectionEventNotifier failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_openEventNotifier = true;
|
||||
|
||||
/* Retrieve gamecard detection kernel event */
|
||||
rc = fsEventNotifierGetEventHandle(&g_gameCardEventNotifier, &g_gameCardKernelEvent, true);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsEventNotifierGetEventHandle failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_loadKernelEvent = true;
|
||||
|
||||
/* Create usermode exit event */
|
||||
ueventCreate(&g_gameCardDetectionThreadExitEvent, false);
|
||||
|
||||
/* Create gamecard detection thread */
|
||||
g_gameCardDetectionThreadCreated = gamecardCreateDetectionThread();
|
||||
if (!g_gameCardDetectionThreadCreated)
|
||||
{
|
||||
LOGFILE("Failed to create gamecard detection thread!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = g_gamecardInitialized = true;
|
||||
|
||||
out:
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gamecardExit(void)
|
||||
{
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
/* Destroy gamecard detection thread */
|
||||
if (g_gameCardDetectionThreadCreated)
|
||||
{
|
||||
gamecardDestroyDetectionThread();
|
||||
g_gameCardDetectionThreadCreated = false;
|
||||
}
|
||||
|
||||
/* Close gamecard detection kernel event */
|
||||
if (g_loadKernelEvent)
|
||||
{
|
||||
eventClose(&g_gameCardKernelEvent);
|
||||
g_loadKernelEvent = false;
|
||||
}
|
||||
|
||||
/* Close gamecard detection event notifier */
|
||||
if (g_openEventNotifier)
|
||||
{
|
||||
fsEventNotifierClose(&g_gameCardEventNotifier);
|
||||
g_openEventNotifier = false;
|
||||
}
|
||||
|
||||
/* Close device operator */
|
||||
if (g_openDeviceOperator)
|
||||
{
|
||||
fsDeviceOperatorClose(&g_deviceOperator);
|
||||
g_openDeviceOperator = false;
|
||||
}
|
||||
|
||||
/* Free gamecard read buffer */
|
||||
if (g_gameCardReadBuf)
|
||||
{
|
||||
free(g_gameCardReadBuf);
|
||||
g_gameCardReadBuf = NULL;
|
||||
}
|
||||
|
||||
g_gamecardInitialized = false;
|
||||
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
}
|
||||
|
||||
bool gamecardIsReady(void)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
ret = (g_gameCardInserted && g_gameCardInfoLoaded);
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -150,13 +257,13 @@ bool gamecardGetHeader(GameCardHeader *out)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && out)
|
||||
{
|
||||
memcpy(out, &g_gameCardHeader, sizeof(GameCardHeader));
|
||||
ret = true;
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -165,13 +272,13 @@ bool gamecardGetTotalSize(u64 *out)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && out)
|
||||
{
|
||||
*out = (g_gameCardStorageNormalAreaSize + g_gameCardStorageSecureAreaSize);
|
||||
ret = true;
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -180,13 +287,13 @@ bool gamecardGetTrimmedSize(u64 *out)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && out)
|
||||
{
|
||||
*out = (sizeof(GameCardHeader) + ((u64)g_gameCardHeader.valid_data_end_address * GAMECARD_MEDIA_UNIT_SIZE));
|
||||
ret = true;
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -195,13 +302,13 @@ bool gamecardGetRomCapacity(u64 *out)
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && out)
|
||||
{
|
||||
*out = g_gameCardCapacity;
|
||||
ret = true;
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -211,14 +318,14 @@ bool gamecardGetCertificate(FsGameCardCertificate *out)
|
|||
Result rc = 0;
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardHandle.value && out)
|
||||
{
|
||||
rc = fsDeviceOperatorGetGameCardDeviceCertificate(&g_deviceOperator, &g_gameCardHandle, out);
|
||||
if (R_FAILED(rc)) LOGFILE("fsDeviceOperatorGetGameCardDeviceCertificate failed! (0x%08X)", rc);
|
||||
ret = R_SUCCEEDED(rc);
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -230,7 +337,7 @@ bool gamecardGetBundledFirmwareUpdateVersion(u32 *out)
|
|||
u32 update_version = 0;
|
||||
bool ret = false;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardHandle.value && out)
|
||||
{
|
||||
rc = fsDeviceOperatorUpdatePartitionInfo(&g_deviceOperator, &g_gameCardHandle, &update_version, &update_id);
|
||||
|
@ -239,7 +346,7 @@ bool gamecardGetBundledFirmwareUpdateVersion(u32 *out)
|
|||
ret = (R_SUCCEEDED(rc) && update_id == GAMECARD_UPDATE_TID);
|
||||
if (ret) *out = update_version;
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -249,7 +356,7 @@ bool gamecardGetEntryCountFromHashFileSystemPartition(u8 hfs_partition_type, u32
|
|||
bool ret = false;
|
||||
GameCardHashFileSystemHeader *fs_header = NULL;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && out_count)
|
||||
{
|
||||
fs_header = gamecardGetHashFileSystemPartitionHeader(hfs_partition_type, NULL);
|
||||
|
@ -261,7 +368,7 @@ bool gamecardGetEntryCountFromHashFileSystemPartition(u8 hfs_partition_type, u32
|
|||
LOGFILE("Failed to retrieve hash FS partition header!");
|
||||
}
|
||||
}
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -274,7 +381,7 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByIndex(u8 hfs_partition_typ
|
|||
GameCardHashFileSystemHeader *fs_header = NULL;
|
||||
GameCardHashFileSystemEntry *fs_entry = NULL;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && (out_offset || out_size || out_name))
|
||||
{
|
||||
|
@ -325,7 +432,7 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByIndex(u8 hfs_partition_typ
|
|||
}
|
||||
|
||||
out:
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -337,7 +444,7 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByName(u8 hfs_partition_type
|
|||
GameCardHashFileSystemHeader *fs_header = NULL;
|
||||
GameCardHashFileSystemEntry *fs_entry = NULL;
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
if (g_gameCardInserted && g_gameCardInfoLoaded && (out_offset || out_size))
|
||||
{
|
||||
|
@ -377,119 +484,16 @@ bool gamecardGetEntryInfoFromHashFileSystemPartitionByName(u8 hfs_partition_type
|
|||
}
|
||||
|
||||
out:
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NX_INLINE Result _gamecardInitialize(void)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
/* Allocate memory for the gamecard read buffer */
|
||||
g_gameCardReadBuf = malloc(GAMECARD_READ_BUFFER_SIZE);
|
||||
if (!g_gameCardReadBuf)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the gamecard read buffer!");
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_HeapAllocFailed);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open device operator */
|
||||
rc = fsOpenDeviceOperator(&g_deviceOperator);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenDeviceOperator failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_openDeviceOperator = true;
|
||||
|
||||
/* Open gamecard detection event notifier */
|
||||
rc = fsOpenGameCardDetectionEventNotifier(&g_gameCardEventNotifier);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsOpenGameCardDetectionEventNotifier failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_openEventNotifier = true;
|
||||
|
||||
/* Retrieve gamecard detection kernel event */
|
||||
rc = fsEventNotifierGetEventHandle(&g_gameCardEventNotifier, &g_gameCardKernelEvent, true);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsEventNotifierGetEventHandle failed! (0x%08X)", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_loadKernelEvent = true;
|
||||
|
||||
/* Create usermode exit event */
|
||||
ueventCreate(&g_gameCardDetectionThreadExitEvent, false);
|
||||
|
||||
/* Create gamecard detection thread */
|
||||
g_gameCardDetectionThreadCreated = gamecardCreateDetectionThread();
|
||||
if (!g_gameCardDetectionThreadCreated)
|
||||
{
|
||||
LOGFILE("Failed to create gamecard detection thread!");
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_IoError);
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _gamecardCleanup(void)
|
||||
{
|
||||
/* Destroy gamecard detection thread */
|
||||
if (g_gameCardDetectionThreadCreated)
|
||||
{
|
||||
gamecardDestroyDetectionThread();
|
||||
g_gameCardDetectionThreadCreated = false;
|
||||
}
|
||||
|
||||
/* Close gamecard detection kernel event */
|
||||
if (g_loadKernelEvent)
|
||||
{
|
||||
eventClose(&g_gameCardKernelEvent);
|
||||
g_loadKernelEvent = false;
|
||||
}
|
||||
|
||||
/* Close gamecard detection event notifier */
|
||||
if (g_openEventNotifier)
|
||||
{
|
||||
fsEventNotifierClose(&g_gameCardEventNotifier);
|
||||
g_openEventNotifier = false;
|
||||
}
|
||||
|
||||
/* Close device operator */
|
||||
if (g_openDeviceOperator)
|
||||
{
|
||||
fsDeviceOperatorClose(&g_deviceOperator);
|
||||
g_openDeviceOperator = false;
|
||||
}
|
||||
|
||||
/* Free gamecard read buffer */
|
||||
if (g_gameCardReadBuf)
|
||||
{
|
||||
free(g_gameCardReadBuf);
|
||||
g_gameCardReadBuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool gamecardCreateDetectionThread(void)
|
||||
{
|
||||
if (mtx_init(&g_gameCardSharedDataMutex, mtx_plain) != thrd_success)
|
||||
{
|
||||
LOGFILE("Failed to initialize gamecard shared data mutex!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thrd_create(&g_gameCardDetectionThread, gamecardDetectionThreadFunc, NULL) != thrd_success)
|
||||
{
|
||||
LOGFILE("Failed to create gamecard detection thread!");
|
||||
mtx_destroy(&g_gameCardSharedDataMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -503,9 +507,6 @@ static void gamecardDestroyDetectionThread(void)
|
|||
|
||||
/* Wait for the gamecard detection thread to exit */
|
||||
thrd_join(g_gameCardDetectionThread, NULL);
|
||||
|
||||
/* Destroy mutex */
|
||||
mtx_destroy(&g_gameCardSharedDataMutex);
|
||||
}
|
||||
|
||||
static int gamecardDetectionThreadFunc(void *arg)
|
||||
|
@ -519,7 +520,7 @@ static int gamecardDetectionThreadFunc(void *arg)
|
|||
Waiter gamecard_event_waiter = waiterForEvent(&g_gameCardKernelEvent);
|
||||
Waiter exit_event_waiter = waiterForUEvent(&g_gameCardDetectionThreadExitEvent);
|
||||
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
/* Retrieve initial gamecard insertion status */
|
||||
g_gameCardInserted = prev_status = gamecardIsInserted();
|
||||
|
@ -527,7 +528,7 @@ static int gamecardDetectionThreadFunc(void *arg)
|
|||
/* Load gamecard info right away if a gamecard is inserted */
|
||||
if (g_gameCardInserted) gamecardLoadInfo();
|
||||
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
@ -540,7 +541,7 @@ static int gamecardDetectionThreadFunc(void *arg)
|
|||
|
||||
/* Retrieve current gamecard insertion status */
|
||||
/* Only proceed if we're dealing with a status change */
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
|
||||
g_gameCardInserted = gamecardIsInserted();
|
||||
|
||||
|
@ -558,14 +559,14 @@ static int gamecardDetectionThreadFunc(void *arg)
|
|||
|
||||
prev_status = g_gameCardInserted;
|
||||
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
}
|
||||
|
||||
/* Free gamecard info and close gamecard handle */
|
||||
mtx_lock(&g_gameCardSharedDataMutex);
|
||||
mutexLock(&g_gamecardMutex);
|
||||
gamecardFreeInfo();
|
||||
g_gameCardInserted = false;
|
||||
mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -840,7 +841,7 @@ static bool gamecardOpenStorageArea(u8 area)
|
|||
|
||||
static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool lock)
|
||||
{
|
||||
if (lock) mtx_lock(&g_gameCardSharedDataMutex);
|
||||
if (lock) mutexLock(&g_gamecardMutex);
|
||||
|
||||
bool success = false;
|
||||
|
||||
|
@ -915,7 +916,7 @@ static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset, bool l
|
|||
}
|
||||
|
||||
exit:
|
||||
if (lock) mtx_unlock(&g_gameCardSharedDataMutex);
|
||||
if (lock) mutexUnlock(&g_gamecardMutex);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ typedef enum {
|
|||
|
||||
/// Initializes data needed to access raw gamecard storage areas.
|
||||
/// Also spans a background thread to automatically detect gamecard status changes and to cache data from the inserted gamecard.
|
||||
Result gamecardInitialize(void);
|
||||
bool gamecardInitialize(void);
|
||||
|
||||
/// Deinitializes data generated by gamecardInitialize().
|
||||
/// This includes destroying the background gamecard detection thread and freeing all cached gamecard data.
|
||||
|
|
|
@ -76,6 +76,8 @@ typedef struct {
|
|||
/* Global variables. */
|
||||
|
||||
static keysNcaKeyset g_ncaKeyset = {0};
|
||||
static bool g_ncaKeysetLoaded = false;
|
||||
static Mutex g_ncaKeysetMutex = 0;
|
||||
|
||||
static keysMemoryInfo g_fsRodataMemoryInfo = {
|
||||
.location = {
|
||||
|
@ -150,6 +152,11 @@ static bool keysReadKeysFromFile(void);
|
|||
|
||||
bool keysLoadNcaKeyset(void)
|
||||
{
|
||||
mutexLock(&g_ncaKeysetMutex);
|
||||
|
||||
bool ret = g_ncaKeysetLoaded;
|
||||
if (ret) goto exit;
|
||||
|
||||
if (!(envIsSyscallHinted(0x60) && /* svcDebugActiveProcess */
|
||||
envIsSyscallHinted(0x63) && /* svcGetDebugEvent */
|
||||
envIsSyscallHinted(0x65) && /* svcGetProcessList */
|
||||
|
@ -157,30 +164,35 @@ bool keysLoadNcaKeyset(void)
|
|||
envIsSyscallHinted(0x6A))) /* svcReadDebugProcessMemory */
|
||||
{
|
||||
LOGFILE("Debug SVC permissions not available!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProcessMemory(&g_fsRodataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .rodata section!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProcessMemory(&g_fsDataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .data section!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!keysDeriveNcaHeaderKey())
|
||||
{
|
||||
LOGFILE("Unable to derive NCA header key!");
|
||||
return false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!keysReadKeysFromFile()) return false;
|
||||
if (!keysReadKeysFromFile()) goto exit;
|
||||
|
||||
return true;
|
||||
ret = g_ncaKeysetLoaded = true;
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_ncaKeysetMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const u8 *keysGetNcaHeaderKey(void)
|
||||
|
|
|
@ -71,44 +71,28 @@ int main(int argc, char *argv[])
|
|||
|
||||
mkdir("sdmc:/nxdt_test", 0744);
|
||||
|
||||
/*FsRightsId rights_id = {
|
||||
.c = { 0x01, 0x00, 0x82, 0x40, 0x0B, 0xCC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 } // Untitled Goose Game
|
||||
};*/
|
||||
|
||||
// Untitled Goose Game's Base Program NCA
|
||||
NcmPackagedContentInfo base_program_content_info = {
|
||||
.hash = {
|
||||
0x8E, 0xF9, 0x20, 0xD4, 0x5E, 0xE1, 0x9E, 0xD1, 0xD2, 0x04, 0xC4, 0xC8, 0x22, 0x50, 0x79, 0xE8,
|
||||
0xD3, 0xE2, 0xE2, 0xA0, 0x66, 0xFD, 0x2B, 0xB6, 0x5C, 0x73, 0xF6, 0x89, 0xE2, 0x25, 0x0A, 0x82
|
||||
NcmContentInfo base_program_content_info = {
|
||||
.content_id = {
|
||||
.c = { 0x8E, 0xF9, 0x20, 0xD4, 0x5E, 0xE1, 0x9E, 0xD1, 0xD2, 0x04, 0xC4, 0xC8, 0x22, 0x50, 0x79, 0xE8 }
|
||||
},
|
||||
.info = {
|
||||
.content_id = {
|
||||
.c = { 0x8E, 0xF9, 0x20, 0xD4, 0x5E, 0xE1, 0x9E, 0xD1, 0xD2, 0x04, 0xC4, 0xC8, 0x22, 0x50, 0x79, 0xE8 }
|
||||
},
|
||||
.size = {
|
||||
0x00, 0x40, 0xAD, 0x31, 0x00, 0x00
|
||||
},
|
||||
.content_type = NcmContentType_Program,
|
||||
.id_offset = 0
|
||||
}
|
||||
.size = {
|
||||
0x00, 0x40, 0xAD, 0x31, 0x00, 0x00
|
||||
},
|
||||
.content_type = NcmContentType_Program,
|
||||
.id_offset = 0
|
||||
};
|
||||
|
||||
// Untitled Goose Game's Update Program NCA
|
||||
NcmPackagedContentInfo update_program_content_info = {
|
||||
.hash = {
|
||||
0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A,
|
||||
0x21, 0x0D, 0x79, 0x50, 0x3A, 0xAF, 0x0D, 0x66, 0x76, 0xE2, 0xBC, 0x84, 0xF7, 0x0A, 0x21, 0xE2
|
||||
NcmContentInfo update_program_content_info = {
|
||||
.content_id = {
|
||||
.c = { 0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A }
|
||||
},
|
||||
.info = {
|
||||
.content_id = {
|
||||
.c = { 0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A }
|
||||
},
|
||||
.size = {
|
||||
0x00, 0xF4, 0xA0, 0x0E, 0x00, 0x00
|
||||
},
|
||||
.content_type = NcmContentType_Program,
|
||||
.id_offset = 0
|
||||
}
|
||||
.size = {
|
||||
0x00, 0xF4, 0xA0, 0x0E, 0x00, 0x00
|
||||
},
|
||||
.content_type = NcmContentType_Program,
|
||||
.id_offset = 0
|
||||
};
|
||||
|
||||
buf = malloc(0x400000);
|
||||
|
@ -311,12 +295,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
|
||||
out2:
|
||||
while(appletMainLoop())
|
||||
{
|
||||
consoleUpdate(NULL);
|
||||
hidScanInput();
|
||||
if (utilsHidKeysAllDown() & KEY_A) break;
|
||||
}
|
||||
consoleUpdate(NULL);
|
||||
utilsWaitForButtonPress();
|
||||
|
||||
if (tmp_file) fclose(tmp_file);
|
||||
|
||||
|
|
15
source/nca.c
15
source/nca.c
|
@ -188,10 +188,10 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ncaInitializeContext(NcaContext *out, u8 storage_id, NcmContentStorage *ncm_storage, u8 hfs_partition_type, const NcmPackagedContentInfo *content_info, Ticket *tik)
|
||||
bool ncaInitializeContext(NcaContext *out, u8 storage_id, NcmContentStorage *ncm_storage, u8 hfs_partition_type, const NcmContentInfo *content_info, Ticket *tik)
|
||||
{
|
||||
if (!out || !tik || (storage_id != NcmStorageId_GameCard && !ncm_storage) || (storage_id == NcmStorageId_GameCard && hfs_partition_type > GameCardHashFileSystemPartitionType_Secure) || \
|
||||
!content_info || content_info->info.content_type > NcmContentType_DeltaFragment)
|
||||
!content_info || content_info->content_type > NcmContentType_DeltaFragment)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
|
@ -201,16 +201,13 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, NcmContentStorage *ncm
|
|||
out->storage_id = storage_id;
|
||||
out->ncm_storage = (out->storage_id != NcmStorageId_GameCard ? ncm_storage : NULL);
|
||||
|
||||
memcpy(&(out->content_id), &(content_info->info.content_id), sizeof(NcmContentId));
|
||||
memcpy(&(out->content_id), &(content_info->content_id), sizeof(NcmContentId));
|
||||
utilsGenerateHexStringFromData(out->content_id_str, sizeof(out->content_id_str), out->content_id.c, sizeof(out->content_id.c));
|
||||
|
||||
memcpy(out->hash, content_info->hash, SHA256_HASH_SIZE);
|
||||
utilsGenerateHexStringFromData(out->hash_str, sizeof(out->hash_str), out->hash, sizeof(out->hash));
|
||||
out->content_type = content_info->content_type;
|
||||
out->id_offset = content_info->id_offset;
|
||||
|
||||
out->content_type = content_info->info.content_type;
|
||||
out->id_offset = content_info->info.id_offset;
|
||||
|
||||
ncaConvertNcmContentSizeToU64(content_info->info.size, &(out->content_size));
|
||||
ncaConvertNcmContentSizeToU64(content_info->size, &(out->content_size));
|
||||
if (out->content_size < NCA_FULL_HEADER_LENGTH)
|
||||
{
|
||||
LOGFILE("Invalid size for NCA \"%s\"!", out->content_id_str);
|
||||
|
|
12
source/nca.h
12
source/nca.h
|
@ -273,13 +273,13 @@ typedef struct {
|
|||
u64 gamecard_offset; ///< Used to read NCA data from a gamecard using a FsStorage instance when storage_id == NcmStorageId_GameCard.
|
||||
NcmContentId content_id; ///< Also used to read NCA data.
|
||||
char content_id_str[0x21];
|
||||
u8 hash[0x20]; ///< Retrieved from NcmPackagedContentInfo.
|
||||
u8 hash[0x20]; ///< Manually calculated (if needed).
|
||||
char hash_str[0x41];
|
||||
u8 format_version; ///< NcaVersion.
|
||||
u8 content_type; ///< NcmContentType. Retrieved from NcmPackagedContentInfo.
|
||||
u64 content_size; ///< Retrieved from NcmPackagedContentInfo.
|
||||
u8 content_type; ///< NcmContentType. Retrieved from NcmContentInfo.
|
||||
u64 content_size; ///< Retrieved from NcmContentInfo.
|
||||
u8 key_generation; ///< NcaKeyGenerationOld / NcaKeyGeneration. Retrieved from the decrypted header.
|
||||
u8 id_offset; ///< Retrieved from NcmPackagedContentInfo.
|
||||
u8 id_offset; ///< Retrieved from NcmContentInfo.
|
||||
bool rights_id_available;
|
||||
u8 titlekey[0x10];
|
||||
bool dirty_header;
|
||||
|
@ -313,7 +313,7 @@ void ncaFreeCryptoBuffer(void);
|
|||
/// If 'storage_id' != NcmStorageId_GameCard, the 'ncm_storage' argument must point to a valid NcmContentStorage instance, previously opened using the same NcmStorageId value.
|
||||
/// If 'storage_id' == NcmStorageId_GameCard, the 'hfs_partition_type' argument must be a valid GameCardHashFileSystemPartitionType value.
|
||||
/// If the NCA holds a populated Rights ID field, and if the Ticket object pointed to by 'tik' hasn't been filled, ticket data will be retrieved.
|
||||
bool ncaInitializeContext(NcaContext *out, u8 storage_id, NcmContentStorage *ncm_storage, u8 hfs_partition_type, const NcmPackagedContentInfo *content_info, Ticket *tik);
|
||||
bool ncaInitializeContext(NcaContext *out, u8 storage_id, NcmContentStorage *ncm_storage, u8 hfs_partition_type, const NcmContentInfo *content_info, Ticket *tik);
|
||||
|
||||
/// Reads raw encrypted data from a NCA using an input context, previously initialized by ncaInitializeContext().
|
||||
/// Input offset must be relative to the start of the NCA content file.
|
||||
|
@ -385,7 +385,7 @@ bool ncaEncryptHeader(NcaContext *ctx);
|
|||
|
||||
|
||||
|
||||
/// Miscellanous functions.
|
||||
/// Miscellaneous functions.
|
||||
|
||||
NX_INLINE void ncaConvertNcmContentSizeToU64(const u8 *size, u64 *out)
|
||||
{
|
||||
|
|
|
@ -67,8 +67,12 @@ static const u32 g_serviceInfoCount = MAX_ELEMENTS(g_serviceInfo);
|
|||
static bool g_clkSvcUsePcv = false;
|
||||
static ClkrstSession g_clkrstCpuSession = {0}, g_clkrstMemSession = {0};
|
||||
|
||||
static Mutex g_servicesMutex = 0;
|
||||
|
||||
bool servicesInitialize(void)
|
||||
{
|
||||
mutexLock(&g_servicesMutex);
|
||||
|
||||
Result rc = 0;
|
||||
bool ret = true;
|
||||
|
||||
|
@ -101,11 +105,15 @@ bool servicesInitialize(void)
|
|||
g_serviceInfo[i].initialized = true;
|
||||
}
|
||||
|
||||
mutexUnlock(&g_servicesMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void servicesClose(void)
|
||||
{
|
||||
mutexLock(&g_servicesMutex);
|
||||
|
||||
for(u32 i = 0; i < g_serviceInfoCount; i++)
|
||||
{
|
||||
/* Check if this service has not been initialized, or if it doesn't have a valid close function */
|
||||
|
@ -114,6 +122,8 @@ void servicesClose(void)
|
|||
/* Close service */
|
||||
g_serviceInfo[i].close_func();
|
||||
}
|
||||
|
||||
mutexUnlock(&g_servicesMutex);
|
||||
}
|
||||
|
||||
bool servicesCheckRunningServiceByName(const char *name)
|
||||
|
@ -134,9 +144,12 @@ bool servicesCheckRunningServiceByName(const char *name)
|
|||
|
||||
bool servicesCheckInitializedServiceByName(const char *name)
|
||||
{
|
||||
if (!name || !strlen(name)) return false;
|
||||
mutexLock(&g_servicesMutex);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (!name || !strlen(name)) goto exit;
|
||||
|
||||
size_t name_len = strlen(name);
|
||||
|
||||
for(u32 i = 0; i < g_serviceInfoCount; i++)
|
||||
|
@ -148,11 +161,16 @@ bool servicesCheckInitializedServiceByName(const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_servicesMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void servicesChangeHardwareClockRates(u32 cpu_rate, u32 mem_rate)
|
||||
{
|
||||
mutexLock(&g_servicesMutex);
|
||||
|
||||
if (g_clkSvcUsePcv)
|
||||
{
|
||||
pcvSetClockRate(PcvModule_CpuBus, cpu_rate);
|
||||
|
@ -161,6 +179,8 @@ void servicesChangeHardwareClockRates(u32 cpu_rate, u32 mem_rate)
|
|||
clkrstSetClockRate(&g_clkrstCpuSession, cpu_rate);
|
||||
clkrstSetClockRate(&g_clkrstMemSession, mem_rate);
|
||||
}
|
||||
|
||||
mutexUnlock(&g_servicesMutex);
|
||||
}
|
||||
|
||||
static Result servicesNifmUserInitialize(void)
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
|
||||
static SetCalRsa2048DeviceKey g_eTicketDeviceKey = {0};
|
||||
static bool g_eTicketDeviceKeyRetrieved = false;
|
||||
static Mutex g_eTicketDeviceKeyMutex = 0;
|
||||
|
||||
/// Used during the RSA-OAEP titlekey decryption stage.
|
||||
static const u8 g_nullHash[0x20] = {
|
||||
|
@ -96,7 +97,11 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!tikGetTitleKekEncryptedTitleKeyFromTicket(dst))
|
||||
mutexLock(&g_eTicketDeviceKeyMutex);
|
||||
bool titlekey_retrieved = tikGetTitleKekEncryptedTitleKeyFromTicket(dst);
|
||||
mutexUnlock(&g_eTicketDeviceKeyMutex);
|
||||
|
||||
if (!titlekey_retrieved)
|
||||
{
|
||||
LOGFILE("Unable to retrieve titlekey from ticket!");
|
||||
return false;
|
||||
|
|
376
source/utils.c
376
source/utils.c
|
@ -18,6 +18,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <switch.h>
|
||||
|
||||
|
@ -32,23 +33,145 @@
|
|||
|
||||
/* Global variables. */
|
||||
|
||||
static bool g_resourcesInitialized = false;
|
||||
static Mutex g_resourcesMutex = 0;
|
||||
|
||||
static FsFileSystem *g_sdCardFileSystem = NULL;
|
||||
|
||||
static FsStorage g_emmcBisSystemPartitionStorage = {0};
|
||||
static FATFS *g_emmcBisSystemPartitionFatFsObj = NULL;
|
||||
|
||||
static AppletType g_programAppletType = 0;
|
||||
static bool g_homeButtonBlocked = false;
|
||||
static Mutex g_homeButtonMutex = 0;
|
||||
|
||||
static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown;
|
||||
|
||||
static AppletHookCookie g_systemOverclockCookie = {0};
|
||||
|
||||
static Mutex g_logfileMutex = 0;
|
||||
|
||||
static FsStorage g_emmcBisSystemPartitionStorage = {0};
|
||||
static FATFS *g_emmcBisSystemPartitionFatFsObj = NULL;
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool utilsMountEmmcBisSystemPartitionStorage(void);
|
||||
static void utilsUnmountEmmcBisSystemPartitionStorage(void);
|
||||
|
||||
static void _utilsGetCustomFirmwareType(void);
|
||||
|
||||
static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param);
|
||||
|
||||
static bool utilsMountEmmcBisSystemPartitionStorage(void);
|
||||
static void utilsUnmountEmmcBisSystemPartitionStorage(void);
|
||||
bool utilsInitializeResources(void)
|
||||
{
|
||||
mutexLock(&g_resourcesMutex);
|
||||
|
||||
bool ret = g_resourcesInitialized;
|
||||
if (ret) goto exit;
|
||||
|
||||
/* Initialize needed services */
|
||||
if (!servicesInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize needed services!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Load NCA keyset */
|
||||
if (!keysLoadNcaKeyset())
|
||||
{
|
||||
LOGFILE("Failed to load NCA keyset!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Allocate NCA crypto buffer */
|
||||
if (!ncaAllocateCryptoBuffer())
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for NCA crypto buffer!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize gamecard interface */
|
||||
if (!gamecardInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize gamecard interface!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Retrieve SD card FsFileSystem */
|
||||
if (!(g_sdCardFileSystem = fsdevGetDeviceFileSystem("sdmc:")))
|
||||
{
|
||||
LOGFILE("fsdevGetDeviceFileSystem failed!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Mount eMMC BIS System partition */
|
||||
if (!utilsMountEmmcBisSystemPartitionStorage()) goto exit;
|
||||
|
||||
/* Get applet type */
|
||||
g_programAppletType = appletGetAppletType();
|
||||
|
||||
/* Disable screen dimming and auto sleep */
|
||||
appletSetMediaPlaybackState(true);
|
||||
|
||||
/* Retrieve custom firmware type */
|
||||
_utilsGetCustomFirmwareType();
|
||||
|
||||
/* Overclock system */
|
||||
utilsOverclockSystem(true);
|
||||
|
||||
/* Setup an applet hook to change the hardware clocks after a system mode change (docked <-> undocked) */
|
||||
appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL);
|
||||
|
||||
/* Initialize FreeType */
|
||||
//if (!freeTypeHelperInitialize()) return false;
|
||||
|
||||
/* Initialize LVGL */
|
||||
//if (!lvglHelperInitialize()) return false;
|
||||
|
||||
ret = g_resourcesInitialized = true;
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_resourcesMutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void utilsCloseResources(void)
|
||||
{
|
||||
mutexLock(&g_resourcesMutex);
|
||||
|
||||
/* Free LVGL resources */
|
||||
//lvglHelperExit();
|
||||
|
||||
/* Free FreeType resouces */
|
||||
//freeTypeHelperExit();
|
||||
|
||||
/* Unset our overclock applet hook */
|
||||
appletUnhook(&g_systemOverclockCookie);
|
||||
|
||||
/* Restore hardware clocks */
|
||||
utilsOverclockSystem(false);
|
||||
|
||||
/* Enable screen dimming and auto sleep */
|
||||
appletSetMediaPlaybackState(false);
|
||||
|
||||
/* Unblock HOME button presses */
|
||||
utilsChangeHomeButtonBlockStatus(false);
|
||||
|
||||
/* Unmount eMMC BIS System partition */
|
||||
utilsUnmountEmmcBisSystemPartitionStorage();
|
||||
|
||||
/* Deinitialize gamecard interface */
|
||||
gamecardExit();
|
||||
|
||||
/* Free NCA crypto buffer */
|
||||
ncaFreeCryptoBuffer();
|
||||
|
||||
/* Close initialized services */
|
||||
servicesClose();
|
||||
|
||||
g_resourcesInitialized = false;
|
||||
|
||||
mutexUnlock(&g_resourcesMutex);
|
||||
}
|
||||
|
||||
u64 utilsHidKeysAllDown(void)
|
||||
{
|
||||
|
@ -111,97 +234,49 @@ out:
|
|||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
|
||||
void utilsOverclockSystem(bool restore)
|
||||
void removeIllegalCharacters(char *name)
|
||||
{
|
||||
u32 cpuClkRate = ((restore ? CPU_CLKRT_NORMAL : CPU_CLKRT_OVERCLOCKED) * 1000000);
|
||||
u32 memClkRate = ((restore ? MEM_CLKRT_NORMAL : MEM_CLKRT_OVERCLOCKED) * 1000000);
|
||||
servicesChangeHardwareClockRates(cpuClkRate, memClkRate);
|
||||
if (!name || !strlen(name)) return;
|
||||
|
||||
u32 i, len = strlen(name);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (memchr("?[]/\\=+<>:;\",*|^", name[i], sizeof("?[]/\\=+<>:;\",*|^") - 1) || name[i] < 0x20 || name[i] > 0x7E) name[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
bool utilsInitializeResources(void)
|
||||
void utilsReplaceIllegalCharacters(char *str)
|
||||
{
|
||||
Result rc = 0;
|
||||
size_t strsize = 0;
|
||||
|
||||
/* Initialize needed services */
|
||||
if (!servicesInitialize())
|
||||
if (!str || !(strsize = strlen(str))) return;
|
||||
|
||||
for(size_t i = 0; i < strsize; i++)
|
||||
{
|
||||
LOGFILE("Failed to initialize needed services!");
|
||||
return false;
|
||||
if (memchr("?[]/\\=+<>:;\",*|^", str[i], sizeof("?[]/\\=+<>:;\",*|^") - 1) || str[i] < 0x20 || str[i] > 0x7E) str[i] = '_';
|
||||
}
|
||||
|
||||
/* Load NCA keyset */
|
||||
if (!keysLoadNcaKeyset())
|
||||
{
|
||||
LOGFILE("Failed to load NCA keyset!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate NCA crypto buffer */
|
||||
if (!ncaAllocateCryptoBuffer())
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for NCA crypto buffer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialize gamecard interface */
|
||||
rc = gamecardInitialize();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("Failed to initialize gamecard interface!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Mount eMMC BIS System partition */
|
||||
if (!utilsMountEmmcBisSystemPartitionStorage()) return false;
|
||||
|
||||
/* Initialize FreeType */
|
||||
//if (!freeTypeHelperInitialize()) return false;
|
||||
|
||||
/* Initialize LVGL */
|
||||
//if (!lvglHelperInitialize()) return false;
|
||||
|
||||
/* Retrieve custom firmware type */
|
||||
_utilsGetCustomFirmwareType();
|
||||
|
||||
/* Overclock system */
|
||||
utilsOverclockSystem(false);
|
||||
|
||||
/* Setup an applet hook to change the hardware clocks after a system mode change (docked <-> undocked) */
|
||||
appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void utilsCloseResources(void)
|
||||
void utilsTrimString(char *str)
|
||||
{
|
||||
/* Unset our overclock applet hook */
|
||||
appletUnhook(&g_systemOverclockCookie);
|
||||
size_t strsize = 0;
|
||||
char *start = NULL, *end = NULL;
|
||||
|
||||
/* Restore hardware clocks */
|
||||
utilsOverclockSystem(true);
|
||||
if (!str || !(strsize = strlen(str))) return;
|
||||
|
||||
/* Free LVGL resources */
|
||||
//lvglHelperExit();
|
||||
start = str;
|
||||
end = (start + strsize);
|
||||
|
||||
/* Free FreeType resouces */
|
||||
//freeTypeHelperExit();
|
||||
while(--end >= start)
|
||||
{
|
||||
if (!isspace((unsigned char)*end)) break;
|
||||
}
|
||||
|
||||
/* Unmount eMMC BIS System partition */
|
||||
utilsUnmountEmmcBisSystemPartitionStorage();
|
||||
*(++end) = '\0';
|
||||
|
||||
/* Deinitialize gamecard interface */
|
||||
gamecardExit();
|
||||
while(isspace((unsigned char)*start)) start++;
|
||||
|
||||
/* Free NCA crypto buffer */
|
||||
ncaFreeCryptoBuffer();
|
||||
|
||||
/* Close initialized services */
|
||||
servicesClose();
|
||||
}
|
||||
|
||||
u8 utilsGetCustomFirmwareType(void)
|
||||
{
|
||||
return g_customFirmwareType;
|
||||
if (start != str) memmove(str, start, end - start + 1);
|
||||
}
|
||||
|
||||
void utilsGenerateHexStringFromData(char *dst, size_t dst_size, const void *src, size_t src_size)
|
||||
|
@ -223,39 +298,109 @@ void utilsGenerateHexStringFromData(char *dst, size_t dst_size, const void *src,
|
|||
dst[j] = '\0';
|
||||
}
|
||||
|
||||
bool utilsGetFreeSdCardSpace(u64 *out)
|
||||
{
|
||||
return utilsGetFreeFileSystemSpace(g_sdCardFileSystem, out);
|
||||
}
|
||||
|
||||
bool utilsGetFreeFileSystemSpace(FsFileSystem *fs, u64 *out)
|
||||
{
|
||||
if (!fs || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Result rc = fsFsGetFreeSpace(fs, "/", (s64*)out);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsFsGetFreeSpace failed! (0x%08X)", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool utilsCheckIfFileExists(const char *path)
|
||||
{
|
||||
if (!path || !strlen(path)) return false;
|
||||
|
||||
FILE *chkfile = fopen(path, "rb");
|
||||
if (chkfile)
|
||||
{
|
||||
fclose(chkfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool utilsCreateConcatenationFile(const char *path)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
if (!path || !strlen(path))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Safety check: remove any existant file/directory at the destination path */
|
||||
remove(path);
|
||||
fsdevDeleteDirectoryRecursively(path);
|
||||
|
||||
/* Create ConcatenationFile */
|
||||
/* If the call succeeds, the caller function will be able to operate on this file using stdio calls */
|
||||
rc = fsdevCreateFile(path, 0, FsCreateOption_BigFile);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("fsdevCreateFile failed for \"%s\"! (0x%08X)", path, rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool utilsAppletModeCheck(void)
|
||||
{
|
||||
return (g_programAppletType != AppletType_Application && g_programAppletType != AppletType_SystemApplication);
|
||||
}
|
||||
|
||||
void utilsChangeHomeButtonBlockStatus(bool block)
|
||||
{
|
||||
mutexLock(&g_homeButtonMutex);
|
||||
|
||||
/* Only change HOME button blocking status if we're running as a regular application or a system application, and if it's current blocking status is different than the requested one */
|
||||
if (!utilsAppletModeCheck() && block != g_homeButtonBlocked)
|
||||
{
|
||||
if (block)
|
||||
{
|
||||
appletBeginBlockingHomeButtonShortAndLongPressed(0);
|
||||
} else {
|
||||
appletEndBlockingHomeButtonShortAndLongPressed();
|
||||
}
|
||||
|
||||
g_homeButtonBlocked = block;
|
||||
}
|
||||
|
||||
mutexUnlock(&g_homeButtonMutex);
|
||||
}
|
||||
|
||||
u8 utilsGetCustomFirmwareType(void)
|
||||
{
|
||||
return g_customFirmwareType;
|
||||
}
|
||||
|
||||
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void)
|
||||
{
|
||||
return &g_emmcBisSystemPartitionStorage;
|
||||
}
|
||||
|
||||
static void _utilsGetCustomFirmwareType(void)
|
||||
void utilsOverclockSystem(bool overclock)
|
||||
{
|
||||
bool tx_srv = servicesCheckRunningServiceByName("tx");
|
||||
bool rnx_srv = servicesCheckRunningServiceByName("rnx");
|
||||
|
||||
if (!tx_srv && !rnx_srv)
|
||||
{
|
||||
/* Atmosphere */
|
||||
g_customFirmwareType = UtilsCustomFirmwareType_Atmosphere;
|
||||
} else
|
||||
if (tx_srv && !rnx_srv)
|
||||
{
|
||||
/* SX OS */
|
||||
g_customFirmwareType = UtilsCustomFirmwareType_SXOS;
|
||||
} else {
|
||||
/* ReiNX */
|
||||
g_customFirmwareType = UtilsCustomFirmwareType_ReiNX;
|
||||
}
|
||||
}
|
||||
|
||||
static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
if (hook != AppletHookType_OnOperationMode && hook != AppletHookType_OnPerformanceMode) return;
|
||||
|
||||
/* To do: read config here to actually know the value to use with utilsOverclockSystem */
|
||||
utilsOverclockSystem(true);
|
||||
u32 cpuClkRate = ((overclock ? CPU_CLKRT_OVERCLOCKED : CPU_CLKRT_NORMAL) * 1000000);
|
||||
u32 memClkRate = ((overclock ? MEM_CLKRT_OVERCLOCKED : MEM_CLKRT_NORMAL) * 1000000);
|
||||
servicesChangeHardwareClockRates(cpuClkRate, memClkRate);
|
||||
}
|
||||
|
||||
static bool utilsMountEmmcBisSystemPartitionStorage(void)
|
||||
|
@ -302,3 +447,20 @@ static void utilsUnmountEmmcBisSystemPartitionStorage(void)
|
|||
memset(&g_emmcBisSystemPartitionStorage, 0, sizeof(FsStorage));
|
||||
}
|
||||
}
|
||||
|
||||
static void _utilsGetCustomFirmwareType(void)
|
||||
{
|
||||
bool tx_srv = servicesCheckRunningServiceByName("tx");
|
||||
bool rnx_srv = servicesCheckRunningServiceByName("rnx");
|
||||
g_customFirmwareType = (rnx_srv ? UtilsCustomFirmwareType_ReiNX : (tx_srv ? UtilsCustomFirmwareType_SXOS : UtilsCustomFirmwareType_Atmosphere));
|
||||
}
|
||||
|
||||
static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param)
|
||||
{
|
||||
(void)param;
|
||||
|
||||
if (hook != AppletHookType_OnOperationMode && hook != AppletHookType_OnPerformanceMode) return;
|
||||
|
||||
/* To do: read config here to actually know the value to use with utilsOverclockSystem */
|
||||
utilsOverclockSystem(false);
|
||||
}
|
||||
|
|
|
@ -38,22 +38,13 @@
|
|||
|
||||
|
||||
|
||||
|
||||
/// Need to move this to npdm.c/h eventually.
|
||||
#define NPDM_META_MAGIC 0x4D455441 /* "META" */
|
||||
|
||||
#define TITLE_PATCH_BITMASK (u64)0x800
|
||||
#define TITLE_ADDON_BITMASK (u64)0xFFFFFFFFFFFF0000
|
||||
|
||||
|
||||
NX_INLINE u64 titleGetPatchIdByApplicationId(u64 app_id)
|
||||
{
|
||||
return (app_id | TITLE_PATCH_BITMASK);
|
||||
}
|
||||
|
||||
NX_INLINE u64 titleGetApplicationIdByPatchId(u64 patch_id)
|
||||
{
|
||||
return (patch_id & ~TITLE_PATCH_BITMASK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -65,15 +56,8 @@ typedef enum {
|
|||
UtilsCustomFirmwareType_ReiNX = 3
|
||||
} UtilsCustomFirmwareType;
|
||||
|
||||
typedef struct {
|
||||
u16 major : 6;
|
||||
u16 minor : 6;
|
||||
u16 micro : 4;
|
||||
u16 bugfix;
|
||||
} TitleVersion;
|
||||
|
||||
|
||||
|
||||
bool utilsInitializeResources(void);
|
||||
void utilsCloseResources(void);
|
||||
|
||||
u64 utilsHidKeysAllDown(void);
|
||||
u64 utilsHidKeysAllHeld(void);
|
||||
|
@ -82,22 +66,32 @@ void utilsWaitForButtonPress(void);
|
|||
|
||||
void utilsWriteLogMessage(const char *func_name, const char *fmt, ...);
|
||||
|
||||
void utilsOverclockSystem(bool restore);
|
||||
void utilsReplaceIllegalCharacters(char *str);
|
||||
|
||||
bool utilsInitializeResources(void);
|
||||
void utilsCloseResources(void);
|
||||
|
||||
u8 utilsGetCustomFirmwareType(void); ///< UtilsCustomFirmwareType.
|
||||
void utilsTrimString(char *str);
|
||||
|
||||
void utilsGenerateHexStringFromData(char *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
bool utilsGetFreeSdCardSpace(u64 *out);
|
||||
bool utilsGetFreeFileSystemSpace(FsFileSystem *fs, u64 *out);
|
||||
|
||||
bool utilsCheckIfFileExists(const char *path);
|
||||
|
||||
bool utilsCreateConcatenationFile(const char *path);
|
||||
|
||||
bool utilsAppletModeCheck(void);
|
||||
|
||||
void utilsChangeHomeButtonBlockStatus(bool block);
|
||||
|
||||
u8 utilsGetCustomFirmwareType(void); ///< UtilsCustomFirmwareType.
|
||||
|
||||
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void);
|
||||
|
||||
static inline void utilsSleep(u64 seconds)
|
||||
void utilsOverclockSystem(bool overclock);
|
||||
|
||||
NX_INLINE void utilsSleep(u64 seconds)
|
||||
{
|
||||
if (seconds) svcSleepThread(seconds * (u64)1000000000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* __UTILS_H__ */
|
||||
|
|
Loading…
Add table
Reference in a new issue