diff --git a/README.md b/README.md index 8cf203baf..67768c78c 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project as GPLv2 or later. +* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license. Credits ===== diff --git a/docs/changelog.md b/docs/changelog.md index 6c112f402..f71da6810 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,18 @@ # Changelog +## 0.10.3 ++ Support was added for 9.2.0. ++ Support was added for redirecting manual html content for games. + + This works like normal layeredfs, replacing content placed in `/atmosphere/contents//manual_html/`. + + This allows for game mods/translations to provide custom manual content, if they so choose. ++ A number of improvements were made to Atmosphere's memory usage, including: + + `fatal` now uses STB instead of freetype for rendering. + + This saves around 1 MB of memory, and makes our fatal substantially leaner than Nintendo's. + + `sm` no longer wastes 2 MiB unnecessarily. ++ fusee/sept's sdmmc access now better matches official behavior. + + This improves compatibility with some SD cards. ++ `ro` has been updated to reflect changes made in 9.1.0. ++ The temporary auto-migration added in 0.10.0 has been removed, since the transitionary period is well over. ++ General system stability improvements to enhance the user's experience. ## 0.10.2 + hbl configuration was made more flexible. + Up to eight specific program ids can now be specified to have their own override keys. diff --git a/fusee/fusee-secondary/src/kernel_patches.c b/fusee/fusee-secondary/src/kernel_patches.c index 659ce8e08..0a6c4c079 100644 --- a/fusee/fusee-secondary/src/kernel_patches.c +++ b/fusee/fusee-secondary/src/kernel_patches.c @@ -801,6 +801,16 @@ static const kernel_info_t g_kernel_infos[] = { .embedded_ini_ptr = 0x180, .free_code_space_offset = 0x65780, KERNEL_PATCHES(900) + }, + { /* 9.2.0. */ + /* NOTE: 9.2.0 has identical kernel layout to 9.0.0, so patches may be reused. */ + .hash = {0x66, 0xE7, 0x73, 0xE7, 0xF5, 0xCB, 0x9B, 0xB8, 0x66, 0xB7, 0xB1, 0x26, 0x23, 0x02, 0x76, 0xF2, 0xD1, 0x60, 0x3E, 0x09, 0x14, 0x19, 0xC2, 0x84, 0xFA, 0x5D, 0x0F, 0x16, 0xA3, 0x65, 0xFA, 0x17}, + .hash_offset = 0x1C0, + .hash_size = 0x90000 - 0x1C0, + .embedded_ini_offset = 0x90000, + .embedded_ini_ptr = 0x180, + .free_code_space_offset = 0x65780, + KERNEL_PATCHES(900) } }; diff --git a/libraries/.gitrepo b/libraries/.gitrepo index c91f69c36..327857bdb 100644 --- a/libraries/.gitrepo +++ b/libraries/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/Atmosphere-NX/Atmosphere-libs branch = master - commit = 08c9b3cbf85471fe6adb5f42ba9f03357a5f633a - parent = 814c9d1cfb54c192bc1deb140ab476c9f3dd0edf + commit = 83aa6133ee2eb43287f8fc373d309a0c99337429 + parent = fd34e2342a66b2aa3062ea7cecaf9728f12ef21a method = merge - cmdver = 0.4.0 + cmdver = 0.4.1 diff --git a/libraries/README.md b/libraries/README.md index da207a789..4bc5792fb 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -11,6 +11,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project as GPLv2 or later. +* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project under the Zero-Clause BSD license. Credits ===== diff --git a/libraries/libmesosphere/README.md b/libraries/libmesosphere/README.md index 88da81b25..bcdb67b94 100644 --- a/libraries/libmesosphere/README.md +++ b/libraries/libmesosphere/README.md @@ -11,6 +11,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project as GPLv2 or later. +* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project under the Zero-Clause BSD license. Credits ===== diff --git a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp index db644ec1a..65451a9b6 100644 --- a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp @@ -63,7 +63,7 @@ namespace ams::kern::init { constexpr size_t SlabCountKTransferMemory = 200; constexpr size_t SlabCountKCodeMemory = 10; constexpr size_t SlabCountKDeviceAddressSpace = 300; - constexpr size_t SlabCountKSession = 900; + constexpr size_t SlabCountKSession = 933; constexpr size_t SlabCountKLightSession = 100; constexpr size_t SlabCountKObjectName = 7; constexpr size_t SlabCountKResourceLimit = 5; diff --git a/libraries/libstratosphere/README.md b/libraries/libstratosphere/README.md index 0dc7138b4..7fd00f8b5 100644 --- a/libraries/libstratosphere/README.md +++ b/libraries/libstratosphere/README.md @@ -15,6 +15,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project as GPLv2 or later. +* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project under the Zero-Clause BSD license. Credits ===== @@ -29,3 +30,4 @@ In addition to those credited in [Atmosphère's credits](https://github.com/Atmo * __misson20000__ * __neobrain__ * __yellows8__ +* @[Nintendo](https://github.com/Nintendo) diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_readonly_filesystem_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_readonly_filesystem_adapter.hpp new file mode 100644 index 000000000..9c3c031d3 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_readonly_filesystem_adapter.hpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018-2020 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 +#include +#include + +namespace ams::fs { + + class ReadOnlyFileAdapter : public fsa::IFile { + NON_COPYABLE(ReadOnlyFileAdapter); + private: + std::unique_ptr base_file; + public: + ReadOnlyFileAdapter(fsa::IFile *f) : base_file(f) { /* ... */ } + ReadOnlyFileAdapter(std::unique_ptr f) : base_file(std::move(f)) { /* ... */ } + virtual ~ReadOnlyFileAdapter() { /* ... */ } + public: + virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { + /* Ensure that we can read these extents. */ + size_t read_size = 0; + R_TRY(this->DryRead(std::addressof(read_size), offset, size, option, fs::OpenMode_Read)); + + /* Validate preconditions. */ + AMS_ASSERT(offset >= 0); + AMS_ASSERT(buffer != nullptr || size == 0); + + return this->base_file->Read(out, offset, buffer, size, option); + } + + virtual Result GetSizeImpl(s64 *out) override final { + return this->base_file->GetSize(out); + } + + virtual Result FlushImpl() override final { + return ResultSuccess(); + } + + virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result SetSizeImpl(s64 size) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { + /* TODO: How should this be handled? */ + return fs::ResultNotImplemented(); + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + return this->base_file->GetDomainObjectId(); + } + }; + + class ReadOnlyFileSystemAdapter : public fsa::IFileSystem { + NON_COPYABLE(ReadOnlyFileSystemAdapter); + private: + std::shared_ptr shared_fs; + std::unique_ptr unique_fs; + protected: + fsa::IFileSystem * const base_fs; + public: + template + explicit ReadOnlyFileSystemAdapter(std::shared_ptr fs) : shared_fs(std::move(fs)), base_fs(shared_fs.get()) { static_assert(std::is_base_of::value); } + + template + explicit ReadOnlyFileSystemAdapter(std::unique_ptr fs) : unique_fs(std::move(fs)), base_fs(unique_fs.get()) { static_assert(std::is_base_of::value); } + + virtual ~ReadOnlyFileSystemAdapter() { /* ... */ } + public: + virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteFileImpl(const char *path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result CreateDirectoryImpl(const char *path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteDirectoryImpl(const char *path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final { + return fs::ResultUnsupportedOperation(); + } + + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final { + return this->base_fs->GetEntryType(out, path); + } + + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + std::unique_ptr f; + R_TRY(this->base_fs->OpenFile(std::addressof(f), path, mode)); + + *out_file = std::make_unique(std::move(f)); + return ResultSuccess(); + } + + virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + return this->base_fs->OpenDirectory(out_dir, path, mode); + } + + virtual Result CommitImpl() override final { + return ResultSuccess(); + } + + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result CleanDirectoryRecursivelyImpl(const char *path) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) { + return this->base_fs->GetFileTimeStampRaw(out, path); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp index 931a63bd5..5466dfe80 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp @@ -83,20 +83,22 @@ namespace ams::fs::fsa { /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0; protected: - Result DryRead(size_t *out, s64 offset, size_t size, const ReadOption &option, fs::OpenMode mode) { - R_UNLESS((mode & fs::OpenMode_Read) != 0, fs::ResultInvalidOperationForOpenMode()); + Result DryRead(size_t *out, s64 offset, size_t size, const fs::ReadOption &option, OpenMode open_mode) { + /* Check that we can read. */ + R_UNLESS((open_mode & OpenMode_Read) != 0, fs::ResultInvalidOperationForOpenMode()); + /* Get the file size, and validate our offset. */ s64 file_size = 0; - R_TRY(this->GetSize(std::addressof(file_size))); + R_TRY(this->GetSize(&file_size)); R_UNLESS(offset <= file_size, fs::ResultOutOfRange()); - const size_t readable_size = file_size - offset; - *out = std::min(readable_size, size); + *out = static_cast(std::min(file_size - offset, static_cast(size))); return ResultSuccess(); } - Result DrySetSize(s64 size, fs::OpenMode mode) { - R_UNLESS((mode & fs::OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode()); + Result DrySetSize(s64 size, fs::OpenMode open_mode) { + /* Check that we can write. */ + R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode()); AMS_ASSERT(size >= 0); diff --git a/libraries/libvapours/include/vapours/ams/ams_api_version.h b/libraries/libvapours/include/vapours/ams/ams_api_version.h index db082832e..6b739942d 100644 --- a/libraries/libvapours/include/vapours/ams/ams_api_version.h +++ b/libraries/libvapours/include/vapours/ams/ams_api_version.h @@ -17,10 +17,10 @@ #define ATMOSPHERE_RELEASE_VERSION_MAJOR 0 #define ATMOSPHERE_RELEASE_VERSION_MINOR 10 -#define ATMOSPHERE_RELEASE_VERSION_MICRO 2 +#define ATMOSPHERE_RELEASE_VERSION_MICRO 3 #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 9 -#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 diff --git a/libraries/libvapours/include/vapours/types.hpp b/libraries/libvapours/include/vapours/types.hpp index 0d4b4b6f0..d77ea21fe 100644 --- a/libraries/libvapours/include/vapours/types.hpp +++ b/libraries/libvapours/include/vapours/types.hpp @@ -69,12 +69,12 @@ typedef u32 Result; ///< Function error code result type. /// Creates a bitmask for bit range extraction. #ifndef MASK2 -#define MASK2(a,b) (MASK(a) & ~MASK(b)) +#define MASK2(a,b) (MASK((a) + 1) & ~MASK(b)) #endif /// Creates a bitmask for bit range extraction (long). #ifndef MASK2L -#define MASK2L(a,b) (MASKL(a) & ~MASKL(b)) +#define MASK2L(a,b) (MASKL((a) + 1) & ~MASKL(b)) #endif /// Marks a function as not returning, for the purposes of compiler optimization. diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp index e622610b9..c43c92ca7 100644 --- a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp @@ -32,38 +32,6 @@ namespace ams::mitm::fs { return ResultSuccess(); } - void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path) { - if (src_path[0] == '/') { - std::snprintf(dst_path, dst_path_size, "/atmosphere%s", src_path); - } else { - std::snprintf(dst_path, dst_path_size, "/atmosphere/%s", src_path); - } - } - - void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path) { - if (src_path[0] == '/') { - std::snprintf(dst_path, dst_path_size, "/atmosphere/%s%s", subdir, src_path); - } else { - std::snprintf(dst_path, dst_path_size, "/atmosphere/%s/%s", subdir, src_path); - } - } - - void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) { - if (src_path[0] == '/') { - std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx%s", static_cast(program_id), src_path); - } else { - std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s", static_cast(program_id), src_path); - } - } - - void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path) { - if (src_path[0] == '/') { - std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s%s", static_cast(program_id), subdir, src_path); - } else { - std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s/%s", static_cast(program_id), subdir, src_path); - } - } - void FormatAtmosphereRomfsPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) { return FormatAtmosphereSdPath(dst_path, dst_path_size, program_id, "romfs", src_path); } @@ -154,14 +122,36 @@ namespace ams::mitm::fs { return fsFsOpenDirectory(fs, fixed_path, mode, out); } - /* TODO: Remove this in Atmosphere 0.10.2. */ - Result RenameProgramDirectoryForCompatibility(const char *dir_name) { - R_TRY(EnsureSdInitialized()); - char titles_fixed_path[ams::fs::EntryNameLengthMax + 1]; - char contents_fixed_path[ams::fs::EntryNameLengthMax + 1]; - FormatAtmosphereSdPath(titles_fixed_path, sizeof(titles_fixed_path), "titles", dir_name); - FormatAtmosphereSdPath(contents_fixed_path, sizeof(contents_fixed_path), "contents", dir_name); - return fsFsRenameDirectory(&g_sd_filesystem, titles_fixed_path, contents_fixed_path); + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path) { + if (src_path[0] == '/') { + std::snprintf(dst_path, dst_path_size, "/atmosphere%s", src_path); + } else { + std::snprintf(dst_path, dst_path_size, "/atmosphere/%s", src_path); + } + } + + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path) { + if (src_path[0] == '/') { + std::snprintf(dst_path, dst_path_size, "/atmosphere/%s%s", subdir, src_path); + } else { + std::snprintf(dst_path, dst_path_size, "/atmosphere/%s/%s", subdir, src_path); + } + } + + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) { + if (src_path[0] == '/') { + std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx%s", static_cast(program_id), src_path); + } else { + std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s", static_cast(program_id), src_path); + } + } + + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path) { + if (src_path[0] == '/') { + std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s%s", static_cast(program_id), subdir, src_path); + } else { + std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s/%s", static_cast(program_id), subdir, src_path); + } } bool HasSdRomfsContent(ncm::ProgramId program_id) { diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp index 1be565201..974df3243 100644 --- a/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp +++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp @@ -38,8 +38,10 @@ namespace ams::mitm::fs { Result OpenAtmosphereSdRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode); Result OpenAtmosphereRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs); - /* TODO: Remove this in Atmosphere 0.10.2. */ - Result RenameProgramDirectoryForCompatibility(const char *dir_name); + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path); + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path); + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path); + void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path); bool HasSdRomfsContent(ncm::ProgramId program_id); diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp index 8ed331785..90b073871 100644 --- a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp @@ -179,23 +179,6 @@ namespace ams::mitm { } } - void RenameTitlesDirectoryProgramFoldersForCompatibility() { - FsDir titles_dir; - if (R_FAILED(mitm::fs::OpenAtmosphereSdDirectory(&titles_dir, "/titles", ams::fs::OpenDirectoryMode_Directory))) { - return; - } - ON_SCOPE_EXIT { fsDirClose(&titles_dir); }; - - ams::fs::DirectoryEntry dir_entry; - s64 read_entries; - while (R_SUCCEEDED(fsDirRead(&titles_dir, &read_entries, 1, &dir_entry)) && read_entries == 1) { - if (strlen(dir_entry.name) == 2 * sizeof(ncm::ProgramId) && IsHexadecimal(dir_entry.name)) { - /* We found a program directory, try to rename it. Failure is allowed. */ - mitm::fs::RenameProgramDirectoryForCompatibility(dir_entry.name); - } - } - } - /* Initialization implementation */ void InitializeThreadFunc(void *arg) { /* Wait for the SD card to be ready. */ @@ -211,10 +194,6 @@ namespace ams::mitm { /* Backup Calibration Binary and BIS keys. */ CreateAutomaticBackups(); - /* Rename program folders in the titles directory. */ - /* TODO: Remove this in Atmosphere 0.10.2. */ - RenameTitlesDirectoryProgramFoldersForCompatibility(); - /* If we're emummc, persist a write-handle to prevent other processes from touching the image. */ if (emummc::IsActive()) { if (const char *emummc_file_path = emummc::GetFilePath(); emummc_file_path != nullptr) { diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp index e6ad2d423..7fffa4d43 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp @@ -19,6 +19,7 @@ #include "fsmitm_boot0storage.hpp" #include "fsmitm_layered_romfs_storage.hpp" #include "fsmitm_save_utils.hpp" +#include "fsmitm_readonly_layered_filesystem.hpp" namespace ams::mitm::fs { @@ -27,6 +28,7 @@ namespace ams::mitm::fs { namespace { constexpr const char AtmosphereHblWebContentDir[] = "/atmosphere/hbl_html/"; + constexpr const char ProgramWebContentDir[] = "/manual_html/"; os::Mutex g_data_storage_lock; os::Mutex g_storage_cache_lock; @@ -67,8 +69,6 @@ namespace ams::mitm::fs { Result OpenHblWebContentFileSystem(sf::Out> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type) { /* Verify eligibility. */ bool is_hbl; - R_UNLESS(ncm::IsWebAppletId(client_program_id), sm::mitm::ResultShouldForwardToSession()); - R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession()); R_UNLESS(R_SUCCEEDED(pm::info::IsHblProgramId(&is_hbl, program_id)), sm::mitm::ResultShouldForwardToSession()); R_UNLESS(is_hbl, sm::mitm::ResultShouldForwardToSession()); @@ -85,18 +85,79 @@ namespace ams::mitm::fs { const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&sd_fs.s)}; std::unique_ptr sd_ifs = std::make_unique(sd_fs); - out.SetValue(std::make_shared(std::make_shared(std::move(sd_ifs), AtmosphereHblWebContentDir), false), target_object_id); + out.SetValue(std::make_shared(std::make_shared(std::make_unique(std::move(sd_ifs), AtmosphereHblWebContentDir)), false), target_object_id); return ResultSuccess(); } + Result OpenProgramSpecificWebContentFileSystem(sf::Out> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id) { + /* Directory must exist. */ + { + FsDir d; + R_UNLESS(R_SUCCEEDED(mitm::fs::OpenAtmosphereSdDirectory(&d, program_id, ProgramWebContentDir, fs::OpenDirectoryMode_Directory)), sm::mitm::ResultShouldForwardToSession()); + fsDirClose(&d); + } + + /* Open the SD card using fs.mitm's session. */ + FsFileSystem sd_fs; + R_TRY(fsOpenSdCardFileSystem(&sd_fs)); + const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&sd_fs.s)}; + std::unique_ptr sd_ifs = std::make_unique(sd_fs); + + /* Format the subdirectory path. */ + char program_web_content_path[fs::EntryNameLengthMax + 1]; + FormatAtmosphereSdPath(program_web_content_path, sizeof(program_web_content_path), program_id, ProgramWebContentDir); + + /* Make a new filesystem. */ + { + std::unique_ptr subdir_fs = std::make_unique(std::move(sd_ifs), program_web_content_path); + std::shared_ptr new_fs = nullptr; + + /* Try to open the existing fs. */ + FsFileSystem base_fs; + bool opened_base_fs = false; + if (with_id) { + opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), static_cast(program_id), filesystem_type, path->str)); + } else { + opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithPatchFwd(fwd, std::addressof(base_fs), static_cast(program_id), filesystem_type)); + } + + if (opened_base_fs) { + /* Create a layered adapter. */ + new_fs = std::make_shared(std::move(subdir_fs), std::make_unique(base_fs)); + } else { + /* Without an existing FS, just make a read only adapter to the subdirectory. */ + new_fs = std::make_shared(std::move(subdir_fs)); + } + + out.SetValue(std::make_shared(std::move(new_fs), false), target_object_id); + } + + return ResultSuccess(); + } + + Result OpenWebContentFileSystem(sf::Out> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool try_program_specific) { + /* Check first that we're a web applet opening web content. */ + R_UNLESS(ncm::IsWebAppletProgramId(client_program_id), sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession()); + + /* Try to mount the HBL web filesystem. If this succeeds then we're done. */ + R_UNLESS(R_FAILED(OpenHblWebContentFileSystem(out, client_program_id, program_id, filesystem_type)), ResultSuccess()); + + /* If program specific override shouldn't be attempted, fall back. */ + R_UNLESS(try_program_specific, sm::mitm::ResultShouldForwardToSession()); + + /* If we're not opening a HBL filesystem, just try to open a generic one. */ + return OpenProgramSpecificWebContentFileSystem(out, client_program_id, program_id, filesystem_type, fwd, path, with_id); + } + } Result FsMitmService::OpenFileSystemWithPatch(sf::Out> out, ncm::ProgramId program_id, u32 _filesystem_type) { - return OpenHblWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast(_filesystem_type)); + return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast(_filesystem_type), this->forward_service.get(), nullptr, false, this->client_info.override_status.IsProgramSpecific()); } Result FsMitmService::OpenFileSystemWithId(sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type) { - return OpenHblWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast(_filesystem_type)); + return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast(_filesystem_type), this->forward_service.get(), std::addressof(path), true, this->client_info.override_status.IsProgramSpecific()); } Result FsMitmService::OpenSdCardFileSystem(sf::Out> out) { diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c index 2a89fb939..38324f069 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c @@ -63,3 +63,29 @@ Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpac .out_objects = &out->s, ); } + +Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) { + const struct { + u32 fsType; + u64 id; + } in = { fsType, id }; + + return serviceDispatchIn(s, 7, in, + .out_num_objects = 1, + .out_objects = &out->s + ); +} + +Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath) { + const struct { + u32 fsType; + u64 id; + } in = { fsType, id }; + + return serviceDispatchIn(s, 8, in, + .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In }, + .buffers = { { contentPath, FS_MAX_PATH } }, + .out_num_objects = 1, + .out_objects = &out->s + ); +} \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h index a39278a28..5af0f4c09 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h @@ -19,6 +19,9 @@ Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, Ncm Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr); +Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType); +Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath); + #ifdef __cplusplus } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp new file mode 100644 index 000000000..de07e1358 --- /dev/null +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018-2020 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 + +namespace ams::mitm::fs { + + class ReadOnlyLayeredFileSystem : public ams::fs::fsa::IFileSystem { + private: + ams::fs::ReadOnlyFileSystemAdapter fs_1; + ams::fs::ReadOnlyFileSystemAdapter fs_2; + public: + explicit ReadOnlyLayeredFileSystem(std::unique_ptr a, std::unique_ptr b) : fs_1(std::move(a)), fs_2(std::move(b)) { /* ... */ } + + virtual ~ReadOnlyLayeredFileSystem() { /* ... */ } + private: + virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteFileImpl(const char *path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result CreateDirectoryImpl(const char *path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteDirectoryImpl(const char *path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result GetEntryTypeImpl(ams::fs::DirectoryEntryType *out, const char *path) override final { + R_UNLESS(R_FAILED(this->fs_1.GetEntryType(out, path)), ResultSuccess()); + return this->fs_2.GetEntryType(out, path); + } + + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, ams::fs::OpenMode mode) override final { + R_UNLESS(R_FAILED(this->fs_1.OpenFile(out_file, path, mode)), ResultSuccess()); + return this->fs_2.OpenFile(out_file, path, mode); + } + + virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, ams::fs::OpenDirectoryMode mode) override final { + R_UNLESS(R_FAILED(this->fs_1.OpenDirectory(out_dir, path, mode)), ResultSuccess()); + return this->fs_2.OpenDirectory(out_dir, path, mode); + } + + virtual Result CommitImpl() override final { + return ResultSuccess(); + } + + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result CleanDirectoryRecursivelyImpl(const char *path) { + return ams::fs::ResultUnsupportedOperation(); + } + + virtual Result GetFileTimeStampRawImpl(ams::fs::FileTimeStampRaw *out, const char *path) { + R_UNLESS(R_FAILED(this->fs_1.GetFileTimeStampRaw(out, path)), ResultSuccess()); + return this->fs_2.GetFileTimeStampRaw(out, path); + } + }; + +} diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp index efe895e18..b0d037f7a 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp @@ -114,7 +114,7 @@ namespace ams::mitm::fs { os::Mutex g_fs_romfs_path_lock; char g_fs_romfs_path_buffer[fs::EntryNameLengthMax + 1]; - __attribute__((noinline)) void OpenFileSystemRomfsDirectory(FsDir *out, ncm::ProgramId program_id, BuildDirectoryContext *parent, fs::OpenDirectoryMode mode, FsFileSystem *fs) { + NOINLINE void OpenFileSystemRomfsDirectory(FsDir *out, ncm::ProgramId program_id, BuildDirectoryContext *parent, fs::OpenDirectoryMode mode, FsFileSystem *fs) { std::scoped_lock lk(g_fs_romfs_path_lock); parent->GetPath(g_fs_romfs_path_buffer); R_ABORT_UNLESS(mitm::fs::OpenAtmosphereRomfsDirectory(out, program_id, g_fs_romfs_path_buffer, mode, fs)); diff --git a/stratosphere/pm/source/impl/pm_resource_manager.cpp b/stratosphere/pm/source/impl/pm_resource_manager.cpp index 48132b641..cfff9bbc9 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.cpp +++ b/stratosphere/pm/source/impl/pm_resource_manager.cpp @@ -35,6 +35,7 @@ namespace ams::pm::resource { constexpr size_t ExtraSystemEventCount600 = 100; constexpr size_t ExtraSystemSessionCount600 = 100; constexpr size_t ReservedMemorySize600 = 5_MB; + constexpr size_t ExtraSystemSessionCount920 = 33; /* Atmosphere always allocates extra memory for system usage. */ constexpr size_t ExtraSystemMemorySizeAtmosphere = 24_MB; @@ -205,6 +206,12 @@ namespace ams::pm::resource { g_resource_limits[ResourceLimitGroup_System][LimitableResource_Events] += ExtraSystemEventCount600; g_resource_limits[ResourceLimitGroup_System][LimitableResource_Sessions] += ExtraSystemSessionCount600; } + if (hos_version >= hos::Version_900) { + /* 9.2.0 increased the system session limit. */ + /* NOTE: We don't currently support detection of minor version, so we will provide this increase on 9.0.0+. */ + /* This shouldn't impact any existing behavior in undesirable ways. */ + g_resource_limits[ResourceLimitGroup_System][LimitableResource_Sessions] += ExtraSystemSessionCount920; + } /* 7.0.0+: Calculate the number of extra application threads available. */ if (hos::GetVersion() >= hos::Version_700) {