1
0
Fork 0
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:
Pablo Curiel 2020-05-02 19:40:50 -04:00
parent d4872ce6d3
commit 2e48a22f8c
11 changed files with 528 additions and 342 deletions

View file

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

View file

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

View file

@ -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.

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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)

View file

@ -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;

View file

@ -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);
}

View file

@ -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__ */