diff --git a/source/cert.c b/source/cert.c index 629d549..18b6912 100644 --- a/source/cert.c +++ b/source/cert.c @@ -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; } diff --git a/source/gamecard.c b/source/gamecard.c index 6b34c6a..defe5f9 100644 --- a/source/gamecard.c +++ b/source/gamecard.c @@ -20,7 +20,6 @@ #include #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; } diff --git a/source/gamecard.h b/source/gamecard.h index 933c462..45b5d02 100644 --- a/source/gamecard.h +++ b/source/gamecard.h @@ -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. diff --git a/source/keys.c b/source/keys.c index e2f08d8..9a3fccf 100644 --- a/source/keys.c +++ b/source/keys.c @@ -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) diff --git a/source/main.c b/source/main.c index d31575a..1518f48 100644 --- a/source/main.c +++ b/source/main.c @@ -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); diff --git a/source/nca.c b/source/nca.c index 97f83cc..9a847e0 100644 --- a/source/nca.c +++ b/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); diff --git a/source/nca.h b/source/nca.h index 3abd35c..9b5cbda 100644 --- a/source/nca.h +++ b/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) { diff --git a/source/services.c b/source/services.c index 6b074dc..e0e33d5 100644 --- a/source/services.c +++ b/source/services.c @@ -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) diff --git a/source/tik.c b/source/tik.c index d2d1375..8af6028 100644 --- a/source/tik.c +++ b/source/tik.c @@ -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; diff --git a/source/utils.c b/source/utils.c index 7d68b31..35a3bf9 100644 --- a/source/utils.c +++ b/source/utils.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -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); +} diff --git a/source/utils.h b/source/utils.h index 03fc1bd..ee889c6 100644 --- a/source/utils.h +++ b/source/utils.h @@ -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__ */