From ef28b7d3955636447a3aaf34859e05b1cebc5f28 Mon Sep 17 00:00:00 2001 From: Adubbz Date: Sun, 4 Aug 2019 13:10:45 +1000 Subject: [PATCH] Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes --- stratosphere/ncm/source/debug.cpp | 142 +++++++++++ stratosphere/ncm/source/debug.hpp | 39 +++ .../ncm/source/impl/ncm_content_manager.cpp | 6 +- .../source/impl/ncm_placeholder_accessor.cpp | 5 + .../ncm/source/lr_contentlocationresolver.cpp | 42 ++++ .../ncm/source/lr_manager_service.cpp | 11 + .../lr_redirectonlylocationresolver.cpp | 28 +++ .../source/lr_registeredlocationresolver.cpp | 20 ++ .../source/ncm_content_manager_service.cpp | 28 +++ .../ncm/source/ncm_contentmetadatabase.cpp | 231 ++++++++---------- .../ncm/source/ncm_contentmetadatabase.hpp | 2 + .../ncm/source/ncm_contentstorage.cpp | 58 +++++ stratosphere/ncm/source/ncm_fs.cpp | 60 +++-- stratosphere/ncm/source/ncm_main.cpp | 43 +++- .../ncm/source/ncm_readonlycontentstorage.cpp | 60 +++++ stratosphere/ncm/source/ncm_types.hpp | 38 ++- 16 files changed, 639 insertions(+), 174 deletions(-) create mode 100644 stratosphere/ncm/source/debug.cpp create mode 100644 stratosphere/ncm/source/debug.hpp diff --git a/stratosphere/ncm/source/debug.cpp b/stratosphere/ncm/source/debug.cpp new file mode 100644 index 000000000..6659ae10f --- /dev/null +++ b/stratosphere/ncm/source/debug.cpp @@ -0,0 +1,142 @@ +#include + +#include "impl/ncm_content_manager.hpp" +#include "debug.hpp" +#include "ncm_fs.hpp" + +namespace sts::debug { + + #define IRAM_BASE 0x40000000ull + #define IRAM_SIZE 0x40000 + + #define IRAM_PAYLOAD_MAX_SIZE 0x2F000 + #define IRAM_PAYLOAD_BASE 0x40010000ull + + #define IRAM_SAFE_START 0x40038000ull + #define IRAM_SAFE_END 0x4003D000ull + #define IRAM_SAFE_SIZE IRAM_SAFE_END - IRAM_SAFE_START + + namespace { + + HosMutex g_log_mutex; + + } + + size_t g_curr_log_offset = 0; + size_t g_log_skip = 4; + + char __attribute__ ((aligned (0x1000))) g_work_page[0x1000]; + + void clear_iram(void) { + /* Fill with null*/ + memset(g_work_page, 0, sizeof(g_work_page)); + + /* Overwrite all of our log's IRAM with 0s. */ + for (size_t ofs = 0; ofs < IRAM_SAFE_SIZE; ofs += sizeof(g_work_page)) { + CopyToIram(IRAM_SAFE_START + ofs, g_work_page, sizeof(g_work_page)); + } + } + + void clear_log(void) { + std::scoped_lock lk(g_log_mutex); + + clear_iram(); + } + + Result Initialize() { + clear_log(); + return ResultSuccess; + } + + void DebugLog(const char* format, ...) { + std::scoped_lock lk(g_log_mutex); + memset(g_work_page, 0, sizeof(g_work_page)); + + /* Format a string with our arguments. */ + va_list args; + va_start(args, format); + vsnprintf(g_work_page, 0x1000, format, args); + va_end(args); + + size_t msg_len = strnlen(g_work_page, 0x1000); + + /* Nothing to log. */ + if (msg_len == 0) { + return; + } + + /* Attempt to put some of our new string in the previous 4 bytes. */ + if (g_curr_log_offset >= 4) { + char __attribute__ ((aligned (0x4))) prev_4[4] = {0}; + CopyFromIram(prev_4, IRAM_SAFE_START+g_curr_log_offset-4, 4); + size_t prev_4_size = strnlen(prev_4, 4); + + /* Do we have room to put some of our new string in the old one? */ + if (prev_4_size < 4) { + size_t spare_4_space = 4 - prev_4_size; + memcpy(prev_4 + prev_4_size, g_work_page, spare_4_space); + + /* Copy the previous 4 bytes back. */ + CopyToIram(IRAM_SAFE_START+g_curr_log_offset-4, prev_4, 4); + memmove(g_work_page, g_work_page + spare_4_space, 0x1000-spare_4_space); + /* Update our size again. */ + msg_len = strnlen(g_work_page, 0x1000); + } + } + + size_t msg_len_aligned = (msg_len + 3) & ~3; + + if (g_curr_log_offset + msg_len_aligned > IRAM_SAFE_SIZE) { + if (g_log_skip == 0) { + /* Log is full. Reboot to RCM to read it. */ + RebootToRcm(); + return; + } + + g_log_skip--; + clear_iram(); + g_curr_log_offset = 0; + } + + /* Fill remainder with 0s. */ + if (msg_len_aligned > msg_len) { + memset(g_work_page + msg_len, '\0', msg_len_aligned - msg_len); + } + + uintptr_t iram_out_start = IRAM_SAFE_START+g_curr_log_offset; + uintptr_t iram_next_page = (iram_out_start + 0x1000-1) & ~(0x1000-1); + + /* We are copying across two pages */ + if (iram_out_start + msg_len_aligned > iram_next_page) { + size_t first_page_size = iram_next_page - iram_out_start; + CopyToIram(iram_out_start, g_work_page, first_page_size); + CopyToIram(iram_next_page, g_work_page+first_page_size, msg_len_aligned-first_page_size); + } else { + CopyToIram(iram_out_start, g_work_page, msg_len_aligned); + } + + g_curr_log_offset += msg_len_aligned; + } + + void LogBytes(const void* buf, size_t len) { + if (buf == NULL || len == 0) { + return; + } + + const u8* bytes = static_cast(buf); + int count = 0; + DebugLog("\n\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); + DebugLog("-----------------------------------------------\n"); + + for (size_t i = 0; i < len; i++) { + DebugLog("%02x ", bytes[i]); + count++; + if ((count % 16) == 0) { + DebugLog("\n"); + } + } + + DebugLog("\n"); + } +} + diff --git a/stratosphere/ncm/source/debug.hpp b/stratosphere/ncm/source/debug.hpp new file mode 100644 index 000000000..0eca28d9a --- /dev/null +++ b/stratosphere/ncm/source/debug.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Adubbz + * + * 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 +#include + +namespace sts::debug { + #define STR_(X) #X + #define STR(X) STR_(X) + + #define D_LOG(format, ...) \ + debug::DebugLog("%s:" STR(__LINE__) " " format, __FUNCTION__, ##__VA_ARGS__); + #define R_DEBUG_START \ + Result rc = [&]() -> Result { + #define R_DEBUG_END \ + }(); \ + D_LOG(" -> 0x%08" PRIX32 "\n", rc); \ + return rc; + + Result Initialize(); + void DebugLog(const char* format, ...); + void LogBytes(const void* buf, size_t len); + +} \ No newline at end of file diff --git a/stratosphere/ncm/source/impl/ncm_content_manager.cpp b/stratosphere/ncm/source/impl/ncm_content_manager.cpp index 9477e1841..dcfe4326f 100644 --- a/stratosphere/ncm/source/impl/ncm_content_manager.cpp +++ b/stratosphere/ncm/source/impl/ncm_content_manager.cpp @@ -19,6 +19,7 @@ #include #include +#include "../debug.hpp" #include "../ncm_contentmetadatabase.hpp" #include "../ncm_contentstorage.hpp" #include "../ncm_fs.hpp" @@ -62,7 +63,7 @@ namespace sts::ncm::impl { u64 journal_size; u32 flags; FsSaveDataSpaceId space_id; - } PACKED; + }; static_assert(sizeof(SaveDataMeta) == 0x20, "SaveDataMeta definition!"); @@ -150,6 +151,9 @@ namespace sts::ncm::impl { return ResultSuccess; } + R_ASSERT(debug::Initialize()); + debug::DebugLog("ContentManager::InitializeContentManager\n"); + size_t cur_storage_index = g_num_content_storage_entries; for (size_t i = 0; i < MaxContentStorageEntries; i++) { diff --git a/stratosphere/ncm/source/impl/ncm_placeholder_accessor.cpp b/stratosphere/ncm/source/impl/ncm_placeholder_accessor.cpp index 5bea9b33a..c3236a4c8 100644 --- a/stratosphere/ncm/source/impl/ncm_placeholder_accessor.cpp +++ b/stratosphere/ncm/source/impl/ncm_placeholder_accessor.cpp @@ -20,6 +20,8 @@ #include "../ncm_make_path.hpp" #include "../ncm_path_utils.hpp" +#include "../debug.hpp" + namespace sts::ncm::impl { unsigned int PlaceHolderAccessor::GetDirectoryDepth() { @@ -78,6 +80,8 @@ namespace sts::ncm::impl { this->GetPlaceHolderPathUncached(placeholder_path, placeholder_id); + debug::DebugLog("Deleting %s\n", placeholder_path); + R_TRY_CATCH(fsdevDeleteDirectoryRecursively(placeholder_path)) { R_CATCH(ResultFsPathNotFound) { return ResultNcmPlaceHolderNotFound; @@ -97,6 +101,7 @@ namespace sts::ncm::impl { FILE* f = fopen(placeholder_path, "r+b"); if (f == nullptr) { + debug::DebugLog("Failed to open placeholder %s\n", placeholder_path); return fsdevGetLastResult(); } diff --git a/stratosphere/ncm/source/lr_contentlocationresolver.cpp b/stratosphere/ncm/source/lr_contentlocationresolver.cpp index 95680e8bd..ddbffc45e 100644 --- a/stratosphere/ncm/source/lr_contentlocationresolver.cpp +++ b/stratosphere/ncm/source/lr_contentlocationresolver.cpp @@ -17,6 +17,8 @@ #include "impl/ncm_content_manager.hpp" #include "lr_contentlocationresolver.hpp" +#include "debug.hpp" + namespace sts::lr { ContentLocationResolverInterface::~ContentLocationResolverInterface() { @@ -28,6 +30,7 @@ namespace sts::lr { } Result ContentLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->program_redirector.FindRedirection(&path, tid)) { @@ -46,14 +49,18 @@ namespace sts::lr { R_ASSERT(this->content_storage->GetPath(&path, program_content_id)); *out.pointer = path; return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.SetRedirection(tid, *path.pointer); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::ResolveApplicationControlPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->app_control_redirector.FindRedirection(&path, tid)) { @@ -62,9 +69,11 @@ namespace sts::lr { } return ResultLrControlNotFound; + R_DEBUG_END } Result ContentLocationResolverInterface::ResolveApplicationHtmlDocumentPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->html_docs_redirector.FindRedirection(&path, tid)) { @@ -73,9 +82,11 @@ namespace sts::lr { } return ResultLrHtmlDocumentNotFound; + R_DEBUG_END } Result ContentLocationResolverInterface::ResolveDataPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; ncm::ContentId data_content_id; @@ -83,19 +94,25 @@ namespace sts::lr { R_ASSERT(this->content_storage->GetPath(&path, data_content_id)); *out.pointer = path; return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectApplicationControlPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->app_control_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectApplicationHtmlDocumentPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->html_docs_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::ResolveApplicationLegalInformationPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->legal_info_redirector.FindRedirection(&path, tid)) { @@ -104,14 +121,18 @@ namespace sts::lr { } return ResultLrLegalInformationNotFound; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectApplicationLegalInformationPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->legal_info_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::Refresh() { + R_DEBUG_START std::shared_ptr content_meta_database; std::shared_ptr content_storage; R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, this->storage_id)); @@ -126,43 +147,57 @@ namespace sts::lr { this->legal_info_redirector.ClearRedirections(); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectApplicationProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::ClearApplicationRedirection() { + R_DEBUG_START this->program_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->debug_program_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->app_control_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->html_docs_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->legal_info_redirector.ClearRedirections(impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::EraseProgramRedirection(ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::EraseApplicationControlRedirection(ncm::TitleId tid) { + R_DEBUG_START this->app_control_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::EraseApplicationHtmlDocumentRedirection(ncm::TitleId tid) { + R_DEBUG_START this->html_docs_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::EraseApplicationLegalInformationRedirection(ncm::TitleId tid) { + R_DEBUG_START this->legal_info_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::ResolveProgramPathForDebug(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->debug_program_redirector.FindRedirection(&path, tid)) { @@ -178,21 +213,28 @@ namespace sts::lr { *out.pointer = path; return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectProgramPathForDebug(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->debug_program_redirector.SetRedirection(tid, *path.pointer); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::RedirectApplicationProgramPathForDebug(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->debug_program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result ContentLocationResolverInterface::EraseProgramRedirectionForDebug(ncm::TitleId tid) { + R_DEBUG_START this->debug_program_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/lr_manager_service.cpp b/stratosphere/ncm/source/lr_manager_service.cpp index b6311dc93..82b11f7ec 100644 --- a/stratosphere/ncm/source/lr_manager_service.cpp +++ b/stratosphere/ncm/source/lr_manager_service.cpp @@ -13,26 +13,37 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include "impl/lr_manager.hpp" #include "lr_manager_service.hpp" +#include "debug.hpp" namespace sts::lr { Result LocationResolverManagerService::OpenLocationResolver(Out> out, ncm::StorageId storage_id) { + R_DEBUG_START return impl::OpenLocationResolver(out, storage_id); + R_DEBUG_END } Result LocationResolverManagerService::OpenRegisteredLocationResolver(Out> out) { + R_DEBUG_START return impl::OpenRegisteredLocationResolver(out); + R_DEBUG_END } Result LocationResolverManagerService::RefreshLocationResolver(ncm::StorageId storage_id) { + R_DEBUG_START + D_LOG("storage_id: 0x%x\n", static_cast(storage_id)); return impl::RefreshLocationResolver(storage_id); + R_DEBUG_END } Result LocationResolverManagerService::OpenAddOnContentLocationResolver(Out> out) { + R_DEBUG_START return impl::OpenAddOnContentLocationResolver(out); + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/lr_redirectonlylocationresolver.cpp b/stratosphere/ncm/source/lr_redirectonlylocationresolver.cpp index b140e69b1..8f626f3ce 100644 --- a/stratosphere/ncm/source/lr_redirectonlylocationresolver.cpp +++ b/stratosphere/ncm/source/lr_redirectonlylocationresolver.cpp @@ -17,6 +17,8 @@ #include "impl/ncm_content_manager.hpp" #include "lr_redirectonlylocationresolver.hpp" +#include "debug.hpp" + namespace sts::lr { RedirectOnlyLocationResolverInterface::~RedirectOnlyLocationResolverInterface() { @@ -28,6 +30,7 @@ namespace sts::lr { } Result RedirectOnlyLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->program_redirector.FindRedirection(&path, tid)) { @@ -36,14 +39,18 @@ namespace sts::lr { } return ResultLrProgramNotFound; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::RedirectProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.SetRedirection(tid, *path.pointer); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::ResolveApplicationControlPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->app_control_redirector.FindRedirection(&path, tid)) { @@ -52,9 +59,11 @@ namespace sts::lr { } return ResultLrControlNotFound; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::ResolveApplicationHtmlDocumentPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->html_docs_redirector.FindRedirection(&path, tid)) { @@ -63,23 +72,31 @@ namespace sts::lr { } return ResultLrHtmlDocumentNotFound; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::ResolveDataPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START return ResultLrDataNotFound; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::RedirectApplicationControlPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->app_control_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::RedirectApplicationHtmlDocumentPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->html_docs_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::ResolveApplicationLegalInformationPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (this->legal_info_redirector.FindRedirection(&path, tid)) { @@ -88,39 +105,50 @@ namespace sts::lr { } return ResultLrLegalInformationNotFound; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::RedirectApplicationLegalInformationPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->legal_info_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::Refresh() { + R_DEBUG_START this->program_redirector.ClearRedirections(); this->debug_program_redirector.ClearRedirections(); this->app_control_redirector.ClearRedirections(); this->html_docs_redirector.ClearRedirections(); this->legal_info_redirector.ClearRedirections(); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::RedirectApplicationProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.SetRedirection(tid, *path.pointer, impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::ClearApplicationRedirection() { + R_DEBUG_START this->program_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->debug_program_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->app_control_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->html_docs_redirector.ClearRedirections(impl::RedirectionFlags_Application); this->legal_info_redirector.ClearRedirections(impl::RedirectionFlags_Application); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::EraseProgramRedirection(ncm::TitleId tid) { + R_DEBUG_START this->program_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result RedirectOnlyLocationResolverInterface::EraseApplicationControlRedirection(ncm::TitleId tid) { diff --git a/stratosphere/ncm/source/lr_registeredlocationresolver.cpp b/stratosphere/ncm/source/lr_registeredlocationresolver.cpp index a21c41120..1b5197fe8 100644 --- a/stratosphere/ncm/source/lr_registeredlocationresolver.cpp +++ b/stratosphere/ncm/source/lr_registeredlocationresolver.cpp @@ -16,6 +16,8 @@ #include "lr_registeredlocationresolver.hpp" +#include "debug.hpp" + namespace sts::lr { RegisteredLocationResolverInterface::RegisteredLocationResolverInterface() { @@ -30,6 +32,7 @@ namespace sts::lr { } Result RegisteredLocationResolverInterface::ResolveProgramPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (!this->program_redirector.FindRedirection(&path, tid)) { @@ -40,9 +43,11 @@ namespace sts::lr { *out.pointer = path; return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::RegisterProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START Path tmp_path = *path.pointer; if (!this->registered_program_redirector.SetRedirection(tid, tmp_path)) { @@ -51,20 +56,26 @@ namespace sts::lr { } return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::UnregisterProgramPath(ncm::TitleId tid) { + R_DEBUG_START this->registered_program_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::RedirectProgramPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START Path tmp_path = *path.pointer; this->program_redirector.SetRedirection(tid, tmp_path); return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::ResolveHtmlDocumentPath(OutPointerWithServerSize out, ncm::TitleId tid) { + R_DEBUG_START Path path; if (!this->html_docs_redirector.FindRedirection(&path, tid)) { @@ -75,9 +86,11 @@ namespace sts::lr { *out.pointer = path; return ResultLrHtmlDocumentNotFound; + R_DEBUG_END } Result RegisteredLocationResolverInterface::RegisterHtmlDocumentPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START Path tmp_path = *path.pointer; if (!this->registered_html_docs_redirector.SetRedirection(tid, tmp_path)) { @@ -86,23 +99,30 @@ namespace sts::lr { } return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::UnregisterHtmlDocumentPath(ncm::TitleId tid) { + R_DEBUG_START this->registered_html_docs_redirector.EraseRedirection(tid); return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::RedirectHtmlDocumentPath(InPointer path, ncm::TitleId tid) { + R_DEBUG_START Path tmp_path = *path.pointer; this->html_docs_redirector.SetRedirection(tid, tmp_path); return ResultSuccess; + R_DEBUG_END } Result RegisteredLocationResolverInterface::Refresh() { + R_DEBUG_START this->registered_program_redirector.ClearRedirections(); this->registered_html_docs_redirector.ClearRedirections(); return ResultSuccess; + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/ncm_content_manager_service.cpp b/stratosphere/ncm/source/ncm_content_manager_service.cpp index 2418dbd09..80f82ae13 100644 --- a/stratosphere/ncm/source/ncm_content_manager_service.cpp +++ b/stratosphere/ncm/source/ncm_content_manager_service.cpp @@ -17,6 +17,8 @@ #include "impl/ncm_content_manager.hpp" #include "ncm_content_manager_service.hpp" +#include "debug.hpp" + namespace sts::ncm { ContentManagerService::~ContentManagerService() { @@ -24,61 +26,87 @@ namespace sts::ncm { } Result ContentManagerService::CreateContentStorage(StorageId storage_id) { + R_DEBUG_START return impl::CreateContentStorage(storage_id); + R_DEBUG_END } Result ContentManagerService::CreateContentMetaDatabase(StorageId storage_id) { + R_DEBUG_START return impl::CreateContentMetaDatabase(storage_id); + R_DEBUG_END } Result ContentManagerService::VerifyContentStorage(StorageId storage_id) { + R_DEBUG_START return impl::VerifyContentStorage(storage_id); + R_DEBUG_END } Result ContentManagerService::VerifyContentMetaDatabase(StorageId storage_id) { + R_DEBUG_START return impl::VerifyContentMetaDatabase(storage_id); + R_DEBUG_END } Result ContentManagerService::OpenContentStorage(Out> out, StorageId storage_id) { + R_DEBUG_START std::shared_ptr content_storage; R_TRY(impl::OpenContentStorage(&content_storage, storage_id)); out.SetValue(std::move(content_storage)); return ResultSuccess; + R_DEBUG_END } Result ContentManagerService::OpenContentMetaDatabase(Out> out, StorageId storage_id) { + R_DEBUG_START std::shared_ptr content_meta_database; R_TRY(impl::OpenContentMetaDatabase(&content_meta_database, storage_id)); out.SetValue(std::move(content_meta_database)); return ResultSuccess; + R_DEBUG_END } Result ContentManagerService::CloseContentStorageForcibly(StorageId storage_id) { + R_DEBUG_START return impl::CloseContentStorageForcibly(storage_id); + R_DEBUG_END } Result ContentManagerService::CloseContentMetaDatabaseForcibly(StorageId storage_id) { + R_DEBUG_START return impl::CloseContentMetaDatabaseForcibly(storage_id); + R_DEBUG_END } Result ContentManagerService::CleanupContentMetaDatabase(StorageId storage_id) { + R_DEBUG_START return impl::CleanupContentMetaDatabase(storage_id); + R_DEBUG_END } Result ContentManagerService::ActivateContentStorage(StorageId storage_id) { + R_DEBUG_START return impl::ActivateContentStorage(storage_id); + R_DEBUG_END } Result ContentManagerService::InactivateContentStorage(StorageId storage_id) { + R_DEBUG_START return impl::InactivateContentStorage(storage_id); + R_DEBUG_END } Result ContentManagerService::ActivateContentMetaDatabase(StorageId storage_id) { + R_DEBUG_START return impl::ActivateContentMetaDatabase(storage_id); + R_DEBUG_END } Result ContentManagerService::InactivateContentMetaDatabase(StorageId storage_id) { + R_DEBUG_START return impl::InactivateContentMetaDatabase(storage_id); + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/ncm_contentmetadatabase.cpp b/stratosphere/ncm/source/ncm_contentmetadatabase.cpp index 5c4de4830..47c8d3ce3 100644 --- a/stratosphere/ncm/source/ncm_contentmetadatabase.cpp +++ b/stratosphere/ncm/source/ncm_contentmetadatabase.cpp @@ -17,6 +17,8 @@ #include "ncm_contentmetadatabase.hpp" #include "ncm_utils.hpp" +#include "debug.hpp" + namespace sts::ncm { namespace { @@ -91,9 +93,7 @@ namespace sts::ncm { } Result ContentMetaDatabaseInterface::GetContentIdByTypeImpl(ContentId* out, const ContentMetaKey& key, ContentType type, std::optional id_offset) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_TRY(this->EnsureEnabled()); const auto it = this->kvs->lower_bound(key); if (it == this->kvs->end() || it->GetKey().id != key.id) { @@ -146,25 +146,13 @@ namespace sts::ncm { } Result ContentMetaDatabaseInterface::GetLatestContentMetaKeyImpl(ContentMetaKey* out_key, TitleId tid) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_TRY(this->EnsureEnabled()); ContentMetaKey key = {0}; key.id = tid; - if (this->kvs->GetCount() == 0) { - return ResultNcmContentMetaNotFound; - } - - auto entry = this->kvs->lower_bound(key); - if (entry == this->kvs->end()) { - return ResultNcmContentMetaNotFound; - } - bool found_key = false; - - for (; entry != this->kvs->end(); entry++) { + for (auto entry = this->kvs->lower_bound(key); entry != this->kvs->end(); entry++) { if (entry->GetKey().id != key.id) { break; } @@ -183,31 +171,41 @@ namespace sts::ncm { return ResultSuccess; } - Result ContentMetaDatabaseInterface::Set(ContentMetaKey key, InBuffer value) { + Result ContentMetaDatabaseInterface::EnsureEnabled() { if (this->disabled) { return ResultNcmInvalidContentMetaDatabase; } + return ResultSuccess; + } + + + Result ContentMetaDatabaseInterface::Set(ContentMetaKey key, InBuffer value) { + R_DEBUG_START + R_TRY(this->EnsureEnabled()); + + D_LOG(" set title_id: 0x%lx\n", key.id); + D_LOG(" set version: 0x%x\n", key.version); + R_TRY(this->kvs->Set(key, value.buffer, value.num_elements)); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::Get(Out out_size, ContentMetaKey key, OutBuffer out_value) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } - + R_DEBUG_START + R_TRY(this->EnsureEnabled()); R_TRY(this->kvs->Get(out_size.GetPointer(), out_value.buffer, out_value.num_elements, key)); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::Remove(ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } - + R_DEBUG_START + R_TRY(this->EnsureEnabled()); R_TRY(this->kvs->Remove(key)); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetContentIdByType(Out out_content_id, ContentMetaKey key, ContentType type) { @@ -217,45 +215,33 @@ namespace sts::ncm { return ResultSuccess; } - Result ContentMetaDatabaseInterface::ListContentInfo(Out out_entries_written, OutBuffer out_info, ContentMetaKey key, u32 start_index) { - if (start_index >> 0x1f != 0) { + Result ContentMetaDatabaseInterface::ListContentInfo(Out out_count, OutBuffer out_info, ContentMetaKey key, u32 offset) { + R_DEBUG_START + if (offset >> 0x1f != 0) { return ResultNcmInvalidOffset; } - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_TRY(this->EnsureEnabled()); - const void* value = nullptr; + const void *value = nullptr; size_t value_size = 0; R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs)); const auto header = GetValueHeader(value); const auto content_infos = GetValueContentInfos(value); - size_t entries_written = 0; - - if (out_info.num_elements == 0) { - out_entries_written.SetValue(0); - return ResultSuccess; + + size_t count; + for (count = 0; offset + count < header->content_count && count < out_info.num_elements; count++) { + out_info[count] = content_infos[offset + count]; } - for (size_t i = start_index; i < out_info.num_elements; i++) { - /* We have no more entries we can read out. */ - if (header->content_count <= start_index + i) { - break; - } - - out_info[i] = content_infos[i]; - entries_written = i + 1; - } - - out_entries_written.SetValue(entries_written); + out_count.SetValue(count); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::List(Out out_entries_total, Out out_entries_written, OutBuffer out_info, ContentMetaType type, TitleId application_title_id, TitleId title_id_min, TitleId title_id_max, ContentInstallType install_type) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); size_t entries_total = 0; size_t entries_written = 0; @@ -311,23 +297,22 @@ namespace sts::ncm { out_entries_total.SetValue(entries_total); out_entries_written.SetValue(entries_written); return ResultSuccess; + R_DEBUG_END } - Result ContentMetaDatabaseInterface::GetLatestContentMetaKey(Out out_key, TitleId title_id) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } - + Result ContentMetaDatabaseInterface::GetLatestContentMetaKey(Out out_key, TitleId title_id) { + R_DEBUG_START + R_TRY(this->EnsureEnabled()); ContentMetaKey key; R_TRY(this->GetLatestContentMetaKeyImpl(&key, title_id)); out_key.SetValue(key); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::ListApplication(Out out_entries_total, Out out_entries_written, OutBuffer out_keys, ContentMetaType type) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); size_t entries_total = 0; size_t entries_written = 0; @@ -377,12 +362,12 @@ namespace sts::ncm { out_entries_total.SetValue(entries_total); out_entries_written.SetValue(entries_written); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::Has(Out out, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (this->kvs->GetCount() == 0) { out.SetValue(false); @@ -397,36 +382,26 @@ namespace sts::ncm { out.SetValue(has); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::HasAll(Out out, InBuffer keys) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); - if (keys.num_elements == 0) { - out.SetValue(true); - return ResultSuccess; - } - - for (size_t i = 0; i < keys.num_elements; i++) { - bool has = false; + bool has = true; + for (size_t i = 0; i < keys.num_elements && has; i++) { R_TRY(this->Has(&has, keys[i])); - - if (!has) { - out.SetValue(false); - return ResultSuccess; - } } - out.SetValue(true); + out.SetValue(has); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetSize(Out out_size, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (this->kvs->GetCount() == 0) { return ResultNcmContentMetaNotFound; @@ -439,12 +414,12 @@ namespace sts::ncm { out_size.SetValue(it->GetValueSize()); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetRequiredSystemVersion(Out out_version, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (key.type != ContentMetaType::Application && key.type != ContentMetaType::Patch) { return ResultNcmInvalidContentMetaKey; @@ -459,34 +434,41 @@ namespace sts::ncm { const auto ext_header = GetValueExtendedHeader(value); out_version.SetValue(ext_header->required_system_version); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetPatchId(Out out_patch_id, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (key.type != ContentMetaType::Application) { return ResultNcmInvalidContentMetaKey; } + D_LOG(" key title_id: 0x%lx\n", key.id); + D_LOG(" key version: 0x%x\n", key.version); + const void* value = nullptr; size_t value_size = 0; R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs)); const auto ext_header = GetValueExtendedHeader(value); + out_patch_id.SetValue(ext_header->patch_id); + D_LOG(" patch title_id: 0x%lx\n", *out_patch_id); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::DisableForcibly() { + R_DEBUG_START this->disabled = true; return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::LookupOrphanContent(OutBuffer out_orphaned, InBuffer content_ids) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (out_orphaned.num_elements < content_ids.num_elements) { return ResultNcmBufferInsufficient; @@ -531,19 +513,20 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::Commit() { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } - + R_DEBUG_START + R_TRY(this->EnsureEnabled()); R_TRY(this->kvs->Save()); R_TRY(fsdevCommitDevice(this->mount_name)); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::HasContent(Out out, ContentMetaKey key, ContentId content_id) { + R_DEBUG_START const void* value = nullptr; size_t value_size = 0; R_TRY(GetContentMetaValuePointer(&value, &value_size, key, this->kvs)); @@ -563,16 +546,16 @@ namespace sts::ncm { out.SetValue(false); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::ListContentMetaInfo(Out out_entries_written, OutBuffer out_meta_info, ContentMetaKey key, u32 start_index) { + R_DEBUG_START if (start_index >> 0x1f != 0) { return ResultNcmInvalidOffset; } - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_TRY(this->EnsureEnabled()); const void* value = nullptr; size_t value_size = 0; @@ -598,12 +581,12 @@ namespace sts::ncm { out_entries_written.SetValue(entries_written); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetAttributes(Out out_attributes, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); const void* value = nullptr; size_t value_size = 0; @@ -611,12 +594,12 @@ namespace sts::ncm { const auto header = GetValueHeader(value); out_attributes.SetValue(header->attributes); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetRequiredApplicationVersion(Out out_version, ContentMetaKey key) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_DEBUG_START + R_TRY(this->EnsureEnabled()); if (key.type != ContentMetaType::AddOnContent) { return ResultNcmInvalidContentMetaKey; @@ -628,13 +611,16 @@ namespace sts::ncm { const auto ext_header = GetValueExtendedHeader(value); out_version.SetValue(ext_header->required_application_version); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetContentIdByTypeAndIdOffset(Out out_content_id, ContentMetaKey key, ContentType type, u8 id_offset) { + R_DEBUG_START ContentId content_id; R_TRY(this->GetContentIdByTypeImpl(&content_id, key, type, std::optional(id_offset))); out_content_id.SetValue(content_id); return ResultSuccess; + R_DEBUG_END } Result ContentMetaDatabaseInterface::GetLatestProgram(ContentId* out_content_id, TitleId title_id) { @@ -653,33 +639,28 @@ namespace sts::ncm { return ResultSuccess; } - Result OnMemoryContentMetaDatabaseInterface::GetLatestContentMetaKey(Out out_key, TitleId tid) { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + Result OnMemoryContentMetaDatabaseInterface::GetLatestContentMetaKey(Out out_key, TitleId title_id) { + R_DEBUG_START + R_TRY(this->EnsureEnabled()); + + const ContentMetaKey key = ContentMetaKey::Make(title_id, 0, ContentMetaType::Unknown); - ContentMetaKey key = {0}; - key.id = tid; - - if (this->kvs->GetCount() == 0) { - return ResultNcmContentMetaNotFound; - } - - auto entry = this->kvs->lower_bound(key); - if (entry == this->kvs->end() || entry->GetKey().id != key.id) { - return ResultNcmContentMetaNotFound; - } - - for (; entry != this->kvs->end(); entry++) { - if (entry->GetKey().id != key.id) { + std::optional found_key; + for (auto entry = this->kvs->lower_bound(key); entry != this->kvs->end(); entry++) { + if (entry->GetKey().id != title_id) { break; } - key = entry->GetKey(); + found_key = entry->GetKey(); } - *out_key = key; + if (!found_key) { + return ResultNcmContentMetaNotFound; + } + + *out_key = *found_key; return ResultSuccess; + R_DEBUG_END } Result OnMemoryContentMetaDatabaseInterface::LookupOrphanContent(OutBuffer out_orphaned, InBuffer content_ids) { @@ -687,9 +668,7 @@ namespace sts::ncm { } Result OnMemoryContentMetaDatabaseInterface::Commit() { - if (this->disabled) { - return ResultNcmInvalidContentMetaDatabase; - } + R_TRY(this->EnsureEnabled()); return ResultSuccess; } diff --git a/stratosphere/ncm/source/ncm_contentmetadatabase.hpp b/stratosphere/ncm/source/ncm_contentmetadatabase.hpp index b306631e3..d393b9d49 100644 --- a/stratosphere/ncm/source/ncm_contentmetadatabase.hpp +++ b/stratosphere/ncm/source/ncm_contentmetadatabase.hpp @@ -31,6 +31,8 @@ namespace sts::ncm { private: Result GetContentIdByTypeImpl(ContentId* out, const ContentMetaKey& key, ContentType type, std::optional id_offset); Result GetLatestContentMetaKeyImpl(ContentMetaKey* out_key, TitleId tid); + protected: + Result EnsureEnabled(); public: virtual Result Set(ContentMetaKey key, InBuffer value) override; virtual Result Get(Out out_size, ContentMetaKey key, OutBuffer out_value) override; diff --git a/stratosphere/ncm/source/ncm_contentstorage.cpp b/stratosphere/ncm/source/ncm_contentstorage.cpp index 4369e0877..9e1599599 100644 --- a/stratosphere/ncm/source/ncm_contentstorage.cpp +++ b/stratosphere/ncm/source/ncm_contentstorage.cpp @@ -20,6 +20,8 @@ #include "ncm_make_path.hpp" #include "ncm_utils.hpp" +#include "debug.hpp" + namespace sts::ncm { ContentStorageInterface::~ContentStorageInterface() { @@ -95,15 +97,18 @@ namespace sts::ncm { } Result ContentStorageInterface::GeneratePlaceHolderId(Out out) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } sts::rnd::GenerateRandomBytes(out.GetPointer(), sizeof(NcmNcaId)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -115,17 +120,21 @@ namespace sts::ncm { R_TRY(this->placeholder_accessor.Create(placeholder_id, size)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } return this->placeholder_accessor.Delete(placeholder_id); + R_DEBUG_END } Result ContentStorageInterface::HasPlaceHolder(Out out, PlaceHolderId placeholder_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -138,9 +147,11 @@ namespace sts::ncm { out.SetValue(has); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, InBuffer data) { + R_DEBUG_START /* Offset is too large */ if (offset >> 0x3f != 0) { return ResultNcmInvalidOffset; @@ -173,9 +184,11 @@ namespace sts::ncm { this->placeholder_accessor.StoreToCache(f, placeholder_id); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) { + R_DEBUG_START this->ClearContentCache(); if (this->disabled) { @@ -200,9 +213,11 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::Delete(ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -220,9 +235,11 @@ namespace sts::ncm { } R_END_TRY_CATCH; return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::Has(Out out, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -235,9 +252,11 @@ namespace sts::ncm { out.SetValue(has); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetPath(OutPointerWithServerSize out, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -248,9 +267,11 @@ namespace sts::ncm { R_TRY(ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path)); *out.pointer = common_path; return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetPlaceHolderPath(OutPointerWithServerSize out, PlaceHolderId placeholder_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -261,9 +282,11 @@ namespace sts::ncm { R_TRY(ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path)); *out.pointer = common_path; return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::CleanupAllPlaceHolder() { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -281,9 +304,11 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::ListPlaceHolder(Out out_count, OutBuffer out_buf) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -312,9 +337,11 @@ namespace sts::ncm { out_count.SetValue(static_cast(entry_count)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetContentCount(Out out_count) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -337,9 +364,11 @@ namespace sts::ncm { out_count.SetValue(content_count); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::ListContentId(Out out_count, OutBuffer out_buf, u32 start_offset) { + R_DEBUG_START if (start_offset >> 0x1f != 0) { return ResultNcmInvalidOffset; } @@ -386,9 +415,11 @@ namespace sts::ncm { out_count.SetValue(static_cast(entry_count)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetSizeFromContentId(Out out_size, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -403,16 +434,20 @@ namespace sts::ncm { out_size.SetValue(st.st_size); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::DisableForcibly() { + R_DEBUG_START this->disabled = true; this->ClearContentCache(); this->placeholder_accessor.ClearAllCaches(); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -441,18 +476,22 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } R_TRY(this->placeholder_accessor.SetSize(placeholder_id, size)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::ReadContentIdFile(OutBuffer buf, ContentId content_id, u64 offset) { + R_DEBUG_START /* Offset is too large */ if (offset >> 0x3f != 0) { return ResultNcmInvalidOffset; @@ -475,9 +514,11 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetRightsIdFromPlaceHolderId(Out out_rights_id, Out out_key_generation, PlaceHolderId placeholder_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -495,9 +536,11 @@ namespace sts::ncm { out_key_generation.SetValue(static_cast(key_generation)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetRightsIdFromContentId(Out out_rights_id, Out out_key_generation, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -556,9 +599,11 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, InBuffer data) { + R_DEBUG_START /* Offset is too large */ if (offset >> 0x3f != 0) { return ResultNcmInvalidOffset; @@ -599,9 +644,11 @@ namespace sts::ncm { fflush(f); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetFreeSpaceSize(Out out_size) { + R_DEBUG_START struct statvfs st = {0}; if (statvfs(this->root_path, &st) == -1) { return fsdevGetLastResult(); @@ -609,9 +656,11 @@ namespace sts::ncm { out_size.SetValue(st.f_bfree); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetTotalSpaceSize(Out out_size) { + R_DEBUG_START struct statvfs st = {0}; if (statvfs(this->root_path, &st) == -1) { return fsdevGetLastResult(); @@ -619,14 +668,18 @@ namespace sts::ncm { out_size.SetValue(st.f_blocks); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::FlushPlaceHolder() { + R_DEBUG_START this->placeholder_accessor.ClearAllCaches(); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetSizeFromPlaceHolderId(Out out_size, PlaceHolderId placeholder_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -651,9 +704,11 @@ namespace sts::ncm { out_size.SetValue(st.st_size); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::RepairInvalidFileAttribute() { + R_DEBUG_START char content_root_path[FS_MAX_PATH] = {0}; this->GetContentRootPath(content_root_path); unsigned int dir_depth = this->GetContentDirectoryDepth(); @@ -682,9 +737,11 @@ namespace sts::ncm { R_TRY(TraverseDirectory(placeholder_root_path, dir_depth, fix_file_attributes)); return ResultSuccess; + R_DEBUG_END } Result ContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(Out out_rights_id, Out out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -743,6 +800,7 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/ncm_fs.cpp b/stratosphere/ncm/source/ncm_fs.cpp index 3fecec315..908f13e43 100644 --- a/stratosphere/ncm/source/ncm_fs.cpp +++ b/stratosphere/ncm/source/ncm_fs.cpp @@ -180,7 +180,15 @@ namespace sts::ncm { return ResultSuccess; } - std::map g_mount_content_storage; + constexpr const char* SystemContentMountName = "@SystemContent"; + constexpr const char* UserContentMountName = "@UserContent"; + constexpr const char* SdCardContentMountName = "@SdCardContent"; + constexpr const char* GameCardMountNameBase = "@Gc"; + + constexpr const char* GameCardPartitionLetters[3] = { "U", "N", "S" }; + + /* Maps mount names to their common mount names. */ + std::map g_mount_content_storage; Result MountContentStorage(const char* mount_point, FsContentStorageId id) { if (!mount_point) { @@ -194,11 +202,30 @@ namespace sts::ncm { std::abort(); } - g_mount_content_storage[mount_point] = id; + switch (id) { + case FS_CONTENTSTORAGEID_NandSystem: + g_mount_content_storage[mount_point] = SystemContentMountName; + break; + + case FS_CONTENTSTORAGEID_NandUser: + g_mount_content_storage[mount_point] = UserContentMountName; + break; + + case FS_CONTENTSTORAGEID_SdCard: + g_mount_content_storage[mount_point] = SdCardContentMountName; + break; + + default: + std::abort(); + }; return ResultSuccess; } Result MountGameCardPartition(const char* mount_point, const FsGameCardHandle handle, FsGameCardPartiton partition) { + if (partition > 2) { + std::abort(); + } + FsFileSystem fs; R_TRY(fsOpenGameCardFileSystem(&fs, &handle, partition)); @@ -206,6 +233,9 @@ namespace sts::ncm { std::abort(); } + MountName mount = {0}; + snprintf(mount.name, sizeof(MountName), "%s%s%08x", GameCardMountNameBase, GameCardPartitionLetters[partition], handle.value); + g_mount_content_storage[mount_point] = mount.name; return ResultSuccess; } @@ -224,10 +254,6 @@ namespace sts::ncm { return ResultSuccess; } - constexpr const char* SystemContentMountName = "@SystemContent"; - constexpr const char* UserContentMountName = "@UserContent"; - constexpr const char* SdCardContentMountName = "@SdCardContent"; - Result ConvertToFsCommonPath(char* out_common_path, size_t out_len, const char* path) { if (!out_common_path || !path) { return ResultFsNullptrArgument; @@ -247,32 +273,14 @@ namespace sts::ncm { return ResultFsMountNameNotFound; } - FsContentStorageId content_storage_id = g_mount_content_storage[mount_name.name]; char translated_path[FS_MAX_PATH] = {0}; - const char* common_mount_name; - - switch (content_storage_id) { - case FS_CONTENTSTORAGEID_NandSystem: - common_mount_name = SystemContentMountName; - break; - - case FS_CONTENTSTORAGEID_NandUser: - common_mount_name = UserContentMountName; - break; - - case FS_CONTENTSTORAGEID_SdCard: - common_mount_name = SdCardContentMountName; - break; - - default: - std::abort(); - }; + std::string common_mount_name = g_mount_content_storage[mount_name.name]; if (fsdevTranslatePath(path, NULL, translated_path) == -1) { std::abort(); } - snprintf(out_common_path, out_len, "%s:%s", common_mount_name, translated_path); + snprintf(out_common_path, out_len, "%s:%s", common_mount_name.c_str(), translated_path); return ResultSuccess; } diff --git a/stratosphere/ncm/source/ncm_main.cpp b/stratosphere/ncm/source/ncm_main.cpp index 2c450e540..787fb0988 100644 --- a/stratosphere/ncm/source/ncm_main.cpp +++ b/stratosphere/ncm/source/ncm_main.cpp @@ -27,7 +27,6 @@ extern "C" { u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x60000 #define INNER_HEAP_SIZE 0x100000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -45,10 +44,52 @@ extern "C" { sts::ncm::TitleId __stratosphere_title_id = sts::ncm::TitleId::Ncm; +namespace { + + /* Convenience definitions. */ + constexpr uintptr_t IramBase = 0x40000000ull; + constexpr uintptr_t IramPayloadBase = 0x40010000ull; + constexpr size_t IramSize = 0x40000; + constexpr size_t IramPayloadMaxSize = 0x2E000; + + /* Globals. */ + u8 __attribute__ ((aligned (0x1000))) g_work_page[0x1000]; + + /* Helpers. */ + void ClearIram() { + /* Make page FFs. */ + memset(g_work_page, 0xFF, sizeof(g_work_page)); + + /* Overwrite all of IRAM with FFs. */ + for (size_t ofs = 0; ofs < IramSize; ofs += sizeof(g_work_page)) { + CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page)); + } + } + + void DoReboot(AtmosphereFatalErrorContext *ctx) { + /* Ensure clean IRAM state. */ + ClearIram(); + + /* Copy in fatal error context, if relevant. */ + if (ctx != nullptr) { + std::memset(g_work_page, 0xCC, sizeof(g_work_page)); + std::memcpy(g_work_page, ctx, sizeof(*ctx)); + CopyToIram(IramPayloadBase + IramPayloadMaxSize, g_work_page, sizeof(g_work_page)); + } + + RebootToRcm(); + } + +} + void __libnx_exception_handler(ThreadExceptionDump *ctx) { StratosphereCrashHandler(ctx); } +void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) { + DoReboot(ctx); +} + void __libnx_initheap(void) { void* addr = nx_inner_heap; size_t size = nx_inner_heap_size; diff --git a/stratosphere/ncm/source/ncm_readonlycontentstorage.cpp b/stratosphere/ncm/source/ncm_readonlycontentstorage.cpp index 246fa05b5..dc4484c63 100644 --- a/stratosphere/ncm/source/ncm_readonlycontentstorage.cpp +++ b/stratosphere/ncm/source/ncm_readonlycontentstorage.cpp @@ -18,9 +18,12 @@ #include "ncm_path_utils.hpp" #include "ncm_readonlycontentstorage.hpp" +#include "debug.hpp" + namespace sts::ncm { Result ReadOnlyContentStorageInterface::Initialize(const char* root_path, MakeContentPathFunc content_path_func) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -34,37 +37,53 @@ namespace sts::ncm { strncpy(this->root_path, root_path, FS_MAX_PATH-2); this->make_content_path_func = *content_path_func; return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GeneratePlaceHolderId(Out out) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::DeletePlaceHolder(PlaceHolderId placeholder_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::HasPlaceHolder(Out out, PlaceHolderId placeholder_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, InBuffer data) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::Register(PlaceHolderId placeholder_id, ContentId content_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::Delete(ContentId content_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::Has(Out out, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -82,9 +101,11 @@ namespace sts::ncm { out.SetValue(has); return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetPath(OutPointerWithServerSize out, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -104,29 +125,41 @@ namespace sts::ncm { *out.pointer = common_path; return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetPlaceHolderPath(OutPointerWithServerSize out, PlaceHolderId placeholder_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::CleanupAllPlaceHolder() { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::ListPlaceHolder(Out out_count, OutBuffer out_buf) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetContentCount(Out out_count) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::ListContentId(Out out_count, OutBuffer out_buf, u32 start_offset) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetSizeFromContentId(Out out_size, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -148,22 +181,30 @@ namespace sts::ncm { out_size.SetValue(st.st_size); return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::DisableForcibly() { + R_DEBUG_START this->disabled = true; return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::ReadContentIdFile(OutBuffer buf, ContentId content_id, u64 offset) { + R_DEBUG_START /* Offset is too large */ if (offset >> 0x3f != 0) { return ResultNcmInvalidOffset; @@ -201,13 +242,17 @@ namespace sts::ncm { } return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderId(Out out_rights_id, Out out_key_generation, PlaceHolderId placeholder_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetRightsIdFromContentId(Out out_rights_id, Out out_key_generation, ContentId content_id) { + R_DEBUG_START if (this->disabled) { return ResultNcmInvalidContentStorage; } @@ -233,36 +278,51 @@ namespace sts::ncm { out_key_generation.SetValue(static_cast(key_generation)); return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::WriteContentForDebug(ContentId content_id, u64 offset, InBuffer data) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetFreeSpaceSize(Out out_size) { + R_DEBUG_START out_size.SetValue(0); return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetTotalSpaceSize(Out out_size) { + R_DEBUG_START out_size.SetValue(0); return ResultSuccess; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::FlushPlaceHolder() { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetSizeFromPlaceHolderId(Out out, PlaceHolderId placeholder_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::RepairInvalidFileAttribute() { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } Result ReadOnlyContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(Out out_rights_id, Out out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) { + R_DEBUG_START return ResultNcmInvalidContentStorageOperation; + R_DEBUG_END } } \ No newline at end of file diff --git a/stratosphere/ncm/source/ncm_types.hpp b/stratosphere/ncm/source/ncm_types.hpp index 98f4a81df..e7d649291 100644 --- a/stratosphere/ncm/source/ncm_types.hpp +++ b/stratosphere/ncm/source/ncm_types.hpp @@ -44,6 +44,7 @@ namespace sts::ncm { typedef Uuid PlaceHolderId; enum class ContentMetaType : u8 { + Unknown = 0x0, SystemProgram = 0x1, SystemData = 0x2, SystemUpdate = 0x3, @@ -107,29 +108,24 @@ namespace sts::ncm { } bool operator==(const ContentMetaKey& other) const { - if (this->id != other.id) { - return false; - } - - if (this->version != other.version) { - return false; - } - - if (this->type != other.type) { - return false; - } - - if (this->install_type != other.install_type) { - return false; - } - - return true; + return this->id == other.id && + this->version == other.version && + this->type == other.type && + this->install_type == other.install_type; } bool operator!=(const ContentMetaKey& other) const { return !(*this == other); } - } PACKED; + + static constexpr ContentMetaKey Make(TitleId title_id, u32 version, ContentMetaType type) { + return { .id = title_id, .version = version, .type = type }; + } + + static constexpr ContentMetaKey Make(TitleId title_id, u32 version, ContentMetaType type, ContentInstallType install_type) { + return { .id = title_id, .version = version, .type = type, .install_type = install_type }; + } + }; static_assert(sizeof(ContentMetaKey) == 0x10, "ContentMetaKey definition!"); @@ -139,14 +135,16 @@ namespace sts::ncm { struct ApplicationContentMetaKey { ContentMetaKey key; TitleId application_title_id; - } PACKED; + }; + + static_assert(sizeof(ApplicationContentMetaKey) == 0x18, "ApplicationContentMetaKey definition!"); struct ContentInfo { ContentId content_id; u8 size[6]; ContentType content_type; u8 id_offset; - } PACKED; + }; static_assert(sizeof(ContentInfo) == 0x18, "ContentInfo definition!");