From afcd075354dec43fae882c3ad4d5220336231d04 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 14 Jun 2019 21:19:37 -0700 Subject: [PATCH] libstrat: revise emummc utility accessors --- include/stratosphere.hpp | 1 + include/stratosphere/emummc_utilities.hpp | 28 +++++ include/stratosphere/utilities.hpp | 17 --- source/emummc_utilities.cpp | 142 ++++++++++++++++++++++ 4 files changed, 171 insertions(+), 17 deletions(-) create mode 100644 include/stratosphere/emummc_utilities.hpp create mode 100644 source/emummc_utilities.cpp diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index 885695c0..cc386d67 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -17,6 +17,7 @@ #pragma once #include "stratosphere/utilities.hpp" +#include "stratosphere/emummc_utilities.hpp" #include "stratosphere/scope_guard.hpp" diff --git a/include/stratosphere/emummc_utilities.hpp b/include/stratosphere/emummc_utilities.hpp new file mode 100644 index 00000000..04bcfd7d --- /dev/null +++ b/include/stratosphere/emummc_utilities.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +/* Get whether emummc is active. */ +bool IsEmummc(); + +/* Get Nintendo redirection path. */ +const char *GetEmummcNintendoDirPath(); + +/* Get Emummc folderpath, NULL if not file-based. */ +const char *GetEmummcFilePath(); diff --git a/include/stratosphere/utilities.hpp b/include/stratosphere/utilities.hpp index 51b82c95..98ccdccf 100644 --- a/include/stratosphere/utilities.hpp +++ b/include/stratosphere/utilities.hpp @@ -118,23 +118,6 @@ static inline bool ShouldBlankProdInfo() { return should_blank_prodinfo; } -static inline Result GetEmunandConfig(u64 *out) { - u64 tmp = 0; - Result rc = SmcGetConfig((SplConfigItem)65100, &tmp); - if (R_SUCCEEDED(rc)) { - *out = tmp; - } - return rc; -} - -static inline bool IsEmunand() { - u64 emunand; - if (R_FAILED(GetEmunandConfig(&emunand))) { - std::abort(); - } - return emunand != 0; -} - HosRecursiveMutex &GetSmSessionMutex(); HosRecursiveMutex &GetSmMitmSessionMutex(); diff --git a/source/emummc_utilities.cpp b/source/emummc_utilities.cpp new file mode 100644 index 00000000..cef3b9af --- /dev/null +++ b/source/emummc_utilities.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +/* EFS0 */ +static constexpr u32 EmummcStorageMagic = 0x30534645; +static constexpr size_t EmummcMaxDirLength = 0x7F; + +struct EmummcBaseConfig { + u32 magic; + u32 type; + u32 id; + u32 fs_version; +}; + +struct EmummcPartitionConfig { + u64 start_sector; +}; + +struct EmummcFileConfig { + char path[EmummcMaxDirLength+1]; +}; + +struct ExoEmummcConfig { + EmummcBaseConfig base_cfg; + union { + EmummcPartitionConfig partition_cfg; + EmummcFileConfig file_cfg; + }; + char emu_dir_path[EmummcMaxDirLength+1]; +}; + +enum EmummcType { + EmummcType_Emmc = 0, + EmummcType_Sd, + EmummcType_SdFile, + + EmummcType_Max, +}; + +static bool g_IsEmummc = false; +static bool g_HasCached = false; +static Mutex g_Mutex; +static ExoEmummcConfig g_exo_emummc_config; + +static void _CacheValues(void) +{ + if (__atomic_load_n(&g_HasCached, __ATOMIC_SEQ_CST)) + return; + + mutexLock(&g_Mutex); + + if (g_HasCached) { + mutexUnlock(&g_Mutex); + return; + } + + static struct { + char file_path[EmummcMaxDirLength+1]; + char nintendo_path[EmummcMaxDirLength+1]; + } __attribute__((aligned(0x1000))) paths; + + { + SecmonArgs args = {0}; + args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */ + args.X[1] = 0; /* NAND */ + args.X[2] = reinterpret_cast(&paths); /* path output */ + if (R_FAILED(svcCallSecureMonitor(&args)) || args.X[0] != 0) { + std::abort(); + } + std::memcpy(&g_exo_emummc_config, &args.X[1], sizeof(args) - sizeof(args.X[0])); + } + + const EmummcType emummc_type = static_cast(g_exo_emummc_config.base_cfg.type); + +/* Ignore format warnings. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" + switch (emummc_type) { + case EmummcType_SdFile: + std::snprintf(g_exo_emummc_config.file_cfg.path, sizeof(g_exo_emummc_config.file_cfg.path), "/%s", paths.file_path); + break; + default: + break; + } + + std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/%s", paths.nintendo_path); + + g_IsEmummc = g_exo_emummc_config.base_cfg.magic == EmummcStorageMagic && emummc_type != EmummcType_Emmc; + + /* Default Nintendo redirection path. */ + if (g_IsEmummc) { + if (std::strcmp(g_exo_emummc_config.emu_dir_path, "/") == 0) { + std::snprintf(g_exo_emummc_config.emu_dir_path, sizeof(g_exo_emummc_config.emu_dir_path), "/emummc/Nintendo_%04x", g_exo_emummc_config.base_cfg.id); + } + } +#pragma GCC diagnostic pop + + __atomic_store_n(&g_HasCached, true, __ATOMIC_SEQ_CST); + + mutexUnlock(&g_Mutex); +} + + +/* Get whether emummc is active. */ +bool IsEmummc() { + _CacheValues(); + return g_IsEmummc; +} + +/* Get Nintendo redirection path. */ +const char *GetEmummcNintendoDirPath() { + _CacheValues(); + if (!g_IsEmummc) { + return nullptr; + } + return g_exo_emummc_config.emu_dir_path; +} + +/* Get Emummc folderpath, NULL if not file-based. */ +const char *GetEmummcFilePath() { + _CacheValues(); + if (!g_IsEmummc || g_exo_emummc_config.base_cfg.type != EmummcType_SdFile) { + return nullptr; + } + return g_exo_emummc_config.file_cfg.path; +}