From 7336dc2b7ab0d397139c7a793003d38c46cc11f9 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 3 Dec 2020 12:54:44 -0800 Subject: [PATCH 01/29] git subrepo push libraries subrepo: subdir: "libraries" merged: "2c3ccef1" upstream: origin: "https://github.com/Atmosphere-NX/Atmosphere-libs" branch: "master" commit: "2c3ccef1" git-subrepo: version: "0.4.1" origin: "???" commit: "???" --- libraries/.gitrepo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/.gitrepo b/libraries/.gitrepo index c03fef33f..aa9cd1291 100644 --- a/libraries/.gitrepo +++ b/libraries/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/Atmosphere-NX/Atmosphere-libs branch = master - commit = 49c1ace8906a967f2c92d369a0c66779b9cd225b - parent = 2b93bbd9ee174863dbf5c611c0d9d159fe9e6e31 + commit = 2c3ccef17e9b267a5d9d232f1aba689f2c591b95 + parent = d2f48d5e36cb2ba4e8cc014238457bd75df81797 method = merge cmdver = 0.4.1 From c45088d1cda2d0bcb6a7fb35f8c2d826728ed730 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 4 Dec 2020 18:20:56 -0800 Subject: [PATCH 02/29] kern: add support for InfoType_FreeThreadCount --- libraries/libmesosphere/source/svc/kern_svc_info.cpp | 10 ++++++++++ .../include/vapours/svc/svc_types_common.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp index adab13b27..fda723182 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp @@ -59,6 +59,7 @@ namespace ams::kern::svc { case ams::svc::InfoType_TotalNonSystemMemorySize: case ams::svc::InfoType_UsedNonSystemMemorySize: case ams::svc::InfoType_IsApplication: + case ams::svc::InfoType_FreeThreadCount: { /* These info types don't support non-zero subtypes. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); @@ -125,6 +126,15 @@ namespace ams::kern::svc { case ams::svc::InfoType_IsApplication: *out = process->IsApplication(); break; + case ams::svc::InfoType_FreeThreadCount: + if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) { + const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax); + const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax); + *out = limit_value - current_value; + } else { + *out = 0; + } + break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 26bf251ec..0630fc017 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -156,6 +156,7 @@ namespace ams::svc { InfoType_TotalNonSystemMemorySize = 21, InfoType_UsedNonSystemMemorySize = 22, InfoType_IsApplication = 23, + InfoType_FreeThreadCount = 24, InfoType_MesosphereMeta = 65000, From 73167448cc493140854a31d3ac3183125adc8040 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 4 Dec 2020 22:08:33 -0800 Subject: [PATCH 03/29] fs/system: deduplicate RomFs code --- .../fs_dbm_hierarchical_rom_file_table.hpp | 32 +- .../fs_dbm_rom_key_value_storage.hpp | 95 +-- .../fs/common/fs_dbm_rom_path_tool.hpp | 103 +++ .../fs/{ => common}/fs_dbm_rom_types.hpp | 2 +- .../stratosphere/fs/fs_dbm_rom_path_tool.hpp | 122 ---- .../stratosphere/fs/fs_romfs_filesystem.hpp | 12 +- ...system_dbm_hierarchical_rom_file_table.hpp | 684 ------------------ .../fssystem_dbm_rom_key_value_storage.hpp | 367 ---------- .../fssystem/fssystem_dbm_rom_path_tool.hpp | 114 --- .../fssystem/fssystem_dbm_rom_types.hpp | 59 -- .../fssystem/fssystem_romfs_file_system.hpp | 4 +- .../fs_dbm_hierarchical_rom_file_table.cpp | 29 +- .../fs/{ => common}/fs_dbm_rom_path_tool.cpp | 105 ++- .../source/fs/fs_romfs_filesystem.cpp | 2 +- .../fssystem/fssystem_dbm_rom_path_tool.cpp | 189 ----- .../fssystem/fssystem_romfs_filesystem.cpp | 30 +- 16 files changed, 226 insertions(+), 1723 deletions(-) rename libraries/libstratosphere/include/stratosphere/fs/{ => common}/fs_dbm_hierarchical_rom_file_table.hpp (85%) rename libraries/libstratosphere/include/stratosphere/fs/{ => common}/fs_dbm_rom_key_value_storage.hpp (73%) create mode 100644 libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp rename libraries/libstratosphere/include/stratosphere/fs/{ => common}/fs_dbm_rom_types.hpp (97%) delete mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp delete mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp delete mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp delete mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp delete mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp rename libraries/libstratosphere/source/fs/{ => common}/fs_dbm_hierarchical_rom_file_table.cpp (96%) rename libraries/libstratosphere/source/fs/{ => common}/fs_dbm_rom_path_tool.cpp (88%) delete mode 100644 libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp similarity index 85% rename from libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp rename to libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp index 25651f7e3..c8cb144b0 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp @@ -14,9 +14,9 @@ * along with this program. If not, see . */ #pragma once -#include "fs_dbm_rom_types.hpp" -#include "fs_dbm_rom_path_tool.hpp" -#include "fs_dbm_rom_key_value_storage.hpp" +#include +#include +#include namespace ams::fs { @@ -33,19 +33,23 @@ namespace ams::fs { using DirectoryInfo = RomDirectoryInfo; using FileInfo = RomFileInfo; - static constexpr RomFileId ConvertToFileId(Position pos) { + static constexpr RomFileId PositionToFileId(Position pos) { return static_cast(pos); } + + static constexpr Position FileIdToPosition(RomFileId id) { + return static_cast(id); + } private: static constexpr inline Position InvalidPosition = ~Position(); static constexpr inline Position RootPosition = 0; static constexpr inline size_t ReservedDirectoryCount = 1; - static constexpr RomDirectoryId ConvertToDirectoryId(Position pos) { + static constexpr RomDirectoryId PositionToDirectoryId(Position pos) { return static_cast(pos); } - static constexpr Position ConvertToPosition(RomDirectoryId id) { + static constexpr Position DirectoryIdToPosition(RomDirectoryId id) { return static_cast(id); } @@ -67,20 +71,20 @@ namespace ams::fs { static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; template - class EntryMapTable : public RomKeyValueStorage { + class EntryMapTable : public KeyValueRomStorageTemplate { public: using ImplKey = ImplKeyType; using ClientKey = ClientKeyType; using Value = ValueType; using Position = HierarchicalRomFileTable::Position; - using Base = RomKeyValueStorage; + using Base = KeyValueRomStorageTemplate; public: Result Add(Position *out, const ClientKeyType &key, const Value &value) { - return Base::AddImpl(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value); + return Base::AddInternal(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value); } Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) { - return Base::GetImpl(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar)); + return Base::GetInternal(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar)); } Result GetByPosition(ImplKey *out_key, Value *out_val, Position pos) { @@ -117,8 +121,8 @@ namespace ams::fs { constexpr u32 Hash() const { u32 hash = this->key.parent ^ 123456789; - const RomPathChar *name = this->name.path; - const RomPathChar *end = name + this->name.length; + const RomPathChar * name = this->name.path; + const RomPathChar * const end = name + this->name.length; while (name < end) { const u32 cur = static_cast(static_cast::type>(*(name++))); hash = ((hash >> 5) | (hash << 27)) ^ cur; @@ -134,10 +138,10 @@ namespace ams::fs { DirectoryEntryMapTable dir_table; FileEntryMapTable file_table; public: - static s64 QueryDirectoryEntryStorageSize(u32 count); static s64 QueryDirectoryEntryBucketStorageSize(s64 count); - static s64 QueryFileEntryStorageSize(u32 count); + static size_t QueryDirectoryEntrySize(size_t aux_size); static s64 QueryFileEntryBucketStorageSize(s64 count); + static size_t QueryFileEntrySize(size_t aux_size); static Result Format(SubStorage dir_bucket, SubStorage file_bucket); public: diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp similarity index 73% rename from libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp rename to libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp index 455f1cdff..4acc152d7 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp @@ -14,13 +14,13 @@ * along with this program. If not, see . */ #pragma once -#include "fs_dbm_rom_types.hpp" -#include "fs_substorage.hpp" +#include +#include namespace ams::fs { template - class RomKeyValueStorage { + class KeyValueRomStorageTemplate { public: using Key = KeyType; using Value = ValueType; @@ -57,8 +57,8 @@ namespace ams::fs { return size / sizeof(Position); } - static constexpr s64 QueryKeyValueStorageSize(u32 num) { - return num * sizeof(Element); + static constexpr size_t QueryEntrySize(size_t aux_size) { + return util::AlignUp(sizeof(Element) + aux_size, alignof(Element)); } static Result Format(SubStorage bucket, s64 count) { @@ -69,13 +69,13 @@ namespace ams::fs { return ResultSuccess(); } public: - RomKeyValueStorage() : bucket_count(), bucket_storage(), kv_storage(), total_entry_size(), entry_count() { /* ... */ } + KeyValueRomStorageTemplate() : bucket_count(), bucket_storage(), kv_storage(), total_entry_size(), entry_count() { /* ... */ } Result Initialize(const SubStorage &bucket, s64 count, const SubStorage &kv) { AMS_ASSERT(count > 0); this->bucket_storage = bucket; - this->kv_storage = kv; this->bucket_count = count; + this->kv_storage = kv; return ResultSuccess(); } @@ -100,82 +100,17 @@ namespace ams::fs { constexpr u32 GetEntryCount() const { return this->entry_count; } - - Result Add(const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { - AMS_ASSERT(aux != nullptr); - AMS_ASSERT(aux_size <= MaxAuxiliarySize); - Position pos; - return this->AddImpl(std::addressof(pos), key, hash_key, aux, aux_size, value); - } - - Result Get(Value *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { - AMS_ASSERT(aux != nullptr); - AMS_ASSERT(aux_size <= MaxAuxiliarySize); - Position pos; - return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size); - } - - void FindOpen(FindIndex *out) const { - AMS_ASSERT(out != nullptr); - - out->ind = static_cast(-1); - out->pos = InvalidPosition; - } - - Result FindNext(Key *out_key, Value *out_val, FindIndex *find) { - AMS_ASSERT(out_key != nullptr); - AMS_ASSERT(out_val != nullptr); - AMS_ASSERT(find != nullptr); - - BucketIndex ind = find->ind; - R_UNLESS((ind < this->bucket_count) || ind == static_cast(-1), fs::ResultDbmFindKeyFinished()); - - s64 kv_size; - R_TRY(this->kv_storage.GetSize(std::addressof(kv_size))); - - while (true) { - if (find->pos != InvalidPosition) { - Element elem; - R_TRY(this->ReadKeyValue(std::addressof(elem), find->pos)); - - AMS_ASSERT(elem.next == InvalidPosition || elem.next < kv_size); - find->pos = elem.next; - *out_key = elem.key; - *out_val = elem.val; - return ResultSuccess(); - } - - while (true) { - ind++; - if (ind == this->bucket_count) { - find->ind = ind; - find->pos = InvalidPosition; - return fs::ResultDbmFindKeyFinished(); - } - - Position pos; - R_TRY(this->ReadBucket(std::addressof(pos), ind)); - AMS_ASSERT(pos == InvalidPosition || pos < kv_size); - - if (pos != InvalidPosition) { - find->ind = ind; - find->pos = pos; - break; - } - } - } - } protected: - Result AddImpl(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { + Result AddInternal(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { AMS_ASSERT(out != nullptr); - AMS_ASSERT(aux != nullptr); + AMS_ASSERT(aux != nullptr || aux_size == 0); AMS_ASSERT(this->bucket_count > 0); { Position pos, prev_pos; Element elem; - const Result find_res = this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size); + const Result find_res = this->FindInternal(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size); R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists()); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res); } @@ -195,14 +130,14 @@ namespace ams::fs { return ResultSuccess(); } - Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { + Result GetInternal(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_val != nullptr); AMS_ASSERT(aux != nullptr); Position pos, prev_pos; Element elem; - R_TRY(this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size)); + R_TRY(this->FindInternal(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size)); *out_pos = pos; *out_val = elem.value; @@ -246,11 +181,11 @@ namespace ams::fs { return hash_key % this->bucket_count; } - Result FindImpl(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { + Result FindInternal(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_prev != nullptr); AMS_ASSERT(out_elem != nullptr); - AMS_ASSERT(aux != nullptr); + AMS_ASSERT(aux != nullptr || aux_size == 0); AMS_ASSERT(this->bucket_count > 0); *out_pos = 0; @@ -296,7 +231,7 @@ namespace ams::fs { *out = static_cast(this->total_entry_size); - this->total_entry_size = util::AlignUp(static_cast(end_pos), s64(4)); + this->total_entry_size = util::AlignUp(static_cast(end_pos), alignof(Position)); return ResultSuccess(); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp new file mode 100644 index 000000000..774feda17 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp @@ -0,0 +1,103 @@ +/* + * 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::fs::RomPathTool { + + constexpr inline u32 MaxPathLength = 0x300; + + struct RomEntryName { + size_t length; + const RomPathChar *path; + }; + static_assert(util::is_pod::value); + + constexpr void InitEntryName(RomEntryName *entry) { + AMS_ASSERT(entry != nullptr); + entry->length = 0; + } + + constexpr inline bool IsSeparator(RomPathChar c) { + return c == RomStringTraits::DirectorySeparator; + } + + constexpr inline bool IsNullTerminator(RomPathChar c) { + return c == RomStringTraits::NullTerminator; + } + + constexpr inline bool IsDot(RomPathChar c) { + return c == RomStringTraits::Dot; + } + + constexpr inline bool IsCurrentDirectory(const RomEntryName &name) { + return name.length == 1 && IsDot(name.path[0]); + } + + constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) { + AMS_ASSERT(p != nullptr); + return length == 1 && IsDot(p[0]); + } + + constexpr inline bool IsCurrentDirectory(const RomPathChar *p) { + AMS_ASSERT(p != nullptr); + return IsDot(p[0]) && IsNullTerminator(p[1]); + } + + constexpr inline bool IsParentDirectory(const RomEntryName &name) { + return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]); + } + + constexpr inline bool IsParentDirectory(const RomPathChar *p) { + AMS_ASSERT(p != nullptr); + return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]); + } + + constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) { + AMS_ASSERT(p != nullptr); + return length == 2 && IsDot(p[0]) && IsDot(p[1]); + } + + constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) { + AMS_ASSERT(lhs != nullptr); + AMS_ASSERT(rhs != nullptr); + return std::strncmp(lhs, rhs, length) == 0; + } + + Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p); + + class PathParser { + private: + const RomPathChar *prev_path_start; + const RomPathChar *prev_path_end; + const RomPathChar *next_path; + bool finished; + public: + constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ } + + Result Initialize(const RomPathChar *path); + void Finalize(); + + bool IsParseFinished() const; + bool IsDirectoryPath() const; + + Result GetAsDirectoryName(RomEntryName *out) const; + Result GetAsFileName(RomEntryName *out) const; + + Result GetNextDirectoryName(RomEntryName *out); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp similarity index 97% rename from libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp rename to libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp index f746af65e..c4ab66d32 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #pragma once -#include "fs_common.hpp" +#include namespace ams::fs { diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp deleted file mode 100644 index 7fc957c92..000000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 "fs_dbm_rom_types.hpp" - -namespace ams::fs { - - namespace RomPathTool { - - constexpr inline u32 MaxPathLength = 0x300; - - struct RomEntryName { - size_t length; - const RomPathChar *path; - }; - static_assert(util::is_pod::value); - - constexpr void InitializeRomEntryName(RomEntryName *entry) { - AMS_ABORT_UNLESS(entry != nullptr); - entry->length = 0; - } - - constexpr inline bool IsSeparator(RomPathChar c) { - return c == RomStringTraits::DirectorySeparator; - } - - constexpr inline bool IsNullTerminator(RomPathChar c) { - return c == RomStringTraits::NullTerminator; - } - - constexpr inline bool IsDot(RomPathChar c) { - return c == RomStringTraits::Dot; - } - - constexpr inline bool IsCurrentDirectory(const RomEntryName &name) { - return name.length == 1 && IsDot(name.path[0]); - } - - constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) { - AMS_ABORT_UNLESS(p != nullptr); - return length == 1 && IsDot(p[0]); - } - - constexpr inline bool IsCurrentDirectory(const RomPathChar *p) { - AMS_ABORT_UNLESS(p != nullptr); - return IsDot(p[0]) && IsNullTerminator(p[1]); - } - - constexpr inline bool IsParentDirectory(const RomEntryName &name) { - return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]); - } - - constexpr inline bool IsParentDirectory(const RomPathChar *p) { - AMS_ABORT_UNLESS(p != nullptr); - return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]); - } - - constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) { - AMS_ABORT_UNLESS(p != nullptr); - return length == 2 && IsDot(p[0]) && IsDot(p[1]); - } - - constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) { - AMS_ABORT_UNLESS(lhs != nullptr); - AMS_ABORT_UNLESS(rhs != nullptr); - return std::strncmp(lhs, rhs, length) == 0; - } - - constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) { - AMS_ABORT_UNLESS(rhs != nullptr); - if (strnlen(rhs, MaxPathLength) != lhs.length) { - return false; - } - return IsEqualPath(lhs.path, rhs, lhs.length); - } - - constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) { - if (lhs.length != rhs.length) { - return false; - } - return IsEqualPath(lhs.path, rhs.path, lhs.length); - } - - Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p); - - class PathParser { - private: - const RomPathChar *prev_path_start; - const RomPathChar *prev_path_end; - const RomPathChar *next_path; - bool finished; - public: - constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ } - - Result Initialize(const RomPathChar *path); - void Finalize(); - - bool IsFinished() const; - bool IsDirectoryPath() const; - - Result GetAsDirectoryName(RomEntryName *out) const; - Result GetAsFileName(RomEntryName *out) const; - - Result GetNextDirectoryName(RomEntryName *out); - }; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp index 36ae47186..b986d2a76 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp @@ -14,12 +14,12 @@ * along with this program. If not, see . */ #pragma once -#include "fs_common.hpp" -#include "impl/fs_newable.hpp" -#include "fsa/fs_ifile.hpp" -#include "fsa/fs_idirectory.hpp" -#include "fsa/fs_ifilesystem.hpp" -#include "fs_dbm_hierarchical_rom_file_table.hpp" +#include +#include +#include +#include +#include +#include namespace ams::fs { diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp deleted file mode 100644 index 390aad10e..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp +++ /dev/null @@ -1,684 +0,0 @@ -/* - * 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::fssystem { - - template - class HierarchicalRomFileTable { - private: - using DirectoryBucketStorage = DBS; - using DirectoryEntryStorage = DES; - using FileBucketStorage = FBS; - using FileEntryStorage = FES; - public: - using Position = u32; - - struct FindPosition { - Position next_dir; - Position next_file; - }; - static_assert(util::is_pod::value); - - using DirectoryInfo = RomDirectoryInfo; - using FileInfo = RomFileInfo; - - static constexpr RomFileId ConvertToFileId(Position pos) { - return static_cast(pos); - } - private: - static constexpr inline Position InvalidPosition = ~Position(); - static constexpr inline Position RootPosition = 0; - static constexpr inline size_t ReservedDirectoryCount = 1; - - static constexpr RomDirectoryId ConvertToDirectoryId(Position pos) { - return static_cast(pos); - } - - static constexpr Position ConvertToPosition(RomDirectoryId id) { - return static_cast(id); - } - - static_assert(std::is_same::value); - - struct RomDirectoryEntry { - Position next; - Position dir; - Position file; - }; - static_assert(util::is_pod::value); - - struct RomFileEntry { - Position next; - FileInfo info; - }; - static_assert(util::is_pod::value); - - static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; - - template - class EntryMapTable : public RomKeyValueStorage { - private: - using BucketStorage = BucketStorageType; - using EntryStorage = EntryStorageType; - public: - using ImplKey = ImplKeyType; - using ClientKey = ClientKeyType; - using Value = ValueType; - using Position = HierarchicalRomFileTable::Position; - using Base = RomKeyValueStorage; - public: - Result Add(Position *out, const ClientKeyType &key, const Value &value) { - return Base::AddImpl(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value); - } - - Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) const { - return Base::GetImpl(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar)); - } - - Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) const { - return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos); - } - - Result SetByPosition(Position pos, const Value &value, fs::WriteOption option) const { - return Base::SetByPosition(pos, value, option); - } - }; - - struct RomEntryKey { - Position parent; - - bool IsEqual(const RomEntryKey &rhs, const void *aux_lhs, size_t aux_lhs_size, const void *aux_rhs, size_t aux_rhs_size) const { - if (this->parent != rhs.parent) { - return false; - } - if (aux_lhs_size != aux_rhs_size) { - return false; - } - return RomPathTool::IsEqualPath(reinterpret_cast(aux_lhs), reinterpret_cast(aux_rhs), aux_lhs_size / sizeof(RomPathChar)); - } - }; - static_assert(util::is_pod::value); - - struct EntryKey { - RomEntryKey key; - RomPathTool::RomEntryName name; - - constexpr u32 Hash() const { - u32 hash = this->key.parent ^ 123456789; - const RomPathChar *name = this->name.path; - const RomPathChar *end = name + this->name.length; - while (name < end) { - const u32 cur = static_cast(static_cast::type>(*(name++))); - hash = ((hash >> 5) | (hash << 27)) ^ cur; - } - return hash; - } - }; - static_assert(util::is_pod::value); - - using DirectoryEntryMapTable = EntryMapTable; - using FileEntryMapTable = EntryMapTable; - private: - DirectoryEntryMapTable dir_table; - FileEntryMapTable file_table; - public: - static u32 QueryDirectoryEntrySize(u32 name_len) { - AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength); - return DirectoryEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar)); - } - - static u32 QueryFileEntrySize(u32 name_len) { - AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength); - return FileEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar)); - } - - static u32 QueryDirectoryEntryBucketStorageSize(u32 count) { return DirectoryEntryMapTable::QueryBucketStorageSize(count); } - static u32 QueryFileEntryBucketStorageSize(u32 count) { return FileEntryMapTable::QueryBucketStorageSize(count); } - - static Result Format(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) { - R_TRY(DirectoryEntryMapTable::Format(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size)); - R_TRY(FileEntryMapTable::Format(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size)); - return ResultSuccess(); - } - public: - HierarchicalRomFileTable() { /* ... */ } - - constexpr u32 GetDirectoryEntryCount() const { - return this->dir_table.GetEntryCount(); - } - - constexpr u32 GetFileEntryCount() const { - return this->file_table.GetEntryCount(); - } - - Result Initialize(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) { - AMS_ASSERT(dir_bucket != nullptr); - AMS_ASSERT(dir_entry != nullptr); - AMS_ASSERT(file_bucket != nullptr); - AMS_ASSERT(file_entry != nullptr); - - R_TRY(this->dir_table.Initialize(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size)); - R_TRY(this->file_table.Initialize(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size)); - - return ResultSuccess(); - } - - void Finalize() { - this->dir_table.Finalize(); - this->file_table.Finalize(); - } - - Result CreateRootDirectory() { - Position root_pos = RootPosition; - EntryKey root_key = {}; - root_key.key.parent = root_pos; - RomPathTool::InitializeRomEntryName(std::addressof(root_key.name)); - RomDirectoryEntry root_entry = { - .next = InvalidPosition, - .dir = InvalidPosition, - .file = InvalidPosition, - }; - return this->dir_table.Add(std::addressof(root_pos), root_key, root_entry); - } - - Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey new_key = {}; - R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), path)); - - R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists())); - - RomDirectoryEntry new_entry = { - .next = InvalidPosition, - .dir = InvalidPosition, - .file = InvalidPosition, - }; - - Position new_pos = 0; - R_TRY_CATCH(this->dir_table.Add(std::addressof(new_pos), new_key, new_entry)) { - R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull()) - } R_END_TRY_CATCH; - - *out = ConvertToDirectoryId(new_pos); - - if (parent_entry.dir == InvalidPosition) { - parent_entry.dir = new_pos; - - R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry, fs::WriteOption::None)); - } else { - Position cur_pos = parent_entry.dir; - while (true) { - RomEntryKey cur_key = {}; - RomDirectoryEntry cur_entry = {}; - R_TRY(this->dir_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), nullptr, nullptr, cur_pos)); - - if (cur_entry.next == InvalidPosition) { - cur_entry.next = new_pos; - - R_TRY(this->dir_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None)); - break; - } - - cur_pos = cur_entry.next; - } - } - - return ResultSuccess(); - } - - Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey new_key = {}; - R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), path)); - - R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists())); - - RomFileEntry new_entry = { - .next = InvalidPosition, - .info = info, - }; - - Position new_pos = 0; - R_TRY_CATCH(this->file_table.Add(std::addressof(new_pos), new_key, new_entry)) { - R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull()) - } R_END_TRY_CATCH; - - *out = ConvertToFileId(new_pos); - - if (parent_entry.file == InvalidPosition) { - parent_entry.file = new_pos; - - R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry, fs::WriteOption::None)); - } else { - Position cur_pos = parent_entry.file; - while (true) { - RomEntryKey cur_key = {}; - RomFileEntry cur_entry = {}; - R_TRY(this->file_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), nullptr, nullptr, cur_pos)); - - if (cur_entry.next == InvalidPosition) { - cur_entry.next = new_pos; - - R_TRY(this->file_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None)); - break; - } - - cur_pos = cur_entry.next; - } - } - - return ResultSuccess(); - } - - Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey key = {}; - R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path)); - - Position pos = 0; - RomDirectoryEntry entry = {}; - R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); - - *out = ConvertToDirectoryId(pos); - return ResultSuccess(); - } - - Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey key = {}; - R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path)); - - Position pos = 0; - RomFileEntry entry = {}; - R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key)); - - *out = ConvertToFileId(pos); - return ResultSuccess(); - } - - Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey key = {}; - R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path)); - - return this->GetDirectoryInformation(out, key); - } - - Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id) const { - AMS_ASSERT(out != nullptr); - - RomDirectoryEntry entry = {}; - R_TRY(this->GetDirectoryEntry(std::addressof(entry), id)); - - return ResultSuccess(); - } - - Result OpenFile(FileInfo *out, const RomPathChar *path) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey key = {}; - R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path)); - - return this->OpenFile(out, key); - } - - Result OpenFile(FileInfo *out, RomFileId id) const { - AMS_ASSERT(out != nullptr); - - RomFileEntry entry = {}; - R_TRY(this->GetFileEntry(std::addressof(entry), id)); - - *out = entry.info; - return ResultSuccess(); - } - - Result FindOpen(FindPosition *out, const RomPathChar *path) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - EntryKey parent_key = {}; - RomDirectoryEntry parent_entry = {}; - EntryKey key = {}; - R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path)); - - return this->FindOpen(out, key); - } - - Result FindOpen(FindPosition *out, RomDirectoryId id) const { - AMS_ASSERT(out != nullptr); - - out->next_dir = InvalidPosition; - out->next_file = InvalidPosition; - - RomDirectoryEntry entry = {}; - R_TRY(this->GetDirectoryEntry(std::addressof(entry), id)); - - out->next_dir = entry.dir; - out->next_file = entry.file; - - return ResultSuccess(); - } - - Result FindNextDirectory(RomPathChar *out, FindPosition *find) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(find != nullptr); - - R_UNLESS(find->next_dir != InvalidPosition, fs::ResultDbmFindFinished()); - - RomEntryKey key = {}; - RomDirectoryEntry entry = {}; - size_t aux_size = 0; - R_TRY(this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_dir)); - - out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator; - - find->next_dir = entry.next; - return ResultSuccess(); - } - - Result FindNextFile(RomPathChar *out, FindPosition *find) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(find != nullptr); - - R_UNLESS(find->next_file != InvalidPosition, fs::ResultDbmFindFinished()); - - RomEntryKey key = {}; - RomFileEntry entry = {}; - size_t aux_size = 0; - R_TRY(this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_file)); - - out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator; - - find->next_file = entry.next; - return ResultSuccess(); - } - - Result QueryRomFileSystemSize(u32 *out_dir_entry_size, u32 *out_file_entry_size) { - AMS_ASSERT(out_dir_entry_size != nullptr); - AMS_ASSERT(out_file_entry_size != nullptr); - - *out_dir_entry_size = this->dir_table.GetTotalEntrySize(); - *out_file_entry_size = this->file_table.GetTotalEntrySize(); - return ResultSuccess(); - } - private: - Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) const { - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_dir_key != nullptr); - AMS_ASSERT(out_dir_entry != nullptr); - - RomEntryKey gp_key = {}; - RomDirectoryEntry gp_entry = {}; - R_TRY(this->dir_table.GetByPosition(std::addressof(gp_key), std::addressof(gp_entry), nullptr, nullptr, pos)); - out_dir_key->key.parent = gp_key.parent; - - R_TRY(RomPathTool::GetParentDirectoryName(std::addressof(out_dir_key->name), name, path)); - - R_TRY(this->GetDirectoryEntry(out_pos, out_dir_entry, *out_dir_key)); - - return ResultSuccess(); - } - - Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser &parser, const RomPathChar *path) const { - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_dir_key != nullptr); - AMS_ASSERT(out_dir_entry != nullptr); - - Position dir_pos = RootPosition; - EntryKey dir_key = {}; - RomDirectoryEntry dir_entry = {}; - dir_key.key.parent = RootPosition; - - R_TRY(parser.GetNextDirectoryName(std::addressof(dir_key.name))); - R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)); - - Position parent_pos = dir_pos; - while (!parser.IsFinished()) { - EntryKey old_key = dir_key; - - R_TRY(parser.GetNextDirectoryName(std::addressof(dir_key.name))); - - if (RomPathTool::IsCurrentDirectory(dir_key.name)) { - dir_key = old_key; - continue; - } else if (RomPathTool::IsParentDirectory(dir_key.name)) { - R_UNLESS(parent_pos != RootPosition, fs::ResultDbmInvalidOperation()); - - R_TRY(this->GetGrandParent(std::addressof(parent_pos), std::addressof(dir_key), std::addressof(dir_entry), dir_key.key.parent, dir_key.name, path)); - } else { - dir_key.key.parent = parent_pos; - R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)); - - parent_pos = dir_pos; - } - } - - *out_pos = parent_pos; - *out_dir_key = dir_key; - *out_dir_entry = dir_entry; - return ResultSuccess(); - } - - Result FindPathRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, bool is_dir, const RomPathChar *path) const { - AMS_ASSERT(out_parent_key != nullptr); - AMS_ASSERT(out_parent_dir_entry != nullptr); - AMS_ASSERT(out_key != nullptr); - AMS_ASSERT(path != nullptr); - - RomPathTool::PathParser parser; - R_TRY(parser.Initialize(path)); - - Position parent_pos = 0; - R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), out_parent_key, out_parent_dir_entry, parser, path)); - - if (is_dir) { - RomPathTool::RomEntryName name = {}; - R_TRY(parser.GetAsDirectoryName(std::addressof(name))); - - if (RomPathTool::IsCurrentDirectory(name)) { - *out_key = *out_parent_key; - if (out_key->key.parent != RootPosition) { - Position pos = 0; - R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_dir_entry, out_key->key.parent, out_key->name, path)); - } - } else if (RomPathTool::IsParentDirectory(name)) { - R_UNLESS(parent_pos != RootPosition, fs::ResultDbmInvalidOperation()); - - Position pos = 0; - RomDirectoryEntry cur_entry = {}; - R_TRY(this->GetGrandParent(std::addressof(pos), out_key, std::addressof(cur_entry), out_parent_key->key.parent, out_parent_key->name, path)); - - if (out_key->key.parent != RootPosition) { - R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_dir_entry, out_key->key.parent, out_key->name, path)); - } - } else { - out_key->name = name; - out_key->key.parent = (out_key->name.length > 0) ? parent_pos : RootPosition; - } - } else { - R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation()); - - out_key->key.parent = parent_pos; - R_TRY(parser.GetAsFileName(std::addressof(out_key->name))); - } - - return ResultSuccess(); - } - - Result FindDirectoryRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const { - return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, true, path); - } - - Result FindFileRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const { - return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, false, path); - } - - Result CheckSameEntryExists(const EntryKey &key, Result if_exists) const { - /* Check dir */ - { - Position pos = InvalidPosition; - RomDirectoryEntry entry = {}; - const Result get_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key); - if (!fs::ResultDbmKeyNotFound::Includes(get_res)) { - R_TRY(get_res); - return if_exists; - } - } - - /* Check file */ - { - Position pos = InvalidPosition; - RomFileEntry entry = {}; - const Result get_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key); - if (!fs::ResultDbmKeyNotFound::Includes(get_res)) { - R_TRY(get_res); - return if_exists; - } - } - return ResultSuccess(); - } - - Result GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) const { - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_entry != nullptr); - - const Result dir_res = this->dir_table.Get(out_pos, out_entry, key); - R_UNLESS(R_FAILED(dir_res), dir_res); - R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res); - - Position pos = 0; - RomFileEntry entry = {}; - const Result file_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key); - R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation()); - R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound()); - return file_res; - } - - Result GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) const { - AMS_ASSERT(out_entry != nullptr); - Position pos = ConvertToPosition(id); - - RomEntryKey key = {}; - const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, pos); - R_UNLESS(R_FAILED(dir_res), dir_res); - R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res); - - RomFileEntry entry = {}; - const Result file_res = this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), nullptr, nullptr, pos); - R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation()); - R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound()); - return file_res; - } - - Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) const { - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_entry != nullptr); - - const Result file_res = this->file_table.Get(out_pos, out_entry, key); - R_UNLESS(R_FAILED(file_res), file_res); - R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res); - - Position pos = 0; - RomDirectoryEntry entry = {}; - const Result dir_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key); - R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation()); - R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound()); - return dir_res; - } - - Result GetFileEntry(RomFileEntry *out_entry, RomFileId id) const { - AMS_ASSERT(out_entry != nullptr); - Position pos = ConvertToPosition(id); - - RomEntryKey key = {}; - const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, pos); - R_UNLESS(R_FAILED(file_res), file_res); - R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res); - - RomDirectoryEntry entry = {}; - const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), nullptr, nullptr, pos); - R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation()); - R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound()); - return dir_res; - } - - Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key) const { - AMS_ASSERT(out != nullptr); - - Position pos = 0; - RomDirectoryEntry entry = {}; - R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); - - return ResultSuccess(); - } - - Result OpenFile(FileInfo *out, const EntryKey &key) const { - AMS_ASSERT(out != nullptr); - - Position pos = 0; - RomFileEntry entry = {}; - R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key)); - - *out = entry.info; - return ResultSuccess(); - } - - Result FindOpen(FindPosition *out, const EntryKey &key) const { - AMS_ASSERT(out != nullptr); - - out->next_dir = InvalidPosition; - out->next_file = InvalidPosition; - - Position pos = 0; - RomDirectoryEntry entry = {}; - R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); - - out->next_dir = entry.dir; - out->next_file = entry.file; - - return ResultSuccess(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp deleted file mode 100644 index 1bbea7a5c..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp +++ /dev/null @@ -1,367 +0,0 @@ -/* - * 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 - -namespace ams::fssystem { - - constexpr ALWAYS_INLINE u32 AlignRomAddress(u32 addr) { - return util::AlignUp(addr, sizeof(addr)); - } - - template - class RomKeyValueStorage { - public: - using BucketStorage = BucketStorageType; - using EntryStorage = EntryStorageType; - using Key = KeyType; - using Value = ValueType; - using Position = u32; - using BucketIndex = u32; - - struct FindIndex { - BucketIndex ind; - Position pos; - }; - static_assert(util::is_pod::value); - private: - static constexpr inline Position InvalidPosition = ~Position(); - - struct Element { - Key key; - Value value; - Position next; - u32 size; - }; - static_assert(util::is_pod::value); - private: - s64 bucket_offset; - u32 bucket_count; - BucketStorage *bucket_storage; - s64 kv_offset; - u32 kv_size; - EntryStorage *kv_storage; - u32 total_entry_size; - u32 entry_count; - public: - static constexpr u32 QueryEntrySize(u32 aux_size) { - return AlignRomAddress(sizeof(Element) + aux_size); - } - - static constexpr u32 QueryBucketStorageSize(u32 num) { - return num * sizeof(Position); - } - - static constexpr u32 QueryBucketCount(u32 size) { - return size / sizeof(Position); - } - - static constexpr u32 QueryKeyValueStorageSize(u32 num) { - return num * sizeof(Element); - } - - static Result Format(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) { - AMS_ASSERT(bucket != nullptr); - AMS_ASSERT(kv != nullptr); - AMS_ASSERT(kv_size >= 0); - - const Position pos = InvalidPosition; - for (s64 i = 0; i < bucket_count; i++) { - R_TRY(bucket->Write(bucket_ofs + i * sizeof(pos), std::addressof(pos), sizeof(pos))); - } - return ResultSuccess(); - } - public: - RomKeyValueStorage() : bucket_offset(), bucket_count(), bucket_storage(), kv_offset(), kv_size(), kv_storage(), total_entry_size(), entry_count() { /* ... */ } - - Result Initialize(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) { - AMS_ASSERT(bucket != nullptr); - AMS_ASSERT(kv != nullptr); - AMS_ASSERT(bucket_count > 0); - - this->bucket_storage = bucket; - this->bucket_offset = bucket_ofs; - this->bucket_count = bucket_count; - - this->kv_storage = kv; - this->kv_offset = kv_ofs; - this->kv_size = kv_size; - - return ResultSuccess(); - } - - void Finalize() { - this->bucket_storage = nullptr; - this->bucket_offset = 0; - this->bucket_count = 0; - - this->kv_storage = nullptr; - this->kv_offset = 0; - this->kv_size = 0; - } - - constexpr u32 GetTotalEntrySize() const { - return this->total_entry_size; - } - - constexpr u32 GetFreeSize() const { - return (this->kv_size - this->total_entry_size); - } - - constexpr u32 GetEntryCount() const { - return this->entry_count; - } - - Result Add(const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { - AMS_ASSERT(aux != nullptr); - AMS_ASSERT(aux_size <= MaxAuxiliarySize); - Position pos; - return this->AddImpl(std::addressof(pos), key, hash_key, aux, aux_size, value); - } - - Result Get(Value *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { - AMS_ASSERT(aux != nullptr); - AMS_ASSERT(aux_size <= MaxAuxiliarySize); - Position pos; - return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size); - } - - void FindOpen(FindIndex *out) const { - AMS_ASSERT(out != nullptr); - - out->ind = static_cast(-1); - out->pos = InvalidPosition; - } - - Result FindNext(Key *out_key, Value *out_val, FindIndex *find) { - AMS_ASSERT(out_key != nullptr); - AMS_ASSERT(out_val != nullptr); - AMS_ASSERT(find != nullptr); - - Element elem; - - BucketIndex ind = find->ind; - R_UNLESS((ind < this->bucket_count) || ind == static_cast(-1), fs::ResultDbmFindKeyFinished()); - - while (true) { - if (find->pos != InvalidPosition) { - R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, find->pos)); - - AMS_ASSERT(elem.next == InvalidPosition || elem.next < this->kv_size); - find->pos = elem.next; - *out_key = elem.key; - *out_val = elem.val; - return ResultSuccess(); - } - - while (true) { - ind++; - if (ind == this->bucket_count) { - find->ind = ind; - find->pos = InvalidPosition; - return fs::ResultDbmFindKeyFinished(); - } - - Position pos; - R_TRY(this->ReadBucket(std::addressof(pos), ind)); - AMS_ASSERT(pos == InvalidPosition || pos < this->kv_size); - - if (pos != InvalidPosition) { - find->ind = ind; - find->pos = pos; - break; - } - } - } - } - protected: - Result AddImpl(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { - Position pos, prev_pos; - Element elem; - - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->bucket_count > 0); - AMS_ASSERT(this->kv_size >= 0); - - const Result find_res = this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size); - R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists()); - R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res); - - R_TRY(this->AllocateEntry(std::addressof(pos), aux_size)); - - Position next_pos; - R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key)); - - elem = { key, value, next_pos, static_cast(aux_size) }; - *out = pos; - R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size, fs::WriteOption::None)); - - this->entry_count++; - - return ResultSuccess(); - } - - Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) const { - Position pos, prev_pos; - Element elem; - - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_val != nullptr); - - R_TRY(this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size)); - - *out_pos = pos; - *out_val = elem.value; - return ResultSuccess(); - } - - Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) const { - AMS_ASSERT(out_key != nullptr); - AMS_ASSERT(out_val != nullptr); - - Element elem; - R_TRY(this->ReadKeyValue(std::addressof(elem), out_aux, out_aux_size, pos)); - - *out_key = elem.key; - *out_val = elem.value; - return ResultSuccess(); - } - - Result SetByPosition(Position pos, const Value &value, fs::WriteOption option) const { - Element elem; - R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, pos)); - elem.value = value; - return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0, option); - } - private: - BucketIndex HashToBucket(u32 hash_key) const { - return hash_key % this->bucket_count; - } - - Result FindImpl(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) const { - AMS_ASSERT(out_pos != nullptr); - AMS_ASSERT(out_prev != nullptr); - AMS_ASSERT(out_elem != nullptr); - AMS_ASSERT(this->bucket_count > 0); - AMS_ASSERT(this->kv_size >= 0); - - *out_pos = 0; - *out_prev = 0; - - const BucketIndex ind = HashToBucket(hash_key); - - Position cur; - R_TRY(this->ReadBucket(std::addressof(cur), ind)); - AMS_ASSERT(cur == InvalidPosition || cur < this->kv_size); - - R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound()); - - u8 buf[MaxAuxiliarySize]; - - while (true) { - size_t cur_aux_size; - R_TRY(this->ReadKeyValue(out_elem, buf, std::addressof(cur_aux_size), cur)); - - if (key.IsEqual(out_elem->key, aux, aux_size, buf, cur_aux_size)) { - *out_pos = cur; - return ResultSuccess(); - } - - *out_prev = cur; - cur = out_elem->next; - R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound()); - } - } - - Result AllocateEntry(Position *out, size_t aux_size) { - AMS_ASSERT(out != nullptr); - - R_UNLESS(this->total_entry_size + sizeof(Element) + aux_size <= this->kv_size, fs::ResultDbmKeyFull()); - - *out = static_cast(this->total_entry_size); - - this->total_entry_size = AlignRomAddress(this->total_entry_size + sizeof(Element) + static_cast(aux_size)); - return ResultSuccess(); - } - - Result LinkEntry(Position *out, Position pos, u32 hash_key) { - AMS_ASSERT(out != nullptr); - - const BucketIndex ind = HashToBucket(hash_key); - - Position next; - R_TRY(this->ReadBucket(std::addressof(next), ind)); - AMS_ASSERT(next == InvalidPosition || next < this->kv_size); - - R_TRY(this->WriteBucket(pos, ind, fs::WriteOption::None)); - - *out = next; - return ResultSuccess(); - } - - Result ReadBucket(Position *out, BucketIndex ind) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->bucket_storage != nullptr); - AMS_ASSERT(ind < this->bucket_count); - - const s64 offset = this->bucket_offset + ind * sizeof(Position); - return this->bucket_storage->Read(offset, out, sizeof(*out)); - } - - Result WriteBucket(Position pos, BucketIndex ind, fs::WriteOption option) const { - AMS_ASSERT(this->bucket_storage != nullptr); - AMS_ASSERT(ind < this->bucket_count); - - const s64 offset = this->bucket_offset + ind * sizeof(Position); - return this->bucket_storage.Write(offset, std::addressof(pos), sizeof(pos)); - } - - Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->kv_storage != nullptr); - AMS_ASSERT(pos < this->kv_size); - - const s64 offset = this->kv_offset + pos; - R_TRY(this->kv_storage->Read(offset, out, sizeof(*out))); - - if (out_aux != nullptr && out_aux_size != nullptr) { - *out_aux_size = out->size; - if (out->size > 0) { - R_TRY(this->kv_storage->Read(offset + sizeof(*out), out_aux, out->size)); - } - } - - return ResultSuccess(); - } - - Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size, fs::WriteOption option) const { - AMS_ASSERT(elem != nullptr); - AMS_ASSERT(this->kv_storage != nullptr); - AMS_ASSERT(pos < this->kv_size); - - const s64 offset = this->kv_offset + pos; - R_TRY(this->kv_storage->Write(offset, elem, sizeof(*elem))); - - if (aux != nullptr && aux_size > 0) { - R_TRY(this->kv_storage->Write(offset + sizeof(*elem), aux, aux_size)); - } - - return ResultSuccess(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp deleted file mode 100644 index 6c40eac59..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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::fssystem { - - namespace RomPathTool { - - constexpr inline u32 MaxPathLength = 0x300; - - struct RomEntryName { - size_t length; - const RomPathChar *path; - }; - static_assert(util::is_pod::value); - - constexpr void InitializeRomEntryName(RomEntryName *entry) { - entry->length = 0; - } - - constexpr inline bool IsSeparator(RomPathChar c) { - return c == RomStringTraits::DirectorySeparator; - } - - constexpr inline bool IsNullTerminator(RomPathChar c) { - return c == RomStringTraits::NullTerminator; - } - - constexpr inline bool IsDot(RomPathChar c) { - return c == RomStringTraits::Dot; - } - - constexpr inline bool IsCurrentDirectory(const RomEntryName &name) { - return name.length == 1 && IsDot(name.path[0]); - } - - constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) { - return length == 1 && IsDot(p[0]); - } - - constexpr inline bool IsCurrentDirectory(const RomPathChar *p) { - return IsDot(p[0]) && IsNullTerminator(p[1]); - } - - constexpr inline bool IsParentDirectory(const RomEntryName &name) { - return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]); - } - - constexpr inline bool IsParentDirectory(const RomPathChar *p) { - return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]); - } - - constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) { - return length == 2 && IsDot(p[0]) && IsDot(p[1]); - } - - constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) { - return std::strncmp(lhs, rhs, length) == 0; - } - - constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) { - if (strnlen(rhs, MaxPathLength) != lhs.length) { - return false; - } - return IsEqualPath(lhs.path, rhs, lhs.length); - } - - constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) { - if (lhs.length != rhs.length) { - return false; - } - return IsEqualPath(lhs.path, rhs.path, lhs.length); - } - - Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p); - - class PathParser { - private: - const RomPathChar *prev_path_start; - const RomPathChar *prev_path_end; - const RomPathChar *next_path; - bool finished; - public: - constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ } - - Result Initialize(const RomPathChar *path); - void Finalize(); - - bool IsFinished() const; - bool IsDirectoryPath() const; - - Result GetAsDirectoryName(RomEntryName *out) const; - Result GetAsFileName(RomEntryName *out) const; - - Result GetNextDirectoryName(RomEntryName *out); - }; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp deleted file mode 100644 index 1baf32eb6..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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::fssystem { - - using RomPathChar = char; - using RomFileId = s32; - using RomDirectoryId = s32; - - struct RomFileSystemInformation { - s64 size; - s64 directory_bucket_offset; - s64 directory_bucket_size; - s64 directory_entry_offset; - s64 directory_entry_size; - s64 file_bucket_offset; - s64 file_bucket_size; - s64 file_entry_offset; - s64 file_entry_size; - s64 body_offset; - }; - static_assert(util::is_pod::value); - static_assert(sizeof(RomFileSystemInformation) == 0x50); - - struct RomDirectoryInfo { - /* ... */ - }; - static_assert(util::is_pod::value); - - struct RomFileInfo { - fs::Int64 offset; - fs::Int64 size; - }; - static_assert(util::is_pod::value); - - namespace RomStringTraits { - - constexpr inline char DirectorySeparator = '/'; - constexpr inline char NullTerminator = '\x00'; - constexpr inline char Dot = '.'; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp index 34dd76003..706775653 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include namespace ams::fssystem { @@ -25,7 +25,7 @@ namespace ams::fssystem { class RomFsFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(RomFsFileSystem); public: - using RomFileTable = HierarchicalRomFileTable; + using RomFileTable = fs::HierarchicalRomFileTable; private: RomFileTable rom_file_table; fs::IStorage *base_storage; diff --git a/libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp b/libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp similarity index 96% rename from libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp rename to libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp index 56d279b25..56803bcc5 100644 --- a/libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp @@ -17,23 +17,22 @@ namespace ams::fs { - s64 HierarchicalRomFileTable::QueryDirectoryEntryStorageSize(u32 count) { - const size_t real_count = count + ReservedDirectoryCount; - return DirectoryEntryMapTable::QueryKeyValueStorageSize(real_count) + real_count * (RomPathTool::MaxPathLength + 1) * sizeof(RomPathChar); - } - s64 HierarchicalRomFileTable::QueryDirectoryEntryBucketStorageSize(s64 count) { return DirectoryEntryMapTable::QueryBucketStorageSize(count); } - s64 HierarchicalRomFileTable::QueryFileEntryStorageSize(u32 count) { - return FileEntryMapTable::QueryKeyValueStorageSize(count) + count * (RomPathTool::MaxPathLength + 1) * sizeof(RomPathChar); + size_t HierarchicalRomFileTable::QueryDirectoryEntrySize(size_t aux_size) { + return DirectoryEntryMapTable::QueryEntrySize(aux_size); } s64 HierarchicalRomFileTable::QueryFileEntryBucketStorageSize(s64 count) { return FileEntryMapTable::QueryBucketStorageSize(count); } + size_t HierarchicalRomFileTable::QueryFileEntrySize(size_t aux_size) { + return FileEntryMapTable::QueryEntrySize(aux_size); + } + Result HierarchicalRomFileTable::Format(SubStorage dir_bucket, SubStorage file_bucket) { s64 dir_bucket_size; R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size))); @@ -69,7 +68,7 @@ namespace ams::fs { Position root_pos = RootPosition; EntryKey root_key = {}; root_key.key.parent = root_pos; - RomPathTool::InitializeRomEntryName(std::addressof(root_key.name)); + RomPathTool::InitEntryName(std::addressof(root_key.name)); RomDirectoryEntry root_entry = { .next = InvalidPosition, .dir = InvalidPosition, @@ -99,7 +98,7 @@ namespace ams::fs { R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull()) } R_END_TRY_CATCH; - *out = ConvertToDirectoryId(new_pos); + *out = PositionToDirectoryId(new_pos); if (parent_entry.dir == InvalidPosition) { parent_entry.dir = new_pos; @@ -146,7 +145,7 @@ namespace ams::fs { R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull()) } R_END_TRY_CATCH; - *out = ConvertToFileId(new_pos); + *out = PositionToFileId(new_pos); if (parent_entry.file == InvalidPosition) { parent_entry.file = new_pos; @@ -185,7 +184,7 @@ namespace ams::fs { RomDirectoryEntry entry = {}; R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); - *out = ConvertToDirectoryId(pos); + *out = PositionToDirectoryId(pos); return ResultSuccess(); } @@ -201,7 +200,7 @@ namespace ams::fs { RomFileEntry entry = {}; R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key)); - *out = ConvertToFileId(pos); + *out = PositionToFileId(pos); return ResultSuccess(); } @@ -353,7 +352,7 @@ namespace ams::fs { R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)); Position parent_pos = dir_pos; - while (!parser->IsFinished()) { + while (!parser->IsParseFinished()) { EntryKey old_key = dir_key; R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name))); @@ -492,7 +491,7 @@ namespace ams::fs { Result HierarchicalRomFileTable::GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) { AMS_ASSERT(out_entry != nullptr); - Position pos = ConvertToPosition(id); + Position pos = DirectoryIdToPosition(id); RomEntryKey key = {}; const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, pos); @@ -524,7 +523,7 @@ namespace ams::fs { Result HierarchicalRomFileTable::GetFileEntry(RomFileEntry *out_entry, RomFileId id) { AMS_ASSERT(out_entry != nullptr); - Position pos = ConvertToPosition(id); + Position pos = FileIdToPosition(id); RomEntryKey key = {}; const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, pos); diff --git a/libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp b/libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp similarity index 88% rename from libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp rename to libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp index a5f10379c..9791368b7 100644 --- a/libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp @@ -28,9 +28,8 @@ namespace ams::fs::RomPathTool { this->prev_path_start = path; this->prev_path_end = path; - this->next_path = path + 1; - while (IsSeparator(this->next_path[0])) { - this->next_path++; + for (this->next_path = path + 1; IsSeparator(this->next_path[0]); ++this->next_path) { + /* ... */ } return ResultSuccess(); @@ -43,12 +42,13 @@ namespace ams::fs::RomPathTool { this->finished = false; } - bool PathParser::IsFinished() const { + bool PathParser::IsParseFinished() const { return this->finished; } bool PathParser::IsDirectoryPath() const { AMS_ASSERT(this->next_path != nullptr); + if (IsNullTerminator(this->next_path[0]) && IsSeparator(this->next_path[-1])) { return true; } @@ -57,11 +57,47 @@ namespace ams::fs::RomPathTool { return true; } - if (IsParentDirectory(this->next_path)) { - return true; + return IsParentDirectory(this->next_path); + } + + Result PathParser::GetNextDirectoryName(RomEntryName *out) { + AMS_ASSERT(out != nullptr); + AMS_ASSERT(this->prev_path_start != nullptr); + AMS_ASSERT(this->prev_path_end != nullptr); + AMS_ASSERT(this->next_path != nullptr); + + /* Set the current path to output. */ + out->length = this->prev_path_end - this->prev_path_start; + out->path = this->prev_path_start; + + /* Parse the next path. */ + this->prev_path_start = this->next_path; + const RomPathChar *cur = this->next_path; + for (size_t name_len = 0; true; name_len++) { + if (IsSeparator(cur[name_len])) { + R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong()); + + this->prev_path_end = cur + name_len; + this->next_path = this->prev_path_end + 1; + + while (IsSeparator(this->next_path[0])) { + ++this->next_path; + } + if (IsNullTerminator(this->next_path[0])) { + this->finished = true; + } + break; + } + + if (IsNullTerminator(cur[name_len])) { + this->finished = true; + this->next_path = cur + name_len; + this->prev_path_end = cur + name_len; + break; + } } - return false; + return ResultSuccess(); } Result PathParser::GetAsDirectoryName(RomEntryName *out) const { @@ -92,45 +128,6 @@ namespace ams::fs::RomPathTool { return ResultSuccess(); } - Result PathParser::GetNextDirectoryName(RomEntryName *out) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->prev_path_start != nullptr); - AMS_ASSERT(this->prev_path_end != nullptr); - AMS_ASSERT(this->next_path != nullptr); - - /* Set the current path to output. */ - out->length = this->prev_path_end - this->prev_path_start; - out->path = this->prev_path_start; - - /* Parse the next path. */ - this->prev_path_start = this->next_path; - const RomPathChar *cur = this->next_path; - for (size_t name_len = 0; true; name_len++) { - if (IsSeparator(cur[name_len])) { - R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong()); - - this->prev_path_end = cur + name_len; - this->next_path = this->prev_path_end + 1; - - while (IsSeparator(this->next_path[0])) { - this->next_path++; - } - if (IsNullTerminator(this->next_path[0])) { - this->finished = true; - } - break; - } - - if (IsNullTerminator(cur[name_len])) { - this->finished = true; - this->prev_path_end = this->next_path = cur + name_len; - break; - } - } - - return ResultSuccess(); - } - Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) { AMS_ASSERT(out != nullptr); AMS_ASSERT(p != nullptr); @@ -140,7 +137,7 @@ namespace ams::fs::RomPathTool { s32 depth = 1; if (IsParentDirectory(cur)) { - depth++; + ++depth; } if (cur.path > p) { @@ -149,7 +146,7 @@ namespace ams::fs::RomPathTool { while (head >= p) { if (IsSeparator(*head)) { if (IsCurrentDirectory(head + 1, len)) { - depth++; + ++depth; } if (IsParentDirectory(head + 1, len)) { @@ -162,16 +159,16 @@ namespace ams::fs::RomPathTool { } while (IsSeparator(*head)) { - head--; + --head; } end = head; len = 0; - depth--; + --depth; } - len++; - head--; + ++len; + --head; } R_UNLESS(depth == 0, fs::ResultDirectoryUnobtainable()); @@ -182,10 +179,10 @@ namespace ams::fs::RomPathTool { } if (end <= p) { - out->path = p; + out->path = p; out->length = 0; } else { - out->path = start; + out->path = start; out->length = end - start + 1; } diff --git a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp index ca6de5ba8..182fe3e0d 100644 --- a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp @@ -316,7 +316,7 @@ namespace ams::fs { out_entries[i].type = fs::DirectoryEntryType_File; RomFsFileSystem::RomFileTable::FileInfo file_info; - R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->ConvertToFileId(file_pos))); + R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->PositionToFileId(file_pos))); out_entries[i].file_size = file_info.size.Get(); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp b/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp deleted file mode 100644 index 6d4e6e1e5..000000000 --- a/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 . - */ -#include - -namespace ams::fssystem::RomPathTool { - - Result PathParser::Initialize(const RomPathChar *path) { - AMS_ASSERT(path != nullptr); - - /* Require paths start with a separator, and skip repeated separators. */ - R_UNLESS(IsSeparator(path[0]), fs::ResultDbmInvalidPathFormat()); - while (IsSeparator(path[1])) { - path++; - } - - this->prev_path_start = path; - this->prev_path_end = path; - this->next_path = path + 1; - while (IsSeparator(this->next_path[0])) { - this->next_path++; - } - - return ResultSuccess(); - } - - void PathParser::Finalize() { - /* ... */ - } - - bool PathParser::IsFinished() const { - return this->finished; - } - - bool PathParser::IsDirectoryPath() const { - AMS_ASSERT(this->next_path != nullptr); - if (IsNullTerminator(this->next_path[0]) && IsSeparator(this->next_path[-1])) { - return true; - } - - if (IsCurrentDirectory(this->next_path)) { - return true; - } - - if (IsParentDirectory(this->next_path)) { - return true; - } - - return false; - } - - Result PathParser::GetAsDirectoryName(RomEntryName *out) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->prev_path_start != nullptr); - AMS_ASSERT(this->prev_path_end != nullptr); - AMS_ASSERT(this->next_path != nullptr); - - const size_t len = this->prev_path_end - this->prev_path_start; - R_UNLESS(len <= MaxPathLength, fs::ResultDbmDirectoryNameTooLong()); - - out->length = len; - out->path = this->prev_path_start; - return ResultSuccess(); - } - - Result PathParser::GetAsFileName(RomEntryName *out) const { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->prev_path_start != nullptr); - AMS_ASSERT(this->prev_path_end != nullptr); - AMS_ASSERT(this->next_path != nullptr); - - const size_t len = this->prev_path_end - this->prev_path_start; - R_UNLESS(len <= MaxPathLength, fs::ResultDbmFileNameTooLong()); - - out->length = len; - out->path = this->prev_path_start; - return ResultSuccess(); - } - - Result PathParser::GetNextDirectoryName(RomEntryName *out) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(this->prev_path_start != nullptr); - AMS_ASSERT(this->prev_path_end != nullptr); - AMS_ASSERT(this->next_path != nullptr); - - /* Set the current path to output. */ - out->length = this->prev_path_end - this->prev_path_start; - out->path = this->prev_path_start; - - /* Parse the next path. */ - this->prev_path_start = this->next_path; - const RomPathChar *cur = this->next_path; - for (size_t name_len = 0; true; name_len++) { - if (IsSeparator(cur[name_len])) { - R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong()); - - this->prev_path_end = cur + name_len; - this->next_path = this->prev_path_end + 1; - - while (IsSeparator(this->next_path[0])) { - this->next_path++; - } - if (IsNullTerminator(this->next_path[0])) { - this->finished = true; - } - break; - } - - if (IsNullTerminator(cur[name_len])) { - this->finished = true; - this->prev_path_end = this->next_path = cur + name_len; - break; - } - } - - return ResultSuccess(); - } - - Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) { - const RomPathChar *start = cur.path; - const RomPathChar *end = cur.path + cur.length - 1; - - s32 depth = 1; - if (IsParentDirectory(cur)) { - depth++; - } - - if (cur.path > p) { - size_t len = 0; - const RomPathChar *head = cur.path - 1; - while (head >= p) { - if (IsSeparator(*head)) { - if (IsCurrentDirectory(head + 1, len)) { - depth++; - } - - if (IsParentDirectory(head + 1, len)) { - depth += 2; - } - - if (depth == 0) { - start = head + 1; - break; - } - - while (IsSeparator(*head)) { - head--; - } - - end = head; - len = 0; - depth--; - } - - len++; - head--; - } - - R_UNLESS(depth == 0, fs::ResultDbmInvalidPathFormat()); - - if (head == p) { - start = p + 1; - } - } - - if (end <= p) { - out->path = p; - out->length = 0; - } else { - out->path = start; - out->length = end - start + 1; - } - - return ResultSuccess(); - } - -} diff --git a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp index 009c51d06..d736962ee 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp @@ -19,7 +19,7 @@ namespace ams::fssystem { namespace { - constexpr size_t CalculateRequiredWorkingMemorySize(const RomFileSystemInformation &header) { + constexpr size_t CalculateRequiredWorkingMemorySize(const fs::RomFileSystemInformation &header) { return header.directory_bucket_size + header.directory_entry_size + header.file_bucket_size + header.file_entry_size; } @@ -114,7 +114,7 @@ namespace ams::fssystem { public: virtual Result ReadImpl(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { - return this->ReadImpl(out_count, std::addressof(this->current_find), out_entries, max_entries); + return this->ReadInternal(out_count, std::addressof(this->current_find), out_entries, max_entries); }, AMS_CURRENT_FUNCTION_NAME)); return ResultSuccess(); } @@ -123,20 +123,20 @@ namespace ams::fssystem { FindPosition find = this->first_find; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { - R_TRY(this->ReadImpl(out, std::addressof(find), nullptr, 0)); + R_TRY(this->ReadInternal(out, std::addressof(find), nullptr, 0)); return ResultSuccess(); }, AMS_CURRENT_FUNCTION_NAME)); return ResultSuccess(); } private: - Result ReadImpl(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) { + Result ReadInternal(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) { constexpr size_t NameBufferSize = fs::EntryNameLengthMax + 1; - RomPathChar name[NameBufferSize]; + fs::RomPathChar name[NameBufferSize]; s32 i = 0; if (this->mode & fs::OpenDirectoryMode_Directory) { while (i < max_entries || out_entries == nullptr) { - R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextDirectory(name, find)) { + R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextDirectory(name, find, NameBufferSize)) { R_CATCH(fs::ResultDbmFindFinished) { break; } } R_END_TRY_CATCH; @@ -156,7 +156,7 @@ namespace ams::fssystem { while (i < max_entries || out_entries == nullptr) { auto file_pos = find->next_file; - R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextFile(name, find)) { + R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextFile(name, find, NameBufferSize)) { R_CATCH(fs::ResultDbmFindFinished) { break; } } R_END_TRY_CATCH; @@ -167,7 +167,7 @@ namespace ams::fssystem { out_entries[i].type = fs::DirectoryEntryType_File; RomFsFileSystem::RomFileTable::FileInfo file_info; - R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->ConvertToFileId(file_pos))); + R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->PositionToFileId(file_pos))); out_entries[i].file_size = file_info.size.Get(); } @@ -204,7 +204,7 @@ namespace ams::fssystem { } Result RomFsFileSystem::GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage) { - RomFileSystemInformation header; + fs::RomFileSystemInformation header; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY(storage->Read(0, std::addressof(header), sizeof(header))); @@ -224,7 +224,7 @@ namespace ams::fssystem { buffers::EnableBlockingBufferManagerAllocation(); /* Read the header. */ - RomFileSystemInformation header; + fs::RomFileSystemInformation header; R_TRY(base->Read(0, std::addressof(header), sizeof(header))); /* Set up our storages. */ @@ -261,10 +261,10 @@ namespace ams::fssystem { R_UNLESS(this->file_entry_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemB()); /* Initialize the rom table. */ - R_TRY(this->rom_file_table.Initialize(this->dir_bucket_storage.get(), 0, static_cast(header.directory_bucket_size), - this->dir_entry_storage.get(), 0, static_cast(header.directory_entry_size), - this->file_bucket_storage.get(), 0, static_cast(header.file_bucket_size), - this->file_entry_storage.get(), 0, static_cast(header.file_entry_size))); + R_TRY(this->rom_file_table.Initialize(fs::SubStorage(this->dir_bucket_storage.get(), 0, static_cast(header.directory_bucket_size)), + fs::SubStorage(this->dir_entry_storage.get(), 0, static_cast(header.directory_entry_size)), + fs::SubStorage(this->file_bucket_storage.get(), 0, static_cast(header.file_bucket_size)), + fs::SubStorage(this->file_entry_storage.get(), 0, static_cast(header.file_entry_size)))); /* Set members. */ this->entry_size = header.body_offset; @@ -326,7 +326,7 @@ namespace ams::fssystem { Result RomFsFileSystem::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { - RomDirectoryInfo dir_info; + fs::RomDirectoryInfo dir_info; R_TRY_CATCH(this->rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) From bf5577624115425f7846446e638a8046001d51c2 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 5 Dec 2020 03:05:06 -0800 Subject: [PATCH 04/29] fsa: *Impl -> Do* --- .../fs/fs_read_only_filesystem.hpp | 42 +++++----- .../stratosphere/fs/fs_remote_filesystem.hpp | 48 ++++++------ .../stratosphere/fs/fs_romfs_filesystem.hpp | 32 ++++---- .../fs/fs_shared_filesystem_holder.hpp | 34 ++++----- .../stratosphere/fs/fsa/fs_idirectory.hpp | 8 +- .../include/stratosphere/fs/fsa/fs_ifile.hpp | 26 +++---- .../stratosphere/fs/fsa/fs_ifilesystem.hpp | 76 +++++++++---------- ...fssystem_directory_savedata_filesystem.hpp | 18 ++--- .../fssystem_partition_file_system.hpp | 26 +++---- .../fssystem/fssystem_romfs_file_system.hpp | 28 +++---- .../fssystem_path_resolution_filesystem.hpp | 38 +++++----- .../libstratosphere/source/fs/fs_code.cpp | 32 ++++---- .../source/fs/fs_romfs_filesystem.cpp | 54 ++++++------- ...fssystem_directory_savedata_filesystem.cpp | 30 ++++---- .../fssystem_partition_file_system.cpp | 46 +++++------ .../fssystem/fssystem_romfs_filesystem.cpp | 44 +++++------ .../fsmitm_readonly_layered_filesystem.hpp | 30 ++++---- 17 files changed, 306 insertions(+), 306 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp index 0cd726b50..9e70d3d8a 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp @@ -33,27 +33,27 @@ namespace ams::fs { explicit ReadOnlyFile(std::unique_ptr &&f) : base_file(std::move(f)) { /* ... */ } virtual ~ReadOnlyFile() { /* ... */ } private: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { return this->base_file->Read(out, offset, buffer, size, option); } - virtual Result GetSizeImpl(s64 *out) override final { + virtual Result DoGetSize(s64 *out) override final { return this->base_file->GetSize(out); } - virtual Result FlushImpl() override final { + virtual Result DoFlush() override final { return ResultSuccess(); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { return fs::ResultUnsupportedOperationInReadOnlyFileA(); } - virtual Result SetSizeImpl(s64 size) override final { + virtual Result DoSetSize(s64 size) override final { return fs::ResultUnsupportedOperationInReadOnlyFileA(); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { switch (op_id) { case OperationId::InvalidateCache: case OperationId::QueryRange: @@ -80,7 +80,7 @@ namespace ams::fs { explicit ReadOnlyFileSystemTemplate(T &&fs) : base_fs(std::move(fs)) { /* ... */ } virtual ~ReadOnlyFileSystemTemplate() { /* ... */ } private: - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); @@ -94,59 +94,59 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { return this->base_fs->OpenDirectory(out_dir, path, mode); } - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { return this->base_fs->GetEntryType(out, path); } - virtual Result CommitImpl() override final { + virtual Result DoCommit() override final { return ResultSuccess(); } - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DeleteFileImpl(const char *path) override final { + virtual Result DoDeleteFile(const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result CreateDirectoryImpl(const char *path) override final { + virtual Result DoCreateDirectory(const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DeleteDirectoryImpl(const char *path) override final { + virtual Result DoDeleteDirectory(const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoCleanDirectoryRecursively(const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override final { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB(); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override final { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB(); } - virtual Result CommitProvisionallyImpl(s64 counter) override final { + virtual Result DoCommitProvisionally(s64 counter) override final { return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateC(); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp index 824fc8432..0d32894ea 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp @@ -33,27 +33,27 @@ namespace ams::fs { virtual ~RemoteFile() { fsFileClose(std::addressof(this->base_file)); } public: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { return fsFileRead(std::addressof(this->base_file), offset, buffer, size, option.value, out); } - virtual Result GetSizeImpl(s64 *out) override final { + virtual Result DoGetSize(s64 *out) override final { return fsFileGetSize(std::addressof(this->base_file), out); } - virtual Result FlushImpl() override final { + virtual Result DoFlush() override final { return fsFileFlush(std::addressof(this->base_file)); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { return fsFileWrite(std::addressof(this->base_file), offset, buffer, size, option.value); } - virtual Result SetSizeImpl(s64 size) override final { + virtual Result DoSetSize(s64 size) override final { return fsFileSetSize(std::addressof(this->base_file), size); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { R_UNLESS(op_id == OperationId::QueryRange, fs::ResultUnsupportedOperationInFileServiceObjectAdapterA()); R_UNLESS(dst_size == sizeof(FileQueryRangeInfo), fs::ResultInvalidSize()); @@ -73,11 +73,11 @@ namespace ams::fs { virtual ~RemoteDirectory() { fsDirClose(std::addressof(this->base_dir)); } public: - virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { + virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { return fsDirRead(std::addressof(this->base_dir), out_count, max_entries, out_entries); } - virtual Result GetEntryCountImpl(s64 *out) override final { + virtual Result DoGetEntryCount(s64 *out) override final { return fsDirGetEntryCount(std::addressof(this->base_dir), out); } public: @@ -109,37 +109,37 @@ namespace ams::fs { return VerifyPath(rel_path, max_len, max_len); } public: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCreateFile(std::addressof(this->base_fs), sf_path.str, size, flags); } - virtual Result DeleteFileImpl(const char *path) override final { + virtual Result DoDeleteFile(const char *path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteFile(std::addressof(this->base_fs), sf_path.str); } - virtual Result CreateDirectoryImpl(const char *path) override final { + virtual Result DoCreateDirectory(const char *path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCreateDirectory(std::addressof(this->base_fs), sf_path.str); } - virtual Result DeleteDirectoryImpl(const char *path) override final { + virtual Result DoDeleteDirectory(const char *path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteDirectory(std::addressof(this->base_fs), sf_path.str); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const char *path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteDirectoryRecursively(std::addressof(this->base_fs), sf_path.str); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); @@ -147,7 +147,7 @@ namespace ams::fs { return fsFsRenameFile(std::addressof(this->base_fs), old_sf_path.str, new_sf_path.str); } - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); @@ -155,7 +155,7 @@ namespace ams::fs { return fsFsRenameDirectory(std::addressof(this->base_fs), old_sf_path.str, new_sf_path.str); } - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -163,7 +163,7 @@ namespace ams::fs { return fsFsGetEntryType(std::addressof(this->base_fs), sf_path.str, reinterpret_cast<::FsDirEntryType *>(out)); } - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -177,7 +177,7 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -191,37 +191,37 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result CommitImpl() override final { + virtual Result DoCommit() override final { return fsFsCommit(std::addressof(this->base_fs)); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsGetFreeSpace(std::addressof(this->base_fs), sf_path.str, out); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsGetTotalSpace(std::addressof(this->base_fs), sf_path.str, out); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) { + virtual Result DoCleanDirectoryRecursively(const char *path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCleanDirectoryRecursively(std::addressof(this->base_fs), sf_path.str); } - virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); return fsFsGetFileTimeStampRaw(std::addressof(this->base_fs), sf_path.str, reinterpret_cast<::FsTimeStampRaw *>(out)); } - virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsQueryEntry(std::addressof(this->base_fs), dst, dst_size, src, src_size, sf_path.str, static_cast(query)); diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp index b986d2a76..230e92991 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp @@ -51,24 +51,24 @@ namespace ams::fs { RomFileTable *GetRomFileTable(); Result GetFileBaseOffset(s64 *out, const char *path); public: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override; - virtual Result DeleteFileImpl(const char *path) override; - virtual Result CreateDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override; - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override; - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override; - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override; - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; - virtual Result CommitImpl() override; - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override; - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override; - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override; + virtual Result DoCreateFile(const char *path, s64 size, int flags) override; + virtual Result DoDeleteFile(const char *path) override; + virtual Result DoCreateDirectory(const char *path) override; + virtual Result DoDeleteDirectory(const char *path) override; + virtual Result DoDeleteDirectoryRecursively(const char *path) override; + virtual Result DoRenameFile(const char *old_path, const char *new_path) override; + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCommit() override; + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override; + virtual Result DoCleanDirectoryRecursively(const char *path) override; /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override; - virtual Result RollbackImpl() override; + virtual Result DoCommitProvisionally(s64 counter) override; + virtual Result DoRollback() override; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp index 9a4c5931f..847c9d6cb 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp @@ -30,25 +30,25 @@ namespace ams::fs { public: SharedFileSystemHolder(std::shared_ptr f) : fs(std::move(f)) { /* ... */ } public: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override { return this->fs->CreateFile(path, size, flags); } - virtual Result DeleteFileImpl(const char *path) override { return this->fs->DeleteFile(path); } - virtual Result CreateDirectoryImpl(const char *path) override { return this->fs->CreateDirectory(path); } - virtual Result DeleteDirectoryImpl(const char *path) override { return this->fs->DeleteDirectory(path); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override { return this->fs->DeleteDirectoryRecursively(path); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override { return this->fs->RenameFile(old_path, new_path); } - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override { return this->fs->RenameDirectory(old_path, new_path); } - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override { return this->fs->GetEntryType(out, path); } - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { return this->fs->OpenFile(out_file, path, mode); } - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { return this->fs->OpenDirectory(out_dir, path, mode); } - virtual Result CommitImpl() override { return this->fs->Commit(); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override { return this->fs->GetFreeSpaceSize(out, path); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override { return this->fs->GetTotalSpaceSize(out, path); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override { return this->fs->CleanDirectoryRecursively(path); } + virtual Result DoCreateFile(const char *path, s64 size, int flags) override { return this->fs->CreateFile(path, size, flags); } + virtual Result DoDeleteFile(const char *path) override { return this->fs->DeleteFile(path); } + virtual Result DoCreateDirectory(const char *path) override { return this->fs->CreateDirectory(path); } + virtual Result DoDeleteDirectory(const char *path) override { return this->fs->DeleteDirectory(path); } + virtual Result DoDeleteDirectoryRecursively(const char *path) override { return this->fs->DeleteDirectoryRecursively(path); } + virtual Result DoRenameFile(const char *old_path, const char *new_path) override { return this->fs->RenameFile(old_path, new_path); } + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override { return this->fs->RenameDirectory(old_path, new_path); } + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override { return this->fs->GetEntryType(out, path); } + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { return this->fs->OpenFile(out_file, path, mode); } + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { return this->fs->OpenDirectory(out_dir, path, mode); } + virtual Result DoCommit() override { return this->fs->Commit(); } + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override { return this->fs->GetFreeSpaceSize(out, path); } + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override { return this->fs->GetTotalSpaceSize(out, path); } + virtual Result DoCleanDirectoryRecursively(const char *path) override { return this->fs->CleanDirectoryRecursively(path); } /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override { return this->fs->CommitProvisionally(counter); } - virtual Result RollbackImpl() override { return this->fs->Rollback(); } - virtual Result FlushImpl() override { return this->fs->Flush(); } + virtual Result DoCommitProvisionally(s64 counter) override { return this->fs->CommitProvisionally(counter); } + virtual Result DoRollback() override { return this->fs->Rollback(); } + virtual Result DoFlush() override { return this->fs->Flush(); } }; } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp index aea0a70da..40a845c3c 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp @@ -32,12 +32,12 @@ namespace ams::fs::fsa { } R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument()); R_UNLESS(max_entries > 0, fs::ResultInvalidArgument()); - return this->ReadImpl(out_count, out_entries, max_entries); + return this->DoRead(out_count, out_entries, max_entries); } Result GetEntryCount(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetEntryCountImpl(out); + return this->DoGetEntryCount(out); } public: /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ @@ -45,8 +45,8 @@ namespace ams::fs::fsa { protected: /* ...? */ private: - virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0; - virtual Result GetEntryCountImpl(s64 *out) = 0; + virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0; + virtual Result DoGetEntryCount(s64 *out) = 0; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp index 2d262639b..1e3bbaf23 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp @@ -36,7 +36,7 @@ namespace ams::fs::fsa { const s64 signed_size = static_cast(size); R_UNLESS(signed_size >= 0, fs::ResultOutOfRange()); R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange()); - return this->ReadImpl(out, offset, buffer, size, option); + return this->DoRead(out, offset, buffer, size, option); } Result Read(size_t *out, s64 offset, void *buffer, size_t size) { @@ -45,11 +45,11 @@ namespace ams::fs::fsa { Result GetSize(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetSizeImpl(out); + return this->DoGetSize(out); } Result Flush() { - return this->FlushImpl(); + return this->DoFlush(); } Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { @@ -64,20 +64,20 @@ namespace ams::fs::fsa { const s64 signed_size = static_cast(size); R_UNLESS(signed_size >= 0, fs::ResultOutOfRange()); R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange()); - return this->WriteImpl(offset, buffer, size, option); + return this->DoWrite(offset, buffer, size, option); } Result SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultOutOfRange()); - return this->SetSizeImpl(size); + return this->DoSetSize(size); } Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { - return this->OperateRangeImpl(dst, dst_size, op_id, offset, size, src, src_size); + return this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size); } Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) { - return this->OperateRangeImpl(nullptr, 0, op_id, offset, size, nullptr, 0); + return this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0); } public: /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ @@ -124,12 +124,12 @@ namespace ams::fs::fsa { return ResultSuccess(); } private: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0; - virtual Result GetSizeImpl(s64 *out) = 0; - virtual Result FlushImpl() = 0; - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0; - virtual Result SetSizeImpl(s64 size) = 0; - virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0; + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0; + virtual Result DoGetSize(s64 *out) = 0; + virtual Result DoFlush() = 0; + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0; + virtual Result DoSetSize(s64 size) = 0; + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp index 83b0ea4ae..d40e6879e 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp @@ -36,7 +36,7 @@ namespace ams::fs::fsa { Result CreateFile(const char *path, s64 size, int option) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); R_UNLESS(size >= 0, fs::ResultOutOfRange()); - return this->CreateFileImpl(path, size, option); + return this->DoCreateFile(path, size, option); } Result CreateFile(const char *path, s64 size) { @@ -45,40 +45,40 @@ namespace ams::fs::fsa { Result DeleteFile(const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DeleteFileImpl(path); + return this->DoDeleteFile(path); } Result CreateDirectory(const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->CreateDirectoryImpl(path); + return this->DoCreateDirectory(path); } Result DeleteDirectory(const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DeleteDirectoryImpl(path); + return this->DoDeleteDirectory(path); } Result DeleteDirectoryRecursively(const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DeleteDirectoryRecursivelyImpl(path); + return this->DoDeleteDirectoryRecursively(path); } Result RenameFile(const char *old_path, const char *new_path) { R_UNLESS(old_path != nullptr, fs::ResultInvalidPath()); R_UNLESS(new_path != nullptr, fs::ResultInvalidPath()); - return this->RenameFileImpl(old_path, new_path); + return this->DoRenameFile(old_path, new_path); } Result RenameDirectory(const char *old_path, const char *new_path) { R_UNLESS(old_path != nullptr, fs::ResultInvalidPath()); R_UNLESS(new_path != nullptr, fs::ResultInvalidPath()); - return this->RenameDirectoryImpl(old_path, new_path); + return this->DoRenameDirectory(old_path, new_path); } Result GetEntryType(DirectoryEntryType *out, const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetEntryTypeImpl(out, path); + return this->DoGetEntryType(out, path); } Result OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) { @@ -86,7 +86,7 @@ namespace ams::fs::fsa { R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidOpenMode()); - return this->OpenFileImpl(out_file, path, mode); + return this->DoOpenFile(out_file, path, mode); } Result OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) { @@ -94,98 +94,98 @@ namespace ams::fs::fsa { R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidOpenMode()); - return this->OpenDirectoryImpl(out_dir, path, mode); + return this->DoOpenDirectory(out_dir, path, mode); } Result Commit() { - return this->CommitImpl(); + return this->DoCommit(); } Result GetFreeSpaceSize(s64 *out, const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetFreeSpaceSizeImpl(out, path); + return this->DoGetFreeSpaceSize(out, path); } Result GetTotalSpaceSize(s64 *out, const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetTotalSpaceSizeImpl(out, path); + return this->DoGetTotalSpaceSize(out, path); } Result CleanDirectoryRecursively(const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->CleanDirectoryRecursivelyImpl(path); + return this->DoCleanDirectoryRecursively(path); } Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->GetFileTimeStampRawImpl(out, path); + return this->DoGetFileTimeStampRaw(out, path); } Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const char *path) { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->QueryEntryImpl(dst, dst_size, src, src_size, query, path); + return this->DoQueryEntry(dst, dst_size, src, src_size, query, path); } /* These aren't accessible as commands. */ Result CommitProvisionally(s64 counter) { - return this->CommitProvisionallyImpl(counter); + return this->DoCommitProvisionally(counter); } Result Rollback() { - return this->RollbackImpl(); + return this->DoRollback(); } Result Flush() { - return this->FlushImpl(); + return this->DoFlush(); } protected: /* ...? */ private: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) = 0; - virtual Result DeleteFileImpl(const char *path) = 0; - virtual Result CreateDirectoryImpl(const char *path) = 0; - virtual Result DeleteDirectoryImpl(const char *path) = 0; - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) = 0; - virtual Result RenameFileImpl(const char *old_path, const char *new_path) = 0; - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) = 0; - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) = 0; - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) = 0; - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0; - virtual Result CommitImpl() = 0; + virtual Result DoCreateFile(const char *path, s64 size, int flags) = 0; + virtual Result DoDeleteFile(const char *path) = 0; + virtual Result DoCreateDirectory(const char *path) = 0; + virtual Result DoDeleteDirectory(const char *path) = 0; + virtual Result DoDeleteDirectoryRecursively(const char *path) = 0; + virtual Result DoRenameFile(const char *old_path, const char *new_path) = 0; + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) = 0; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) = 0; + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) = 0; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0; + virtual Result DoCommit() = 0; - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { return fs::ResultNotImplemented(); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { return fs::ResultNotImplemented(); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) = 0; + virtual Result DoCleanDirectoryRecursively(const char *path) = 0; - virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) { return fs::ResultNotImplemented(); } - virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { return fs::ResultNotImplemented(); } /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) { + virtual Result DoCommitProvisionally(s64 counter) { return fs::ResultNotImplemented(); } - virtual Result RollbackImpl() { + virtual Result DoRollback() { return fs::ResultNotImplemented(); } - virtual Result FlushImpl() { + virtual Result DoFlush() { return fs::ResultNotImplemented(); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp index d895c47ad..4a741efde 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp @@ -46,19 +46,19 @@ namespace ams::fssystem { Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs); public: /* Overridden from IPathResolutionFileSystem */ - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result CommitImpl() override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result DoCommit() override; /* Overridden from IPathResolutionFileSystem but not commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override; - virtual Result RollbackImpl() override; + virtual Result DoCommitProvisionally(s64 counter) override; + virtual Result DoRollback() override; /* Explicitly overridden to be not implemented. */ - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override; - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override; - virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override; - virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override; - virtual Result FlushImpl() override; + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override; + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) override; + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override; + virtual Result DoFlush() override; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp index 1230665c3..97897dfae 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp @@ -49,21 +49,21 @@ namespace ams::fssystem { Result GetFileBaseOffset(s64 *out_offset, const char *path); - virtual Result CreateFileImpl(const char *path, s64 size, int option) override; - virtual Result DeleteFileImpl(const char *path) override; - virtual Result CreateDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override; - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override; - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override; - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override; - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; - virtual Result CommitImpl() override; - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override; + virtual Result DoCreateFile(const char *path, s64 size, int option) override; + virtual Result DoDeleteFile(const char *path) override; + virtual Result DoCreateDirectory(const char *path) override; + virtual Result DoDeleteDirectory(const char *path) override; + virtual Result DoDeleteDirectoryRecursively(const char *path) override; + virtual Result DoRenameFile(const char *old_path, const char *new_path) override; + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCommit() override; + virtual Result DoCleanDirectoryRecursively(const char *path) override; /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override; + virtual Result DoCommitProvisionally(s64 counter) override; }; using PartitionFileSystem = PartitionFileSystemCore; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp index 706775653..aea549475 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp @@ -50,22 +50,22 @@ namespace ams::fssystem { RomFileTable *GetRomFileTable(); Result GetFileBaseOffset(s64 *out, const char *path); public: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override; - virtual Result DeleteFileImpl(const char *path) override; - virtual Result CreateDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryImpl(const char *path) override; - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override; - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override; - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override; - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override; - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; - virtual Result CommitImpl() override; - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override; - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override; + virtual Result DoCreateFile(const char *path, s64 size, int flags) override; + virtual Result DoDeleteFile(const char *path) override; + virtual Result DoCreateDirectory(const char *path) override; + virtual Result DoDeleteDirectory(const char *path) override; + virtual Result DoDeleteDirectoryRecursively(const char *path) override; + virtual Result DoRenameFile(const char *old_path, const char *new_path) override; + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCommit() override; + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; + virtual Result DoCleanDirectoryRecursively(const char *path) override; /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override; + virtual Result DoCommitProvisionally(s64 counter) override; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp index d07739349..75991c055 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp @@ -46,7 +46,7 @@ namespace ams::fssystem::impl { return this->unc_preserved; } public: - virtual Result CreateFileImpl(const char *path, s64 size, int option) override { + virtual Result DoCreateFile(const char *path, s64 size, int option) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -54,7 +54,7 @@ namespace ams::fssystem::impl { return this->base_fs->CreateFile(full_path, size, option); } - virtual Result DeleteFileImpl(const char *path) override { + virtual Result DoDeleteFile(const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -62,7 +62,7 @@ namespace ams::fssystem::impl { return this->base_fs->DeleteFile(full_path); } - virtual Result CreateDirectoryImpl(const char *path) override { + virtual Result DoCreateDirectory(const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -70,7 +70,7 @@ namespace ams::fssystem::impl { return this->base_fs->CreateDirectory(full_path); } - virtual Result DeleteDirectoryImpl(const char *path) override { + virtual Result DoDeleteDirectory(const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -78,7 +78,7 @@ namespace ams::fssystem::impl { return this->base_fs->DeleteDirectory(full_path); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override { + virtual Result DoDeleteDirectoryRecursively(const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -86,7 +86,7 @@ namespace ams::fssystem::impl { return this->base_fs->DeleteDirectoryRecursively(full_path); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override { + virtual Result DoRenameFile(const char *old_path, const char *new_path) override { char old_full_path[fs::EntryNameLengthMax + 1]; char new_full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path)); @@ -96,7 +96,7 @@ namespace ams::fssystem::impl { return this->base_fs->RenameFile(old_full_path, new_full_path); } - virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override { + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override { char old_full_path[fs::EntryNameLengthMax + 1]; char new_full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path)); @@ -106,7 +106,7 @@ namespace ams::fssystem::impl { return this->base_fs->RenameDirectory(old_full_path, new_full_path); } - virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override { + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -114,7 +114,7 @@ namespace ams::fssystem::impl { return this->base_fs->GetEntryType(out, full_path); } - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -122,7 +122,7 @@ namespace ams::fssystem::impl { return this->base_fs->OpenFile(out_file, full_path, mode); } - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -130,12 +130,12 @@ namespace ams::fssystem::impl { return this->base_fs->OpenDirectory(out_dir, full_path, mode); } - virtual Result CommitImpl() override { + virtual Result DoCommit() override { std::optional optional_lock = static_cast(this)->GetAccessorLock(); return this->base_fs->Commit(); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -143,7 +143,7 @@ namespace ams::fssystem::impl { return this->base_fs->GetFreeSpaceSize(out, full_path); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -151,7 +151,7 @@ namespace ams::fssystem::impl { return this->base_fs->GetTotalSpaceSize(out, full_path); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override { + virtual Result DoCleanDirectoryRecursively(const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -159,7 +159,7 @@ namespace ams::fssystem::impl { return this->base_fs->CleanDirectoryRecursively(full_path); } - virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override { + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -167,7 +167,7 @@ namespace ams::fssystem::impl { return this->base_fs->GetFileTimeStampRaw(out, full_path); } - virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override { + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -176,17 +176,17 @@ namespace ams::fssystem::impl { } /* These aren't accessible as commands. */ - virtual Result CommitProvisionallyImpl(s64 counter) override { + virtual Result DoCommitProvisionally(s64 counter) override { std::optional optional_lock = static_cast(this)->GetAccessorLock(); return this->base_fs->CommitProvisionally(counter); } - virtual Result RollbackImpl() override { + virtual Result DoRollback() override { std::optional optional_lock = static_cast(this)->GetAccessorLock(); return this->base_fs->Rollback(); } - virtual Result FlushImpl() override { + virtual Result DoFlush() override { std::optional optional_lock = static_cast(this)->GetAccessorLock(); return this->base_fs->Flush(); } diff --git a/libraries/libstratosphere/source/fs/fs_code.cpp b/libraries/libstratosphere/source/fs/fs_code.cpp index ddd363779..00e6a3481 100644 --- a/libraries/libstratosphere/source/fs/fs_code.cpp +++ b/libraries/libstratosphere/source/fs/fs_code.cpp @@ -96,59 +96,59 @@ namespace ams::fs { class OpenFileOnlyFileSystem : public fsa::IFileSystem, public impl::Newable { private: - virtual Result CommitImpl() override final { + virtual Result DoCommit() override final { return ResultSuccess(); } - virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { return fs::ResultUnsupportedOperation(); } - virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { return fs::ResultUnsupportedOperation(); } - virtual Result DeleteFileImpl(const char *path) override final { + virtual Result DoDeleteFile(const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result CreateDirectoryImpl(const char *path) override final { + virtual Result DoCreateDirectory(const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result DeleteDirectoryImpl(const char *path) override final { + virtual Result DoDeleteDirectory(const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(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 { + virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoCleanDirectoryRecursively(const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override final { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override final { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override final { return fs::ResultUnsupportedOperation(); } - virtual Result CommitProvisionallyImpl(s64 counter) override final { + virtual Result DoCommitProvisionally(s64 counter) override final { return fs::ResultUnsupportedOperation(); } }; @@ -201,7 +201,7 @@ namespace ams::fs { return has_file; } - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); @@ -248,7 +248,7 @@ namespace ams::fs { return ResultSuccess(); } private: - virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { /* Ensure that we're initialized. */ R_UNLESS(this->initialized, fs::ResultNotInitialized()); diff --git a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp index 182fe3e0d..311cc407b 100644 --- a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp @@ -199,7 +199,7 @@ namespace ams::fs { return this->parent->GetBaseStorage(); } public: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { size_t read_size = 0; R_TRY(this->VerifyArguments(std::addressof(read_size), offset, buffer, size, option)); @@ -209,24 +209,24 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result GetSizeImpl(s64 *out) override { + virtual Result DoGetSize(s64 *out) override { *out = this->GetSize(); return ResultSuccess(); } - virtual Result FlushImpl() override { + virtual Result DoFlush() override { return ResultSuccess(); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { return fs::ResultUnsupportedOperationInRomFsFileA(); } - virtual Result SetSizeImpl(s64 size) override { + virtual Result DoSetSize(s64 size) override { return fs::ResultUnsupportedOperationInRomFsFileA(); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { switch (op_id) { case OperationId::InvalidateCache: case OperationId::QueryRange: @@ -263,16 +263,16 @@ namespace ams::fs { RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : parent(p), current_find(f), first_find(f), mode(m) { /* ... */ } virtual ~RomFsDirectory() override { /* ... */ } public: - virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { - return this->ReadImpl(out_count, std::addressof(this->current_find), out_entries, max_entries); + virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { + return this->ReadInternal(out_count, std::addressof(this->current_find), out_entries, max_entries); } - virtual Result GetEntryCountImpl(s64 *out) { + virtual Result DoGetEntryCount(s64 *out) { FindPosition find = this->first_find; - return this->ReadImpl(out, std::addressof(find), nullptr, 0); + return this->ReadInternal(out, std::addressof(find), nullptr, 0); } private: - Result ReadImpl(s64 *out_count, FindPosition *find, DirectoryEntry *out_entries, s64 max_entries) { + Result ReadInternal(s64 *out_count, FindPosition *find, DirectoryEntry *out_entries, s64 max_entries) { AMS_ASSERT(out_count != nullptr); AMS_ASSERT(find != nullptr); @@ -440,35 +440,35 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::CreateFileImpl(const char *path, s64 size, int flags) { + Result RomFsFileSystem::DoCreateFile(const char *path, s64 size, int flags) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteFileImpl(const char *path) { + Result RomFsFileSystem::DoDeleteFile(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::CreateDirectoryImpl(const char *path) { + Result RomFsFileSystem::DoCreateDirectory(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteDirectoryImpl(const char *path) { + Result RomFsFileSystem::DoDeleteDirectory(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteDirectoryRecursivelyImpl(const char *path) { + Result RomFsFileSystem::DoDeleteDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::RenameFileImpl(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameFile(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::RenameDirectoryImpl(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameDirectory(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) { + Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { RomDirectoryInfo dir_info; R_TRY_CATCH(this->rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) @@ -484,7 +484,7 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { AMS_ASSERT(out_file != nullptr); AMS_ASSERT(path != nullptr); @@ -500,7 +500,7 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { AMS_ASSERT(out_dir != nullptr); AMS_ASSERT(path != nullptr); @@ -517,28 +517,28 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::CommitImpl() { + Result RomFsFileSystem::DoCommit() { return ResultSuccess(); } - Result RomFsFileSystem::GetFreeSpaceSizeImpl(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { *out = 0; return ResultSuccess(); } - Result RomFsFileSystem::GetTotalSpaceSizeImpl(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetTotalSpaceSize(s64 *out, const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemC(); } - Result RomFsFileSystem::CleanDirectoryRecursivelyImpl(const char *path) { + Result RomFsFileSystem::DoCleanDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::CommitProvisionallyImpl(s64 counter) { + Result RomFsFileSystem::DoCommitProvisionally(s64 counter) { return fs::ResultUnsupportedOperationInRomFsFileSystemB(); } - Result RomFsFileSystem::RollbackImpl() { + Result RomFsFileSystem::DoRollback() { return ResultSuccess(); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp index 723cfd1c6..ebc1b1e54 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp @@ -42,27 +42,27 @@ namespace ams::fssystem { } } public: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { return this->base_file->Read(out, offset, buffer, size, option); } - virtual Result GetSizeImpl(s64 *out) override { + virtual Result DoGetSize(s64 *out) override { return this->base_file->GetSize(out); } - virtual Result FlushImpl() override { + virtual Result DoFlush() override { return this->base_file->Flush(); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { return this->base_file->Write(offset, buffer, size, option); } - virtual Result SetSizeImpl(s64 size) override { + virtual Result DoSetSize(s64 size) override { return this->base_file->SetSize(size); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { return this->base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size); } public: @@ -192,7 +192,7 @@ namespace ams::fssystem { } /* Overridden from IPathResolutionFileSystem */ - Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result DirectorySaveDataFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { char full_path[fs::EntryNameLengthMax + 1]; R_TRY(this->ResolveFullPath(full_path, sizeof(full_path), path)); @@ -211,7 +211,7 @@ namespace ams::fssystem { return ResultSuccess(); } - Result DirectorySaveDataFileSystem::CommitImpl() { + Result DirectorySaveDataFileSystem::DoCommit() { /* Here, Nintendo does the following (with retries): */ /* - Rename Committed -> Synchronizing. */ /* - Synchronize Working -> Synchronizing (deleting Synchronizing). */ @@ -238,34 +238,34 @@ namespace ams::fssystem { } /* Overridden from IPathResolutionFileSystem but not commands. */ - Result DirectorySaveDataFileSystem::CommitProvisionallyImpl(s64 counter) { + Result DirectorySaveDataFileSystem::DoCommitProvisionally(s64 counter) { /* Nintendo does nothing here. */ return ResultSuccess(); } - Result DirectorySaveDataFileSystem::RollbackImpl() { + Result DirectorySaveDataFileSystem::DoRollback() { /* Initialize overwrites the working directory with the committed directory. */ return this->Initialize(); } /* Explicitly overridden to be not implemented. */ - Result DirectorySaveDataFileSystem::GetFreeSpaceSizeImpl(s64 *out, const char *path) { + Result DirectorySaveDataFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { return fs::ResultNotImplemented(); } - Result DirectorySaveDataFileSystem::GetTotalSpaceSizeImpl(s64 *out, const char *path) { + Result DirectorySaveDataFileSystem::DoGetTotalSpaceSize(s64 *out, const char *path) { return fs::ResultNotImplemented(); } - Result DirectorySaveDataFileSystem::GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) { + Result DirectorySaveDataFileSystem::DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) { return fs::ResultNotImplemented(); } - Result DirectorySaveDataFileSystem::QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { + Result DirectorySaveDataFileSystem::DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { return fs::ResultNotImplemented(); } - Result DirectorySaveDataFileSystem::FlushImpl() { + Result DirectorySaveDataFileSystem::DoFlush() { return fs::ResultNotImplemented(); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp index 85632d939..add60023d 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp @@ -47,14 +47,14 @@ namespace ams::fssystem { public: PartitionFile(PartitionFileSystemCore *parent, const typename MetaType::PartitionEntry *partition_entry, fs::OpenMode mode) : partition_entry(partition_entry), parent(parent), mode(mode) { /* ... */ } private: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final; + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final; - virtual Result GetSizeImpl(s64 *out) override final { + virtual Result DoGetSize(s64 *out) override final { *out = this->partition_entry->size; return ResultSuccess(); } - virtual Result FlushImpl() override final { + virtual Result DoFlush() override final { /* Nothing to do if writing disallowed. */ R_SUCCEED_IF((this->mode & fs::OpenMode_Write) == 0); @@ -62,7 +62,7 @@ namespace ams::fssystem { return this->parent->base_storage->Flush(); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { /* Ensure appending is not required. */ bool needs_append; R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, this->mode)); @@ -79,12 +79,12 @@ namespace ams::fssystem { return this->parent->base_storage->Write(this->parent->meta_data_size + this->partition_entry->offset + offset, buffer, size); } - virtual Result SetSizeImpl(s64 size) override final { + virtual Result DoSetSize(s64 size) override final { R_TRY(this->DrySetSize(size, this->mode)); return fs::ResultUnsupportedOperationInPartitionFileA(); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { /* Validate preconditions for operation. */ switch (op_id) { case fs::OperationId::InvalidateCache: @@ -113,7 +113,7 @@ namespace ams::fssystem { }; template<> - Result PartitionFileSystemCore::PartitionFile::ReadImpl(size_t *out, s64 offset, void *dst, size_t dst_size, const fs::ReadOption &option) { + Result PartitionFileSystemCore::PartitionFile::DoRead(size_t *out, s64 offset, void *dst, size_t dst_size, const fs::ReadOption &option) { /* Perform a dry read. */ size_t read_size = 0; R_TRY(this->DryRead(std::addressof(read_size), offset, dst_size, option, this->mode)); @@ -127,7 +127,7 @@ namespace ams::fssystem { } template<> - Result PartitionFileSystemCore::PartitionFile::ReadImpl(size_t *out, s64 offset, void *dst, size_t dst_size, const fs::ReadOption &option) { + Result PartitionFileSystemCore::PartitionFile::DoRead(size_t *out, s64 offset, void *dst, size_t dst_size, const fs::ReadOption &option) { /* Perform a dry read. */ size_t read_size = 0; R_TRY(this->DryRead(std::addressof(read_size), offset, dst_size, option, this->mode)); @@ -223,7 +223,7 @@ namespace ams::fssystem { public: PartitionDirectory(PartitionFileSystemCore *parent, fs::OpenDirectoryMode mode) : cur_index(0), parent(parent), mode(mode) { /* ... */ } public: - virtual Result ReadImpl(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override final { + virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override final { /* There are no subdirectories. */ if ((this->mode & fs::OpenDirectoryMode_File) == 0) { *out_count = 0; @@ -248,7 +248,7 @@ namespace ams::fssystem { return ResultSuccess(); } - virtual Result GetEntryCountImpl(s64 *out) override final { + virtual Result DoGetEntryCount(s64 *out) override final { /* Output the parent meta data entry count for files, otherwise 0. */ if (this->mode & fs::OpenDirectoryMode_File) { *out = this->parent->meta_data->GetEntryCount(); @@ -347,7 +347,7 @@ namespace ams::fssystem { } template - Result PartitionFileSystemCore::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) { + Result PartitionFileSystemCore::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { /* Validate preconditions. */ R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); R_UNLESS(PathTool::IsSeparator(path[0]), fs::ResultInvalidPathFormat()); @@ -366,7 +366,7 @@ namespace ams::fssystem { } template - Result PartitionFileSystemCore::OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result PartitionFileSystemCore::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { /* Validate preconditions. */ R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); @@ -382,7 +382,7 @@ namespace ams::fssystem { } template - Result PartitionFileSystemCore::OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result PartitionFileSystemCore::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { /* Validate preconditions. */ R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); R_UNLESS(std::strncmp(path, PathTool::RootPath, sizeof(PathTool::RootPath)) == 0, fs::ResultPathNotFound()); @@ -395,52 +395,52 @@ namespace ams::fssystem { } template - Result PartitionFileSystemCore::CommitImpl() { + Result PartitionFileSystemCore::DoCommit() { return ResultSuccess(); } template - Result PartitionFileSystemCore::CleanDirectoryRecursivelyImpl(const char *path) { + Result PartitionFileSystemCore::DoCleanDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::CreateDirectoryImpl(const char *path) { + Result PartitionFileSystemCore::DoCreateDirectory(const char *path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::CreateFileImpl(const char *path, s64 size, int option) { + Result PartitionFileSystemCore::DoCreateFile(const char *path, s64 size, int option) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::DeleteDirectoryImpl(const char *path) { + Result PartitionFileSystemCore::DoDeleteDirectory(const char *path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::DeleteDirectoryRecursivelyImpl(const char *path) { + Result PartitionFileSystemCore::DoDeleteDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::DeleteFileImpl(const char *path) { + Result PartitionFileSystemCore::DoDeleteFile(const char *path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::RenameDirectoryImpl(const char *old_path, const char *new_path) { + Result PartitionFileSystemCore::DoRenameDirectory(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::RenameFileImpl(const char *old_path, const char *new_path) { + Result PartitionFileSystemCore::DoRenameFile(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInPartitionFileSystemA(); } template - Result PartitionFileSystemCore::CommitProvisionallyImpl(s64 counter) { + Result PartitionFileSystemCore::DoCommitProvisionally(s64 counter) { return fs::ResultUnsupportedOperationInPartitionFileSystemB(); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp index d736962ee..6c8873735 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp @@ -36,7 +36,7 @@ namespace ams::fssystem { RomFsFile(RomFsFileSystem *p, s64 s, s64 e) : parent(p), start(s), end(e) { /* ... */ } virtual ~RomFsFile() { /* ... */ } public: - virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { size_t read_size = 0; R_TRY(this->DryRead(std::addressof(read_size), offset, size, option, fs::OpenMode_Read)); @@ -50,28 +50,28 @@ namespace ams::fssystem { return ResultSuccess(); } - virtual Result GetSizeImpl(s64 *out) override { + virtual Result DoGetSize(s64 *out) override { *out = this->GetSize(); return ResultSuccess(); } - virtual Result FlushImpl() override { + virtual Result DoFlush() override { return ResultSuccess(); } - virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { bool needs_append; R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, fs::OpenMode_Read)); AMS_ASSERT(needs_append == false); return fs::ResultUnsupportedOperationInRomFsFileA(); } - virtual Result SetSizeImpl(s64 size) override { + virtual Result DoSetSize(s64 size) override { R_TRY(this->DrySetSize(size, fs::OpenMode_Read)); return fs::ResultUnsupportedOperationInRomFsFileA(); } - 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 { + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { switch (op_id) { case fs::OperationId::InvalidateCache: case fs::OperationId::QueryRange: @@ -112,14 +112,14 @@ namespace ams::fssystem { RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : parent(p), current_find(f), first_find(f), mode(m) { /* ... */ } virtual ~RomFsDirectory() override { /* ... */ } public: - virtual Result ReadImpl(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) { + virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { return this->ReadInternal(out_count, std::addressof(this->current_find), out_entries, max_entries); }, AMS_CURRENT_FUNCTION_NAME)); return ResultSuccess(); } - virtual Result GetEntryCountImpl(s64 *out) { + virtual Result DoGetEntryCount(s64 *out) { FindPosition find = this->first_find; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { @@ -296,35 +296,35 @@ namespace ams::fssystem { return ResultSuccess(); } - Result RomFsFileSystem::CreateFileImpl(const char *path, s64 size, int flags) { + Result RomFsFileSystem::DoCreateFile(const char *path, s64 size, int flags) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteFileImpl(const char *path) { + Result RomFsFileSystem::DoDeleteFile(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::CreateDirectoryImpl(const char *path) { + Result RomFsFileSystem::DoCreateDirectory(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteDirectoryImpl(const char *path) { + Result RomFsFileSystem::DoDeleteDirectory(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DeleteDirectoryRecursivelyImpl(const char *path) { + Result RomFsFileSystem::DoDeleteDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::RenameFileImpl(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameFile(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::RenameDirectoryImpl(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameDirectory(const char *old_path, const char *new_path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) { + Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { fs::RomDirectoryInfo dir_info; @@ -346,7 +346,7 @@ namespace ams::fssystem { return ResultSuccess(); } - Result RomFsFileSystem::OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { R_UNLESS(mode == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); RomFileTable::FileInfo file_info; @@ -359,7 +359,7 @@ namespace ams::fssystem { return ResultSuccess(); } - Result RomFsFileSystem::OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { RomFileTable::FindPosition find; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY_CATCH(this->rom_file_table.FindOpen(std::addressof(find), path)) { @@ -376,20 +376,20 @@ namespace ams::fssystem { return ResultSuccess(); } - Result RomFsFileSystem::CommitImpl() { + Result RomFsFileSystem::DoCommit() { return ResultSuccess(); } - Result RomFsFileSystem::GetFreeSpaceSizeImpl(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { *out = 0; return ResultSuccess(); } - Result RomFsFileSystem::CleanDirectoryRecursivelyImpl(const char *path) { + Result RomFsFileSystem::DoCleanDirectoryRecursively(const char *path) { return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::CommitProvisionallyImpl(s64 counter) { + Result RomFsFileSystem::DoCommitProvisionally(s64 counter) { return fs::ResultUnsupportedOperationInRomFsFileSystemB(); } 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 index 4e8a3f580..a2350cbd1 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp @@ -27,66 +27,66 @@ namespace ams::mitm::fs { virtual ~ReadOnlyLayeredFileSystem() { /* ... */ } private: - virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { return ams::fs::ResultUnsupportedOperation(); } - virtual Result DeleteFileImpl(const char *path) override final { + virtual Result DoDeleteFile(const char *path) override final { return ams::fs::ResultUnsupportedOperation(); } - virtual Result CreateDirectoryImpl(const char *path) override final { + virtual Result DoCreateDirectory(const char *path) override final { return ams::fs::ResultUnsupportedOperation(); } - virtual Result DeleteDirectoryImpl(const char *path) override final { + virtual Result DoDeleteDirectory(const char *path) override final { return ams::fs::ResultUnsupportedOperation(); } - virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const char *path) override final { return ams::fs::ResultUnsupportedOperation(); } - virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(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 { + virtual Result DoRenameDirectory(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 { + virtual Result DoGetEntryType(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 { + virtual Result DoOpenFile(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 { + virtual Result DoOpenDirectory(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 { + virtual Result DoCommit() override final { return ResultSuccess(); } - virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { return ams::fs::ResultUnsupportedOperation(); } - virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { return ams::fs::ResultUnsupportedOperation(); } - virtual Result CleanDirectoryRecursivelyImpl(const char *path) { + virtual Result DoCleanDirectoryRecursively(const char *path) { return ams::fs::ResultUnsupportedOperation(); } - virtual Result GetFileTimeStampRawImpl(ams::fs::FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(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); } From 7548940efa3deb0282c08def4f2768e46f15b618 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 5 Dec 2020 03:15:48 -0800 Subject: [PATCH 05/29] IStorage: rename access check helpers --- .../include/stratosphere/fs/fs_istorage.hpp | 12 ++++++------ .../stratosphere/fs/fs_memory_storage.hpp | 8 ++++---- .../include/stratosphere/fs/fs_substorage.hpp | 16 ++++++++-------- .../fssystem_alignment_matching_storage.hpp | 16 ++++++++-------- .../source/fs/fs_file_storage.cpp | 10 +++++----- .../fssystem_alignment_matching_storage_impl.cpp | 2 +- .../fssystem_integrity_verification_storage.cpp | 8 ++++---- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp index d6749c5c3..7a837242d 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp @@ -40,25 +40,25 @@ namespace ams::fs { return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0); } public: - static inline bool IsRangeValid(s64 offset, s64 size, s64 total_size) { + static inline bool CheckAccessRange(s64 offset, s64 size, s64 total_size) { return offset >= 0 && size >= 0 && size <= total_size && offset <= (total_size - size); } - static inline bool IsRangeValid(s64 offset, size_t size, s64 total_size) { - return IsRangeValid(offset, static_cast(size), total_size); + static inline bool CheckAccessRange(s64 offset, size_t size, s64 total_size) { + return CheckAccessRange(offset, static_cast(size), total_size); } - static inline bool IsOffsetAndSizeValid(s64 offset, s64 size) { + static inline bool CheckOffsetAndSize(s64 offset, s64 size) { return offset >= 0 && size >= 0 && offset <= (offset + size); } - static inline bool IsOffsetAndSizeValid(s64 offset, size_t size) { - return IsOffsetAndSizeValid(offset, static_cast(size)); + static inline bool CheckOffsetAndSize(s64 offset, size_t size) { + return CheckOffsetAndSize(offset, static_cast(size)); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp index b897c535e..9cc59e790 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp @@ -32,8 +32,8 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); /* Copy from memory. */ std::memcpy(buffer, this->buf + offset, size); @@ -45,8 +45,8 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); /* Copy to memory. */ std::memcpy(this->buf + offset, buffer, size); diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp index 4e39ae361..08ac3cf7b 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp @@ -77,8 +77,8 @@ namespace ams::fs { /* Validate arguments and read. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); return this->base_storage->Read(this->offset + offset, buffer, size); } @@ -90,8 +90,8 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments and write. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); return this->base_storage->Write(this->offset + offset, buffer, size); } @@ -102,9 +102,9 @@ namespace ams::fs { virtual Result SetSize(s64 size) override { /* Ensure we're initialized and validate arguments. */ - R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); - R_UNLESS(this->resizable, fs::ResultUnsupportedOperationInSubStorageA()); - R_UNLESS(IStorage::IsOffsetAndSizeValid(this->offset, size), fs::ResultInvalidSize()); + R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); + R_UNLESS(this->resizable, fs::ResultUnsupportedOperationInSubStorageA()); + R_UNLESS(IStorage::CheckOffsetAndSize(this->offset, size), fs::ResultInvalidSize()); /* Ensure that we're allowed to set size. */ s64 cur_size; @@ -134,7 +134,7 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments and operate. */ - R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); return this->base_storage->OperateRange(dst, dst_size, op_id, this->offset + offset, size, src, src_size); } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp index 2ff67cea3..ba3a92194 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp @@ -61,7 +61,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); return AlignmentMatchingStorageImpl::Read(this->base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast(buffer), size); } @@ -79,7 +79,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); return AlignmentMatchingStorageImpl::Write(this->base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast(buffer), size); } @@ -115,7 +115,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); @@ -154,7 +154,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; @@ -172,7 +172,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; @@ -212,7 +212,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); @@ -257,7 +257,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer(this->data_align, this->data_align); @@ -294,7 +294,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); diff --git a/libraries/libstratosphere/source/fs/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/fs_file_storage.cpp index b56153fb0..d0401bb3d 100644 --- a/libraries/libstratosphere/source/fs/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/fs_file_storage.cpp @@ -33,7 +33,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); size_t read_size; return this->base_file->Read(&read_size, offset, buffer, size); @@ -50,7 +50,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); return this->base_file->Write(offset, buffer, size, fs::WriteOption()); } @@ -83,7 +83,7 @@ namespace ams::fs { return ResultSuccess(); } R_TRY(this->UpdateSize()); - R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); return this->base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size); default: return fs::ResultUnsupportedOperationInFileStorageA(); @@ -121,7 +121,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); return ReadFile(this->handle, offset, buffer, size, fs::ReadOption()); } @@ -140,7 +140,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); return WriteFile(this->handle, offset, buffer, size, fs::WriteOption()); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp b/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp index 920e8a2e8..eb5b2cfc5 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp @@ -197,7 +197,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::IsRangeValid(offset, size, bs_size), fs::ResultOutOfRange()); + R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); /* Determine extents. */ const auto offset_end = offset + static_cast(size); diff --git a/libraries/libstratosphere/source/fssystem/save/fssystem_integrity_verification_storage.cpp b/libraries/libstratosphere/source/fssystem/save/fssystem_integrity_verification_storage.cpp index c2f5737b0..18003dded 100644 --- a/libraries/libstratosphere/source/fssystem/save/fssystem_integrity_verification_storage.cpp +++ b/libraries/libstratosphere/source/fssystem/save/fssystem_integrity_verification_storage.cpp @@ -86,7 +86,7 @@ namespace ams::fssystem::save { R_UNLESS(offset <= data_size, fs::ResultInvalidOffset()); /* Validate the access range. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, util::AlignUp(data_size, static_cast(this->verification_block_size))), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(this->verification_block_size))), fs::ResultOutOfRange()); /* Determine the read extents. */ size_t read_size = size; @@ -164,8 +164,8 @@ namespace ams::fssystem::save { R_SUCCEED_IF(size == 0); /* Validate arguments. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultInvalidOffset()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultInvalidOffset()); /* Validate the offset. */ s64 data_size; @@ -173,7 +173,7 @@ namespace ams::fssystem::save { R_UNLESS(offset < data_size, fs::ResultInvalidOffset()); /* Validate the access range. */ - R_UNLESS(IStorage::IsRangeValid(offset, size, util::AlignUp(data_size, static_cast(this->verification_block_size))), fs::ResultOutOfRange()); + R_UNLESS(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(this->verification_block_size))), fs::ResultOutOfRange()); /* Validate preconditions. */ AMS_ASSERT(util::IsAligned(offset, this->verification_block_size)); From 5ef93778f62cb52d0fbf9ca01b2a43444c35b200 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 5 Dec 2020 03:31:12 -0800 Subject: [PATCH 06/29] fs: move file storage to common --- libraries/libstratosphere/include/stratosphere/fs.hpp | 2 +- .../include/stratosphere/fs/{ => common}/fs_file_storage.hpp | 0 .../stratosphere/ncm/ncm_submission_package_install_task.hpp | 2 +- .../source/fs/{ => common}/fs_file_storage.cpp | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename libraries/libstratosphere/include/stratosphere/fs/{ => common}/fs_file_storage.hpp (100%) rename libraries/libstratosphere/source/fs/{ => common}/fs_file_storage.cpp (97%) diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 176588fe7..413d23b28 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp similarity index 100% rename from libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp rename to libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_submission_package_install_task.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_submission_package_install_task.hpp index 91f8b2001..790590c23 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_submission_package_install_task.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_submission_package_install_task.hpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #pragma once -#include +#include #include namespace ams::ncm { diff --git a/libraries/libstratosphere/source/fs/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp similarity index 97% rename from libraries/libstratosphere/source/fs/fs_file_storage.cpp rename to libraries/libstratosphere/source/fs/common/fs_file_storage.cpp index d0401bb3d..1d6bdfd13 100644 --- a/libraries/libstratosphere/source/fs/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp @@ -19,7 +19,7 @@ namespace ams::fs { Result FileStorage::UpdateSize() { R_SUCCEED_IF(this->size != InvalidSize); - return this->base_file->GetSize(&this->size); + return this->base_file->GetSize(std::addressof(this->size)); } Result FileStorage::Read(s64 offset, void *buffer, size_t size) { @@ -36,7 +36,7 @@ namespace ams::fs { R_UNLESS(IStorage::CheckAccessRange(offset, size, this->size), fs::ResultOutOfRange()); size_t read_size; - return this->base_file->Read(&read_size, offset, buffer, size); + return this->base_file->Read(std::addressof(read_size), offset, buffer, size); } Result FileStorage::Write(s64 offset, const void *buffer, size_t size) { From 32803d992063b9aa365f7791112482368b9e61ab Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 6 Dec 2020 19:56:45 -0800 Subject: [PATCH 07/29] fs: update + consolidate path normalization logic --- .../include/stratosphere/fs.hpp | 1 - .../include/stratosphere/fs/fs_path_tool.hpp | 86 --- .../include/stratosphere/fs/fs_path_utils.hpp | 79 ++- .../stratosphere/fs/fs_remote_filesystem.hpp | 9 +- .../fssrv/fssrv_path_normalizer.hpp | 11 +- .../include/stratosphere/fssystem.hpp | 1 - .../fssystem/fssystem_utility.hpp | 20 +- .../libstratosphere/source/fs/fs_bis.cpp | 2 +- .../source/fs/fs_path_normalizer.cpp | 569 ++++++++++++++++++ .../source/fs/fs_path_tool.cpp | 248 -------- .../source/fs/fs_path_utils.cpp | 117 +++- .../source/fs/fsa/fs_mount_utils.cpp | 22 +- .../fssrv_filesystem_interface_adapter.cpp | 2 +- .../source/fssrv/fssrv_path_normalizer.cpp | 37 +- ...ystem_directory_redirection_filesystem.cpp | 42 +- ...fssystem_directory_savedata_filesystem.cpp | 8 +- .../fssystem_partition_file_system.cpp | 12 +- .../fssystem_subdirectory_filesystem.cpp | 20 +- .../source/fssystem/fssystem_utility.cpp | 12 +- libraries/libvapours/include/vapours/util.hpp | 1 + .../vapours/util/util_character_encoding.hpp} | 17 +- .../source/util/util_character_encoding.cpp | 154 +++++ 22 files changed, 1007 insertions(+), 463 deletions(-) delete mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp create mode 100644 libraries/libstratosphere/source/fs/fs_path_normalizer.cpp delete mode 100644 libraries/libstratosphere/source/fs/fs_path_tool.cpp rename libraries/{libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp => libvapours/include/vapours/util/util_character_encoding.hpp} (58%) create mode 100644 libraries/libvapours/source/util/util_character_encoding.cpp diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 413d23b28..c6b5bc537 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp deleted file mode 100644 index 9d9e145b8..000000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 - -namespace ams::fs { - - namespace StringTraits { - - constexpr inline char DirectorySeparator = '/'; - constexpr inline char DriveSeparator = ':'; - constexpr inline char Dot = '.'; - constexpr inline char NullTerminator = '\x00'; - - constexpr inline char AlternateDirectorySeparator = '\\'; - } - - class PathTool { - public: - static constexpr const char RootPath[] = "/"; - public: - static constexpr inline bool IsAlternateSeparator(char c) { - return c == StringTraits::AlternateDirectorySeparator; - } - - static constexpr inline bool IsSeparator(char c) { - return c == StringTraits::DirectorySeparator; - } - - static constexpr inline bool IsAnySeparator(char c) { - return IsSeparator(c) || IsAlternateSeparator(c); - } - - static constexpr inline bool IsNullTerminator(char c) { - return c == StringTraits::NullTerminator; - } - - static constexpr inline bool IsDot(char c) { - return c == StringTraits::Dot; - } - - static constexpr inline bool IsWindowsDriveCharacter(char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); - } - - static constexpr inline bool IsDriveSeparator(char c) { - return c == StringTraits::DriveSeparator; - } - - static constexpr inline bool IsWindowsAbsolutePath(const char *p) { - return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]); - } - - static constexpr inline bool IsUnc(const char *p) { - return (IsSeparator(p[0]) && IsSeparator(p[1])) || (IsAlternateSeparator(p[0]) && IsAlternateSeparator(p[1])); - } - - static constexpr inline bool IsCurrentDirectory(const char *p) { - return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1])); - } - - static constexpr inline bool IsParentDirectory(const char *p) { - return IsDot(p[0]) && IsDot(p[1]) && (IsSeparator(p[2]) || IsNullTerminator(p[2])); - } - - static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false); - static Result IsNormalized(bool *out, const char *path); - - static bool IsSubPath(const char *lhs, const char *rhs); - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp index 59174ce20..7ddeb8a78 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp @@ -19,15 +19,59 @@ namespace ams::fs { + namespace StringTraits { + + constexpr inline char DirectorySeparator = '/'; + constexpr inline char DriveSeparator = ':'; + constexpr inline char Dot = '.'; + constexpr inline char NullTerminator = '\x00'; + + constexpr inline char AlternateDirectorySeparator = '\\'; + + } + + /* Windows path utilities. */ + constexpr inline bool IsWindowsDrive(const char *path) { + AMS_ASSERT(path != nullptr); + + const char c = path[0]; + return (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) && path[1] == StringTraits::DriveSeparator; + } + + constexpr inline bool IsUnc(const char *path) { + return (path[0] == StringTraits::DirectorySeparator && path[1] == StringTraits::DirectorySeparator) || + (path[0] == StringTraits::AlternateDirectorySeparator && path[1] == StringTraits::AlternateDirectorySeparator); + } + + constexpr inline s64 GetWindowsPathSkipLength(const char *path) { + if (IsWindowsDrive(path)) { + return 2; + } + if (IsUnc(path)) { + for (s64 i = 2; path[i] != StringTraits::NullTerminator; ++i) { + if (path[i] == '$' || path[i] == ':') { + return i + 1; + } + } + } + return 0; + } + + /* Path utilities. */ inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) { - for (char *cur = dst; cur < dst + dst_size && *cur != '\x00'; cur++) { + AMS_ASSERT(dst != nullptr); + for (char *cur = dst; cur < dst + dst_size && *cur != StringTraits::NullTerminator; ++cur) { if (*cur == old_char) { *cur = new_char; } } } + Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) __attribute__((format(printf, 2, 3))); + inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) { + AMS_ASSERT(dst != nullptr); + /* Format the path. */ std::va_list va_list; va_start(va_list, format); @@ -43,6 +87,37 @@ namespace ams::fs { return ResultSuccess(); } - Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len); + Result VerifyPath(const char *path, int max_path_len, int max_name_len); + + bool IsSubPath(const char *lhs, const char *rhs); + + /* Path normalization. */ + class PathNormalizer { + public: + static constexpr const char RootPath[] = "/"; + public: + static constexpr inline bool IsSeparator(char c) { + return c == StringTraits::DirectorySeparator; + } + + static constexpr inline bool IsAnySeparator(char c) { + return c == StringTraits::DirectorySeparator || c == StringTraits::AlternateDirectorySeparator; + } + + static constexpr inline bool IsNullTerminator(char c) { + return c == StringTraits::NullTerminator; + } + + static constexpr inline bool IsCurrentDirectory(const char *p) { + return p[0] == StringTraits::Dot && (IsSeparator(p[1]) || IsNullTerminator(p[1])); + } + + static constexpr inline bool IsParentDirectory(const char *p) { + return p[0] == StringTraits::Dot && p[1] == StringTraits::Dot && (IsSeparator(p[2]) || IsNullTerminator(p[2])); + } + + static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false, bool has_mount_name = false); + static Result IsNormalized(bool *out, const char *path, bool unc_preserved = false, bool has_mount_name = false); + }; } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp index 0d32894ea..b1b95c95c 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include namespace ams::fs { @@ -100,12 +99,12 @@ namespace ams::fs { out_path->str[sizeof(out_path->str) - 1] = '\x00'; /* Replace directory separators. */ - Replace(out_path->str, sizeof(out_path->str) - 1, StringTraits::AlternateDirectorySeparator, StringTraits::DirectorySeparator); + fs::Replace(out_path->str, sizeof(out_path->str) - 1, StringTraits::AlternateDirectorySeparator, StringTraits::DirectorySeparator); /* Get lengths. */ - const auto mount_name_len = PathTool::IsWindowsAbsolutePath(path) ? 2 : 0; - const auto rel_path = out_path->str + mount_name_len; - const auto max_len = fs::EntryNameLengthMax - mount_name_len; + const auto skip_len = fs::GetWindowsPathSkipLength(path); + const auto rel_path = out_path->str + skip_len; + const auto max_len = fs::EntryNameLengthMax - skip_len; return VerifyPath(rel_path, max_len, max_len); } public: diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp index 6bace6065..2d970b4ec 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp @@ -31,7 +31,7 @@ namespace ams::fssrv { Option_AcceptEmpty = BIT(4), }; private: - using Buffer = std::unique_ptr; + using Buffer = std::unique_ptr; private: Buffer buffer; const char *path; @@ -39,8 +39,9 @@ namespace ams::fssrv { private: static Result Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name); public: + /* TODO: Remove non-option constructor. */ explicit PathNormalizer(const char *p) : buffer(), path(nullptr), result(ResultSuccess()) { - this->result = Normalize(&this->path, &this->buffer, p, false, false, false); + this->result = Normalize(std::addressof(this->path), std::addressof(this->buffer), p, false, false, false); } PathNormalizer(const char *p, u32 option) : buffer(), path(nullptr), result(ResultSuccess()) { @@ -50,15 +51,15 @@ namespace ams::fssrv { const bool preserve_unc = (option & Option_PreserveUnc); const bool preserve_tail_sep = (option & Option_PreserveTailSeparator); const bool has_mount_name = (option & Option_HasMountName); - this->result = Normalize(&this->path, &this->buffer, p, preserve_unc, preserve_tail_sep, has_mount_name); + this->result = Normalize(std::addressof(this->path), std::addressof(this->buffer), p, preserve_unc, preserve_tail_sep, has_mount_name); } } - inline Result GetResult() const { + Result GetResult() const { return this->result; } - inline const char * GetPath() const { + const char *GetPath() const { return this->path; } }; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem.hpp index 2be11f318..d95feee40 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp index fefa2df3c..4e6b77a8b 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp @@ -14,11 +14,11 @@ * along with this program. If not, see . */ #pragma once -#include "../fs/fs_common.hpp" -#include "../fs/fs_file.hpp" -#include "../fs/fs_directory.hpp" -#include "../fs/fs_filesystem.hpp" -#include "fssystem_path_tool.hpp" +#include +#include +#include +#include +#include namespace ams::fssystem { @@ -70,7 +70,7 @@ namespace ams::fssystem { } /* Restore parent path. */ - work_path[parent_len] = StringTraits::NullTerminator; + work_path[parent_len] = fs::StringTraits::NullTerminator; } return ResultSuccess(); @@ -91,13 +91,13 @@ namespace ams::fssystem { /* Copy root path in, add a / if necessary. */ std::memcpy(work_path, root_path, root_path_len); - if (!PathTool::IsSeparator(work_path[root_path_len - 1])) { - work_path[root_path_len++] = StringTraits::DirectorySeparator; + if (!fs::PathNormalizer::IsSeparator(work_path[root_path_len - 1])) { + work_path[root_path_len++] = fs::StringTraits::DirectorySeparator; } /* Make sure the result path is still valid. */ R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); - work_path[root_path_len] = StringTraits::NullTerminator; + work_path[root_path_len] = fs::StringTraits::NullTerminator; return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file); } @@ -111,7 +111,7 @@ namespace ams::fssystem { template Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { - return IterateDirectoryRecursively(fs, PathTool::RootPath, on_enter_dir, on_exit_dir, on_file); + return IterateDirectoryRecursively(fs, fs::PathNormalizer::RootPath, on_enter_dir, on_exit_dir, on_file); } /* TODO: Cleanup API */ diff --git a/libraries/libstratosphere/source/fs/fs_bis.cpp b/libraries/libstratosphere/source/fs/fs_bis.cpp index a90ee12b8..0d9694cd9 100644 --- a/libraries/libstratosphere/source/fs/fs_bis.cpp +++ b/libraries/libstratosphere/source/fs/fs_bis.cpp @@ -72,7 +72,7 @@ namespace ams::fs { fssrv::sf::Path sf_path; if (len > 0) { - const bool ending_sep = PathTool::IsSeparator(root_path[len - 1]); + const bool ending_sep = PathNormalizer::IsSeparator(root_path[len - 1]); FspPathPrintf(std::addressof(sf_path), "%s%s", root_path, ending_sep ? "" : "/"); } else { sf_path.str[0] = '\x00'; diff --git a/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp b/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp new file mode 100644 index 000000000..7f1beadba --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp @@ -0,0 +1,569 @@ +/* + * 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 . + */ +#include + +namespace ams::fs { + + namespace { + + Result CheckSharedName(const char *path, int len) { + if (len == 1) { + R_UNLESS(path[0] != StringTraits::Dot, fs::ResultInvalidPathFormat()); + } else if (len == 2) { + R_UNLESS(path[0] != StringTraits::Dot || path[1] != StringTraits::Dot, fs::ResultInvalidPathFormat()); + } + + return ResultSuccess(); + } + + Result ParseWindowsPath(const char **out_path, char *out, size_t *out_windows_path_len, bool *out_normalized, const char *path, size_t max_out_size, bool has_mount_name) { + /* Prepare to parse. */ + const char * const path_start = path; + if (out_normalized != nullptr) { + *out_normalized = true; + } + + /* Handle start of path. */ + bool skipped_mount = false; + auto prefix_len = 0; + if (has_mount_name) { + if (PathNormalizer::IsSeparator(path[0]) && path[1] == StringTraits::AlternateDirectorySeparator && path[2] == StringTraits::AlternateDirectorySeparator) { + path += 1; + prefix_len = 1; + } else { + /* Advance past separators. */ + while (PathNormalizer::IsSeparator(path[0])) { + ++path; + } + if (path != path_start) { + if (path - path_start == 1 || IsWindowsDrive(path)) { + prefix_len = 1; + } else { + if (path - path_start > 2 && out_normalized != nullptr) { + *out_normalized = false; + return ResultSuccess(); + } + path -= 2; + skipped_mount = true; + } + } + } + } else if (PathNormalizer::IsSeparator(path[0]) && !IsUnc(path)) { + path += 1; + prefix_len = 1; + } + + + /* Parse the path. */ + const char *trimmed_path = path_start; + if (IsWindowsDrive(path)) { + /* Find the first separator. */ + int i; + for (i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { + if (PathNormalizer::IsAnySeparator(path[i])) { + break; + } + } + trimmed_path = path + i; + + const size_t win_path_len = trimmed_path - path_start; + if (out != nullptr) { + R_UNLESS(win_path_len <= max_out_size, fs::ResultTooLongPath()); + std::memcpy(out, path_start, win_path_len); + } + *out_path = trimmed_path; + *out_windows_path_len = win_path_len; + } else if (IsUnc(path)) { + if (PathNormalizer::IsAnySeparator(path[2])) { + AMS_ASSERT(!has_mount_name); + return fs::ResultInvalidPathFormat(); + } + + int cur_part_ofs = 0; + bool needs_sep_fix = false; + for (auto i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { + if (cur_part_ofs == 0 && path[i] == StringTraits::AlternateDirectorySeparator) { + needs_sep_fix = true; + if (out_normalized != nullptr) { + *out_normalized = false; + return ResultSuccess(); + } + } + if (PathNormalizer::IsAnySeparator(path[i])) { + if (path[i] == StringTraits::AlternateDirectorySeparator) { + needs_sep_fix = true; + } + + if (cur_part_ofs != 0) { + break; + } + + R_UNLESS(!PathNormalizer::IsSeparator(path[i + 1]), fs::ResultInvalidPathFormat()); + + R_TRY(CheckSharedName(path + 2, i - 2)); + + cur_part_ofs = i + 1; + } + if (path[i] == '$' || path[i] == StringTraits::DriveSeparator) { + R_UNLESS(cur_part_ofs != 0, fs::ResultInvalidCharacter()); + R_UNLESS(PathNormalizer::IsAnySeparator(path[i + 1]) || PathNormalizer::IsNullTerminator(path[i + 1]), fs::ResultInvalidPathFormat()); + trimmed_path = path + i + 1; + break; + } + } + + if (trimmed_path == path_start) { + int tr_part_ofs = 0; + int i; + for (i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { + if (PathNormalizer::IsAnySeparator(path[i])) { + if (tr_part_ofs != 0) { + R_TRY(CheckSharedName(path + tr_part_ofs, i - tr_part_ofs)); + trimmed_path = path + i; + break; + } + + R_UNLESS(!PathNormalizer::IsSeparator(path[i + 1]), fs::ResultInvalidPathFormat()); + + R_TRY(CheckSharedName(path + 2, i - 2)); + + cur_part_ofs = i + 1; + } + } + + if (tr_part_ofs != 0 && trimmed_path == path_start) { + R_TRY(CheckSharedName(path + tr_part_ofs, i - tr_part_ofs)); + trimmed_path = path + i; + } + } + + const size_t win_path_len = trimmed_path - path; + const bool prepend_sep = prefix_len != 0 || skipped_mount; + if (out != nullptr) { + R_UNLESS(win_path_len <= max_out_size, fs::ResultTooLongPath()); + if (prepend_sep) { + *(out++) = StringTraits::DirectorySeparator; + } + std::memcpy(out, path, win_path_len); + out[0] = StringTraits::AlternateDirectorySeparator; + out[1] = StringTraits::AlternateDirectorySeparator; + if (needs_sep_fix) { + for (size_t i = 2; i < win_path_len; ++i) { + if (PathNormalizer::IsSeparator(out[i])) { + out[i] = StringTraits::AlternateDirectorySeparator; + } + } + } + } + *out_path = trimmed_path; + *out_windows_path_len = win_path_len + (prepend_sep ? 1 : 0); + } else { + *out_path = trimmed_path; + } + + return ResultSuccess(); + } + + Result SkipWindowsPath(const char **out_path, bool *out_normalized, const char *path, bool has_mount_name) { + size_t windows_path_len; + return ParseWindowsPath(out_path, nullptr, std::addressof(windows_path_len), out_normalized, path, 0, has_mount_name); + } + + Result ParseMountName(const char **out_path, char *out, size_t *out_mount_name_len, const char *path, size_t max_out_size) { + /* Decide on a start. */ + const char *start = PathNormalizer::IsSeparator(path[0]) ? path + 1 : path; + + /* Find the end of the mount name. */ + const char *cur; + for (cur = start; cur < start + MountNameLengthMax + 1; ++cur) { + if (*cur == StringTraits::DriveSeparator) { + ++cur; + break; + } + if (PathNormalizer::IsSeparator(*cur)) { + *out_path = path; + *out_mount_name_len = 0; + return ResultSuccess(); + } + } + R_UNLESS(start < cur - 1, fs::ResultInvalidPathFormat()); + R_UNLESS(cur[-1] == StringTraits::DriveSeparator, fs::ResultInvalidPathFormat()); + + /* Check the mount name doesn't contain a dot. */ + if (cur != start) { + for (const char *p = start; p < cur; ++p) { + R_UNLESS(*p != StringTraits::Dot, fs::ResultInvalidCharacter()); + } + } + + const size_t mount_name_len = cur - path; + if (out != nullptr) { + R_UNLESS(mount_name_len <= max_out_size, fs::ResultTooLongPath()); + std::memcpy(out, path, mount_name_len); + } + *out_path = cur; + *out_mount_name_len = mount_name_len; + + return ResultSuccess(); + } + + Result SkipMountName(const char **out_path, const char *path) { + size_t mount_name_len; + return ParseMountName(out_path, nullptr, std::addressof(mount_name_len), path, 0); + } + + bool IsParentDirectoryPathReplacementNeeded(const char *path) { + if (!PathNormalizer::IsAnySeparator(path[0])) { + return false; + } + + for (auto i = 0; !PathNormalizer::IsNullTerminator(path[i]); ++i) { + if (path[i + 0] == StringTraits::AlternateDirectorySeparator && + path[i + 1] == StringTraits::Dot && + path[i + 2] == StringTraits::Dot && + (PathNormalizer::IsAnySeparator(path[i + 3]) || PathNormalizer::IsNullTerminator(path[i + 3]))) + { + return true; + } + + if (PathNormalizer::IsAnySeparator(path[i + 0]) && + path[i + 1] == StringTraits::Dot && + path[i + 2] == StringTraits::Dot && + path[i + 3] == StringTraits::AlternateDirectorySeparator) + { + return true; + } + } + + return false; + } + + void ReplaceParentDirectoryPath(char *dst, const char *src) { + dst[0] = StringTraits::DirectorySeparator; + + int i = 1; + while (!PathNormalizer::IsNullTerminator(src[i])) { + if (PathNormalizer::IsAnySeparator(src[i - 1]) && + src[i + 0] == StringTraits::Dot && + src[i + 1] == StringTraits::Dot && + PathNormalizer::IsAnySeparator(src[i + 2])) + { + dst[i - 1] = StringTraits::DirectorySeparator; + dst[i + 0] = StringTraits::Dot; + dst[i + 1] = StringTraits::Dot; + dst[i - 2] = StringTraits::DirectorySeparator; + i += 3; + } else { + if (src[i - 1] == StringTraits::AlternateDirectorySeparator && + src[i + 0] == StringTraits::Dot && + src[i + 1] == StringTraits::Dot && + PathNormalizer::IsNullTerminator(src[i + 2])) + { + dst[i - 1] = StringTraits::DirectorySeparator; + dst[i + 0] = StringTraits::Dot; + dst[i + 1] = StringTraits::Dot; + i += 2; + break; + } + + dst[i] = src[i]; + ++i; + } + } + + dst[i] = StringTraits::NullTerminator; + } + + } + + Result PathNormalizer::Normalize(char *out, size_t *out_len, const char *path, size_t max_out_size, bool unc_preserved, bool has_mount_name) { + /* Check pre-conditions. */ + AMS_ASSERT(out != nullptr); + AMS_ASSERT(out_len != nullptr); + AMS_ASSERT(path != nullptr); + + /* If we should, handle the mount name. */ + size_t prefix_len = 0; + if (has_mount_name) { + size_t mount_name_len = 0; + R_TRY(ParseMountName(std::addressof(path), out, std::addressof(mount_name_len), path, max_out_size)); + prefix_len += mount_name_len; + } + + /* Deal with unc. */ + bool is_unc_path = false; + if (unc_preserved) { + const char * const path_start = path; + size_t windows_path_len = 0; + R_TRY(ParseWindowsPath(std::addressof(path), out + prefix_len, std::addressof(windows_path_len), nullptr, path, max_out_size, has_mount_name)); + prefix_len += windows_path_len; + is_unc_path = path != path_start; + } + + /* Paths must start with / */ + R_UNLESS(prefix_len != 0 || IsSeparator(path[0]), fs::ResultInvalidPathFormat()); + + /* Check if parent directory path replacement is needed. */ + std::unique_ptr replacement_path; + if (IsParentDirectoryPathReplacementNeeded(path)) { + /* Allocate a buffer to hold the replacement path. */ + replacement_path = fs::impl::MakeUnique(EntryNameLengthMax + 1); + R_UNLESS(replacement_path != nullptr, fs::ResultAllocationFailureInNew()); + + /* Replace the path. */ + ReplaceParentDirectoryPath(replacement_path.get(), path); + + /* Set path to be the replacement path. */ + path = replacement_path.get(); + } + + bool skip_next_sep = false; + size_t i = 0; + size_t len = prefix_len; + + while (!IsNullTerminator(path[i])) { + if (IsSeparator(path[i])) { + /* Swallow separators. */ + while (IsSeparator(path[++i])) { } + if (IsNullTerminator(path[i])) { + break; + } + + /* Handle skip if needed */ + if (!skip_next_sep) { + if (len + 1 == max_out_size) { + out[len] = StringTraits::NullTerminator; + *out_len = len; + return fs::ResultTooLongPath(); + } + + out[len++] = StringTraits::DirectorySeparator; + } + skip_next_sep = false; + } + + /* See length of current dir. */ + size_t dir_len = 0; + while (!IsSeparator(path[i + dir_len]) && !IsNullTerminator(path[i + dir_len])) { + ++dir_len; + } + + if (IsCurrentDirectory(path + i)) { + skip_next_sep = true; + } else if (IsParentDirectory(path + i)) { + AMS_ASSERT(IsSeparator(out[len - 1])); + if (!is_unc_path) { + AMS_ASSERT(IsSeparator(out[prefix_len])); + } + + /* Walk up a directory. */ + if (len == prefix_len + 1) { + R_UNLESS(is_unc_path, fs::ResultDirectoryUnobtainable()); + --len; + } else { + len -= 2; + do { + if (IsSeparator(out[len])) { + break; + } + --len; + } while (len != prefix_len); + } + + if (!is_unc_path) { + AMS_ASSERT(IsSeparator(out[prefix_len])); + } + + AMS_ASSERT(len < max_out_size); + } else { + /* Copy, possibly truncating. */ + if (len + dir_len + 1 <= max_out_size) { + for (size_t j = 0; j < dir_len; ++j) { + out[len++] = path[i+j]; + } + } else { + const size_t copy_len = max_out_size - 1 - len; + for (size_t j = 0; j < copy_len; ++j) { + out[len++] = path[i+j]; + } + out[len] = StringTraits::NullTerminator; + *out_len = len; + return fs::ResultTooLongPath(); + } + } + + i += dir_len; + } + + if (skip_next_sep) { + --len; + } + + if (!is_unc_path && len == prefix_len && max_out_size > len) { + out[len++] = StringTraits::DirectorySeparator; + } + + R_UNLESS(max_out_size >= len - 1, fs::ResultTooLongPath()); + + /* Null terminate. */ + out[len] = StringTraits::NullTerminator; + *out_len = len; + + /* Assert normalized. */ + { + bool normalized = false; + const auto is_norm_result = IsNormalized(std::addressof(normalized), out, unc_preserved, has_mount_name); + AMS_ASSERT(R_SUCCEEDED(is_norm_result)); + AMS_ASSERT(normalized); + } + + return ResultSuccess(); + } + + Result PathNormalizer::IsNormalized(bool *out, const char *path, bool unc_preserved, bool has_mount_name) { + AMS_ASSERT(out != nullptr); + AMS_ASSERT(path != nullptr); + + /* Save the start of the path. */ + const char *path_start = path; + + /* If we should, skip the mount name. */ + if (has_mount_name) { + R_TRY(SkipMountName(std::addressof(path), path)); + R_UNLESS(IsSeparator(*path), fs::ResultInvalidPathFormat()); + } + + /* If we should, handle unc. */ + bool is_unc_path = false; + if (unc_preserved) { + path_start = path; + + /* Skip the windows path. */ + bool normalized_windows = false; + R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(normalized_windows), path, has_mount_name)); + + /* If we're not windows-normalized, we're not normalized. */ + if (!normalized_windows) { + *out = false; + return ResultSuccess(); + } + + /* Handle the case where we're dealing with a unc path. */ + if (path != path_start) { + is_unc_path = true; + if (IsSeparator(path_start[0]) && IsSeparator(path_start[1])) { + *out = false; + return ResultSuccess(); + } + + if (IsNullTerminator(path[0])) { + *out = true; + return ResultSuccess(); + } + } + } + + /* Check if parent directory path replacement is needed. */ + if (IsParentDirectoryPathReplacementNeeded(path)) { + *out = false; + return ResultSuccess(); + } + + /* Nintendo uses a state machine here. */ + enum class PathState { + Start, + Normal, + FirstSeparator, + Separator, + CurrentDir, + ParentDir, + }; + + PathState state = PathState::Start; + for (const char *cur = path; *cur != StringTraits::NullTerminator; ++cur) { + const char c = *cur; + switch (state) { + case PathState::Start: + if (IsSeparator(c)) { + state = PathState::FirstSeparator; + } else { + R_UNLESS(path != path_start, fs::ResultInvalidPathFormat()); + if (c == StringTraits::Dot) { + state = PathState::CurrentDir; + } else { + state = PathState::Normal; + } + } + break; + case PathState::Normal: + if (IsSeparator(c)) { + state = PathState::Separator; + } + break; + case PathState::FirstSeparator: + case PathState::Separator: + if (IsSeparator(c)) { + *out = false; + return ResultSuccess(); + } else if (c == StringTraits::Dot) { + state = PathState::CurrentDir; + } else { + state = PathState::Normal; + } + break; + case PathState::CurrentDir: + if (IsSeparator(c)) { + *out = false; + return ResultSuccess(); + } else if (c == StringTraits::Dot) { + state = PathState::ParentDir; + } else { + state = PathState::Normal; + } + break; + case PathState::ParentDir: + if (IsSeparator(c)) { + *out = false; + return ResultSuccess(); + } else { + state = PathState::Normal; + } + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + switch (state) { + case PathState::Start: + return fs::ResultInvalidPathFormat(); + case PathState::Normal: + *out = true; + break; + case PathState::FirstSeparator: + *out = !is_unc_path; + break; + case PathState::CurrentDir: + case PathState::ParentDir: + case PathState::Separator: + *out = false; + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + return ResultSuccess(); + } + +} diff --git a/libraries/libstratosphere/source/fs/fs_path_tool.cpp b/libraries/libstratosphere/source/fs/fs_path_tool.cpp deleted file mode 100644 index fdd64dbdc..000000000 --- a/libraries/libstratosphere/source/fs/fs_path_tool.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 . - */ -#include - -namespace ams::fs { - - - Result PathTool::Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved) { - /* Paths must start with / */ - R_UNLESS(IsSeparator(src[0]), fs::ResultInvalidPathFormat()); - - bool skip_next_sep = false; - size_t i = 0; - size_t len = 0; - - while (!IsNullTerminator(src[i])) { - if (IsSeparator(src[i])) { - /* Swallow separators. */ - while (IsSeparator(src[++i])) { } - if (IsNullTerminator(src[i])) { - break; - } - - /* Handle skip if needed */ - if (!skip_next_sep) { - if (len + 1 == max_out_size) { - out[len] = StringTraits::NullTerminator; - if (out_len != nullptr) { - *out_len = len; - } - return fs::ResultTooLongPath(); - } - - out[len++] = StringTraits::DirectorySeparator; - - if (unc_preserved && len == 1) { - while (len < i) { - if (len + 1 == max_out_size) { - out[len] = StringTraits::NullTerminator; - if (out_len != nullptr) { - *out_len = len; - } - return fs::ResultTooLongPath(); - } - out[len++] = StringTraits::DirectorySeparator; - } - } - } - skip_next_sep = false; - } - - /* See length of current dir. */ - size_t dir_len = 0; - while (!IsSeparator(src[i+dir_len]) && !IsNullTerminator(src[i+dir_len])) { - dir_len++; - } - - if (IsCurrentDirectory(&src[i])) { - skip_next_sep = true; - } else if (IsParentDirectory(&src[i])) { - AMS_ABORT_UNLESS(IsSeparator(out[0])); - AMS_ABORT_UNLESS(IsSeparator(out[len - 1])); - R_UNLESS(len != 1, fs::ResultDirectoryUnobtainable()); - - /* Walk up a directory. */ - len -= 2; - while (!IsSeparator(out[len])) { - len--; - } - } else { - /* Copy, possibly truncating. */ - if (len + dir_len + 1 <= max_out_size) { - for (size_t j = 0; j < dir_len; j++) { - out[len++] = src[i+j]; - } - } else { - const size_t copy_len = max_out_size - 1 - len; - for (size_t j = 0; j < copy_len; j++) { - out[len++] = src[i+j]; - } - out[len] = StringTraits::NullTerminator; - if (out_len != nullptr) { - *out_len = len; - } - return fs::ResultTooLongPath(); - } - } - - i += dir_len; - } - - if (skip_next_sep) { - len--; - } - - if (len == 0 && max_out_size) { - out[len++] = StringTraits::DirectorySeparator; - } - - R_UNLESS(max_out_size >= len - 1, fs::ResultTooLongPath()); - - /* Null terminate. */ - out[len] = StringTraits::NullTerminator; - if (out_len != nullptr) { - *out_len = len; - } - - /* Assert normalized. */ - bool normalized = false; - AMS_ABORT_UNLESS(unc_preserved || (R_SUCCEEDED(IsNormalized(&normalized, out)) && normalized)); - - return ResultSuccess(); - } - - Result PathTool::IsNormalized(bool *out, const char *path) { - /* Nintendo uses a state machine here. */ - enum class PathState { - Start, - Normal, - FirstSeparator, - Separator, - CurrentDir, - ParentDir, - WindowsDriveLetter, - }; - - PathState state = PathState::Start; - - for (const char *cur = path; *cur != StringTraits::NullTerminator; cur++) { - const char c = *cur; - switch (state) { - case PathState::Start: - if (IsWindowsDriveCharacter(c)) { - state = PathState::WindowsDriveLetter; - } else if (IsSeparator(c)) { - state = PathState::FirstSeparator; - } else { - return fs::ResultInvalidPathFormat(); - } - break; - case PathState::Normal: - if (IsSeparator(c)) { - state = PathState::Separator; - } - break; - case PathState::FirstSeparator: - case PathState::Separator: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else if (IsDot(c)) { - state = PathState::CurrentDir; - } else { - state = PathState::Normal; - } - break; - case PathState::CurrentDir: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else if (IsDot(c)) { - state = PathState::ParentDir; - } else { - state = PathState::Normal; - } - break; - case PathState::ParentDir: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else { - state = PathState::Normal; - } - break; - case PathState::WindowsDriveLetter: - if (IsDriveSeparator(c)) { - *out = true; - return ResultSuccess(); - } else { - return fs::ResultInvalidPathFormat(); - } - break; - } - } - - switch (state) { - case PathState::Start: - case PathState::WindowsDriveLetter: - return fs::ResultInvalidPathFormat(); - case PathState::FirstSeparator: - case PathState::Normal: - *out = true; - break; - case PathState::CurrentDir: - case PathState::ParentDir: - case PathState::Separator: - *out = false; - break; - AMS_UNREACHABLE_DEFAULT_CASE(); - } - - return ResultSuccess(); - } - - bool PathTool::IsSubPath(const char *lhs, const char *rhs) { - AMS_ABORT_UNLESS(lhs != nullptr); - AMS_ABORT_UNLESS(rhs != nullptr); - - /* Special case certain paths. */ - if (IsSeparator(lhs[0]) && !IsSeparator(lhs[1]) && IsSeparator(rhs[0]) && IsSeparator(rhs[1])) { - return false; - } - if (IsSeparator(rhs[0]) && !IsSeparator(rhs[1]) && IsSeparator(lhs[0]) && IsSeparator(lhs[1])) { - return false; - } - if (IsSeparator(lhs[0]) && IsNullTerminator(lhs[1]) && IsSeparator(rhs[0]) && !IsNullTerminator(rhs[1])) { - return true; - } - if (IsSeparator(rhs[0]) && IsNullTerminator(rhs[1]) && IsSeparator(lhs[0]) && !IsNullTerminator(lhs[1])) { - return true; - } - - /* Check subpath. */ - for (size_t i = 0; /* No terminating condition */; i++) { - if (IsNullTerminator(lhs[i])) { - return IsSeparator(rhs[i]); - } else if (IsNullTerminator(rhs[i])) { - return IsSeparator(lhs[i]); - } else if (lhs[i] != rhs[i]) { - return false; - } - } - } - -} diff --git a/libraries/libstratosphere/source/fs/fs_path_utils.cpp b/libraries/libstratosphere/source/fs/fs_path_utils.cpp index db15d5b8f..8239e713c 100644 --- a/libraries/libstratosphere/source/fs/fs_path_utils.cpp +++ b/libraries/libstratosphere/source/fs/fs_path_utils.cpp @@ -17,31 +17,114 @@ namespace ams::fs { - Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len) { - const char *cur = path; - size_t name_len = 0; + namespace { - for (size_t path_len = 0; path_len <= max_path_len && name_len <= max_name_len; path_len++) { - const char c = *(cur++); + class PathVerifier { + private: + u32 invalid_chars[6]; + u32 separators[2]; + public: + PathVerifier() { + /* Convert all invalid characters. */ + u32 *dst_invalid = this->invalid_chars; + for (const char *cur = ":*?<>|"; *cur != '\x00'; ++cur) { + AMS_ASSERT(dst_invalid < std::end(this->invalid_chars)); + const auto result = util::ConvertCharacterUtf8ToUtf32(dst_invalid, cur); + AMS_ASSERT(result == util::CharacterEncodingResult_Success); + ++dst_invalid; + } + AMS_ASSERT(dst_invalid == std::end(this->invalid_chars)); - /* If terminated, we're done. */ - R_SUCCEED_IF(PathTool::IsNullTerminator(c)); + /* Convert all separators. */ + u32 *dst_sep = this->separators; + for (const char *cur = "/\\"; *cur != '\x00'; ++cur) { + AMS_ASSERT(dst_sep < std::end(this->separators)); + const auto result = util::ConvertCharacterUtf8ToUtf32(dst_sep, cur); + AMS_ASSERT(result == util::CharacterEncodingResult_Success); + ++dst_sep; + } + AMS_ASSERT(dst_sep == std::end(this->separators)); + } - /* TODO: Nintendo converts the path from utf-8 to utf-32, one character at a time. */ - /* We should do this. */ + Result Verify(const char *path, int max_path_len, int max_name_len) const { + AMS_ASSERT(path != nullptr); - /* Banned characters: :*?<>| */ - R_UNLESS((c != ':' && c != '*' && c != '?' && c != '<' && c != '>' && c != '|'), fs::ResultInvalidCharacter()); + auto cur = path; + auto name_len = 0; - name_len++; - /* Check for separator. */ - if (c == '\\' || c == '/') { - name_len = 0; - } + for (auto path_len = 0; path_len <= max_path_len && name_len <= max_name_len; ++path_len) { + /* We're done, if the path is terminated. */ + R_SUCCEED_IF(*cur == '\x00'); + /* Get the current utf-8 character. */ + util::CharacterEncodingResult result; + char char_buf[4] = {}; + result = util::PickOutCharacterFromUtf8String(char_buf, std::addressof(cur)); + R_UNLESS(result == util::CharacterEncodingResult_Success, fs::ResultInvalidCharacter()); + + /* Convert the current utf-8 character to utf-32. */ + u32 path_char = 0; + result = util::ConvertCharacterUtf8ToUtf32(std::addressof(path_char), char_buf); + R_UNLESS(result == util::CharacterEncodingResult_Success, fs::ResultInvalidCharacter()); + + /* Check if the character is invalid. */ + for (const auto invalid : this->invalid_chars) { + R_UNLESS(path_char != invalid, fs::ResultInvalidCharacter()); + } + + /* Increment name length. */ + ++name_len; + + /* Check for separator. */ + for (const auto sep : this->separators) { + if (path_char == sep) { + name_len = 0; + break; + } + } + } + + /* The path was too long. */ + return fs::ResultTooLongPath(); + } + }; + + PathVerifier g_path_verifier; + + } + + Result VerifyPath(const char *path, int max_path_len, int max_name_len) { + return g_path_verifier.Verify(path, max_path_len, max_name_len); + } + + bool IsSubPath(const char *lhs, const char *rhs) { + AMS_ASSERT(lhs != nullptr); + AMS_ASSERT(rhs != nullptr); + + /* Special case certain paths. */ + if (IsUnc(lhs) && !IsUnc(rhs)) { + return false; + } + if (!IsUnc(lhs) && IsUnc(rhs)) { + return false; + } + if (PathNormalizer::IsSeparator(lhs[0]) && PathNormalizer::IsNullTerminator(lhs[1]) && PathNormalizer::IsSeparator(rhs[0]) && !PathNormalizer::IsNullTerminator(rhs[1])) { + return true; + } + if (PathNormalizer::IsSeparator(rhs[0]) && PathNormalizer::IsNullTerminator(rhs[1]) && PathNormalizer::IsSeparator(lhs[0]) && !PathNormalizer::IsNullTerminator(lhs[1])) { + return true; } - return fs::ResultTooLongPath(); + /* Check subpath. */ + for (size_t i = 0; /* No terminating condition */; i++) { + if (PathNormalizer::IsNullTerminator(lhs[i])) { + return PathNormalizer::IsSeparator(rhs[i]); + } else if (PathNormalizer::IsNullTerminator(rhs[i])) { + return PathNormalizer::IsSeparator(lhs[i]); + } else if (lhs[i] != rhs[i]) { + return false; + } + } } } diff --git a/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp b/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp index 79c226526..aeb04ee83 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp @@ -24,9 +24,9 @@ namespace ams::fs::impl { const char *FindMountNameDriveSeparator(const char *path) { for (const char *cur = path; cur < path + MountNameLengthMax + 1; cur++) { - if (PathTool::IsDriveSeparator(*cur)) { + if (*cur == StringTraits::DriveSeparator) { return cur; - } else if (PathTool::IsNullTerminator(*cur)) { + } else if (PathNormalizer::IsNullTerminator(*cur)) { break; } } @@ -35,7 +35,7 @@ namespace ams::fs::impl { Result GetMountNameAndSubPath(MountName *out_mount_name, const char **out_sub_path, const char *path) { /* Handle the Host-path case. */ - if (PathTool::IsWindowsAbsolutePath(path) || PathTool::IsUnc(path)) { + if (fs::IsWindowsDrive(path) || fs::IsUnc(path)) { std::strncpy(out_mount_name->str, HostRootFileSystemMountName, MountNameLengthMax); out_mount_name->str[MountNameLengthMax] = '\x00'; return ResultSuccess(); @@ -51,8 +51,8 @@ namespace ams::fs::impl { /* Ensure the result sub-path is valid. */ const char *sub_path = drive_separator + 1; - R_UNLESS(!PathTool::IsNullTerminator(sub_path[0]), fs::ResultInvalidMountName()); - R_UNLESS(PathTool::IsAnySeparator(sub_path[0]), fs::ResultInvalidPathFormat()); + R_UNLESS(!PathNormalizer::IsNullTerminator(sub_path[0]), fs::ResultInvalidMountName()); + R_UNLESS(PathNormalizer::IsAnySeparator(sub_path[0]), fs::ResultInvalidPathFormat()); /* Set output. */ std::memcpy(out_mount_name->str, path, len); @@ -64,17 +64,17 @@ namespace ams::fs::impl { } bool IsValidMountName(const char *name) { - if (PathTool::IsNullTerminator(*name)) { + if (PathNormalizer::IsNullTerminator(name[0])) { return false; } - if (PathTool::IsWindowsDriveCharacter(name[0]) && PathTool::IsNullTerminator(name[1])) { + if ((('a' <= name[0] && name[0] <= 'z') || ('A' <= name[0] && name[0] <= 'Z')) && PathNormalizer::IsNullTerminator(name[1])) { return false; } size_t len = 0; - for (const char *cur = name; !PathTool::IsNullTerminator(*cur); cur++) { - if (PathTool::IsDriveSeparator(*cur) || PathTool::IsSeparator(*cur)) { + for (const char *cur = name; !PathNormalizer::IsNullTerminator(*cur); cur++) { + if (*cur == StringTraits::DriveSeparator || PathNormalizer::IsSeparator(*cur)) { return false; } @@ -87,10 +87,6 @@ namespace ams::fs::impl { return true; } - bool IsWindowsDrive(const char *name) { - return PathTool::IsWindowsAbsolutePath(name); - } - bool IsReservedMountName(const char *name) { return name[0] == ReservedMountNamePrefixCharacter; } diff --git a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp index 23040e25c..8e612bf02 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp @@ -216,7 +216,7 @@ namespace ams::fssrv::impl { R_UNLESS(old_normalizer.GetPath() != nullptr, old_normalizer.GetResult()); R_UNLESS(new_normalizer.GetPath() != nullptr, new_normalizer.GetResult()); - const bool is_subpath = fssystem::PathTool::IsSubPath(old_normalizer.GetPath(), new_normalizer.GetPath()); + const bool is_subpath = fs::IsSubPath(old_normalizer.GetPath(), new_normalizer.GetPath()); R_UNLESS(!is_subpath, fs::ResultDirectoryNotRenamable()); return this->base_fs->RenameFile(old_normalizer.GetPath(), new_normalizer.GetPath()); diff --git a/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp b/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp index 8b478c656..d58623841 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp @@ -18,51 +18,36 @@ namespace ams::fssrv { Result PathNormalizer::Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name) { + /* Check pre-conditions. */ + AMS_ASSERT(out_path != nullptr); + AMS_ASSERT(out_buf != nullptr); + /* Clear output. */ *out_path = nullptr; *out_buf = Buffer(); - /* Find start of path. */ - const char *path_start = path; - if (has_mount_name) { - while (path_start < path + fs::MountNameLengthMax + 1) { - if (fssystem::PathTool::IsNullTerminator(*path_start)) { - break; - } else if (fssystem::PathTool::IsDriveSeparator(*(path_start++))) { - break; - } - } - R_UNLESS(path < path_start - 1, fs::ResultInvalidPath()); - R_UNLESS(fssystem::PathTool::IsDriveSeparator(*(path_start - 1)), fs::ResultInvalidPath()); - } - /* Check if we're normalized. */ bool normalized = false; - R_TRY(fssystem::PathTool::IsNormalized(&normalized, path_start)); + R_TRY(fs::PathNormalizer::IsNormalized(std::addressof(normalized), path, preserve_unc, has_mount_name)); if (normalized) { /* If we're already normalized, no allocation is needed. */ *out_path = path; } else { /* Allocate a new buffer. */ - auto buffer = std::make_unique(fs::EntryNameLengthMax + 1); + auto buffer = fs::impl::MakeUnique(fs::EntryNameLengthMax + 1); R_UNLESS(buffer != nullptr, fs::ResultAllocationFailureInPathNormalizer()); - /* Copy in mount name. */ - const size_t mount_name_len = path_start - path; - std::memcpy(buffer.get(), path, mount_name_len); - /* Generate normalized path. */ size_t normalized_len = 0; - R_TRY(fssystem::PathTool::Normalize(buffer.get() + mount_name_len, &normalized_len, path_start, fs::EntryNameLengthMax + 1 - mount_name_len, preserve_unc)); + R_TRY(fs::PathNormalizer::Normalize(buffer.get(), std::addressof(normalized_len), path, fs::EntryNameLengthMax + 1, preserve_unc, has_mount_name)); /* Preserve the tail separator, if we should. */ if (preserve_tail_sep) { - if (fssystem::PathTool::IsSeparator(path[strnlen(path, fs::EntryNameLengthMax) - 1])) { - /* Nintendo doesn't actually validate this. */ - R_UNLESS(mount_name_len + normalized_len < fs::EntryNameLengthMax, fs::ResultTooLongPath()); - buffer[mount_name_len + normalized_len] = fssystem::StringTraits::DirectorySeparator; - buffer[mount_name_len + normalized_len + 1] = fssystem::StringTraits::NullTerminator; + if (fs::PathNormalizer::IsSeparator(path[strnlen(path, fs::EntryNameLengthMax) - 1]) && !fs::PathNormalizer::IsSeparator(buffer[normalized_len - 1])) { + AMS_ASSERT(normalized_len < fs::EntryNameLengthMax); + buffer[normalized_len] = fs::StringTraits::DirectorySeparator; + buffer[normalized_len + 1] = fs::StringTraits::NullTerminator; } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp index 45eb64a2e..abbcb899f 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp @@ -35,10 +35,10 @@ namespace ams::fssystem { DirectoryRedirectionFileSystem::~DirectoryRedirectionFileSystem() { if (this->before_dir != nullptr) { - std::free(this->before_dir); + fs::impl::Deallocate(this->before_dir, this->before_dir_len); } if (this->after_dir != nullptr) { - std::free(this->after_dir); + fs::impl::Deallocate(this->after_dir, this->after_dir_len); } } @@ -53,26 +53,26 @@ namespace ams::fssystem { /* Normalize the path. */ char normalized_path[fs::EntryNameLengthMax + 2]; size_t normalized_path_len; - R_TRY(PathTool::Normalize(normalized_path, &normalized_path_len, dir, sizeof(normalized_path), this->IsUncPreserved())); + R_TRY(fs::PathNormalizer::Normalize(normalized_path, &normalized_path_len, dir, sizeof(normalized_path), this->IsUncPreserved(), false)); /* Ensure terminating '/' */ - if (!PathTool::IsSeparator(normalized_path[normalized_path_len - 1])) { - AMS_ABORT_UNLESS(normalized_path_len + 2 <= sizeof(normalized_path)); - normalized_path[normalized_path_len] = StringTraits::DirectorySeparator; - normalized_path[normalized_path_len + 1] = StringTraits::NullTerminator; + if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) { + AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path)); + normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator; + normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator; - normalized_path_len++; + ++normalized_path_len; } /* Allocate new path. */ const size_t size = normalized_path_len + 1; - char *new_dir = static_cast(std::malloc(size)); + char *new_dir = static_cast(fs::impl::Allocate(size)); AMS_ABORT_UNLESS(new_dir != nullptr); /* TODO: custom ResultAllocationFailure? */ /* Copy path in. */ std::memcpy(new_dir, normalized_path, normalized_path_len); - new_dir[normalized_path_len] = StringTraits::NullTerminator; + new_dir[normalized_path_len] = fs::StringTraits::NullTerminator; /* Set output. */ *out = new_dir; @@ -82,20 +82,30 @@ namespace ams::fssystem { Result DirectoryRedirectionFileSystem::Initialize(const char *before, const char *after) { /* Normalize both directories. */ - this->GetNormalizedDirectoryPath(&this->before_dir, &this->before_dir_len, before); - this->GetNormalizedDirectoryPath(&this->after_dir, &this->after_dir_len, after); + this->GetNormalizedDirectoryPath(std::addressof(this->before_dir), std::addressof(this->before_dir_len), before); + this->GetNormalizedDirectoryPath(std::addressof(this->after_dir), std::addressof(this->after_dir_len), after); return ResultSuccess(); } Result DirectoryRedirectionFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) { + /* Check pre-conditions. */ + AMS_ASSERT(relative_path[0] == '/'); + AMS_ASSERT(this->before_dir_len >= 2); + AMS_ASSERT(this->after_dir_len >= 2); + AMS_ASSERT(this->after_dir_len <= out_size); + AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(this->before_dir[this->before_dir_len - 1])); + AMS_ASSERT(fs::PathNormalizer::IsSeparator(this->before_dir[this->before_dir_len - 2])); + AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(this->after_dir[this->after_dir_len - 1])); + AMS_ASSERT(fs::PathNormalizer::IsSeparator(this->after_dir[this->after_dir_len - 2])); + /* Normalize the relative path. */ char normalized_rel_path[fs::EntryNameLengthMax + 1]; size_t normalized_rel_path_len; - R_TRY(PathTool::Normalize(normalized_rel_path, &normalized_rel_path_len, relative_path, sizeof(normalized_rel_path), this->IsUncPreserved())); + R_TRY(fs::PathNormalizer::Normalize(normalized_rel_path, std::addressof(normalized_rel_path_len), relative_path, sizeof(normalized_rel_path), this->IsUncPreserved(), false)); const bool is_prefixed = std::memcmp(normalized_rel_path, this->before_dir, this->before_dir_len - 2) == 0 && - (PathTool::IsSeparator(normalized_rel_path[this->before_dir_len - 2]) || PathTool::IsNullTerminator(normalized_rel_path[this->before_dir_len - 2])); + (fs::PathNormalizer::IsSeparator(normalized_rel_path[this->before_dir_len - 2]) || fs::PathNormalizer::IsNullTerminator(normalized_rel_path[this->before_dir_len - 2])); if (is_prefixed) { const size_t before_prefix_len = this->before_dir_len - 2; const size_t after_prefix_len = this->after_dir_len - 2; @@ -105,12 +115,12 @@ namespace ams::fssystem { /* Copy normalized path. */ std::memcpy(out, this->after_dir, after_prefix_len); std::memcpy(out + after_prefix_len, normalized_rel_path + before_prefix_len, normalized_rel_path_len - before_prefix_len); - out[final_str_len] = StringTraits::NullTerminator; + out[final_str_len] = fs::StringTraits::NullTerminator; } else { /* Path is not prefixed. */ R_UNLESS(normalized_rel_path_len + 1 <= out_size, fs::ResultTooLongPath()); std::memcpy(out, normalized_rel_path, normalized_rel_path_len); - out[normalized_rel_path_len] = StringTraits::NullTerminator; + out[normalized_rel_path_len] = fs::StringTraits::NullTerminator; } return ResultSuccess(); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp index ebc1b1e54..8f60adee9 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp @@ -156,16 +156,16 @@ namespace ams::fssystem { Result DirectorySaveDataFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) { R_UNLESS(strnlen(relative_path, fs::EntryNameLengthMax + 1) < fs::EntryNameLengthMax + 1, fs::ResultTooLongPath()); - R_UNLESS(PathTool::IsSeparator(relative_path[0]), fs::ResultInvalidPath()); + R_UNLESS(fs::PathNormalizer::IsSeparator(relative_path[0]), fs::ResultInvalidPath()); /* Copy working directory path. */ std::strncpy(out, WorkingDirectoryPath, out_size); - out[out_size - 1] = StringTraits::NullTerminator; + out[out_size - 1] = fs::StringTraits::NullTerminator; /* Normalize it. */ constexpr size_t WorkingDirectoryPathLength = sizeof(WorkingDirectoryPath) - 1; size_t normalized_length; - return PathTool::Normalize(out + WorkingDirectoryPathLength - 1, &normalized_length, relative_path, out_size - (WorkingDirectoryPathLength - 1)); + return fs::PathNormalizer::Normalize(out + WorkingDirectoryPathLength - 1, &normalized_length, relative_path, out_size - (WorkingDirectoryPathLength - 1)); } void DirectorySaveDataFileSystem::OnWritableFileClose() { @@ -186,7 +186,7 @@ namespace ams::fssystem { R_TRY(this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBufferSize)); /* Copy the directory recursively. */ - R_TRY(fssystem::CopyDirectoryRecursively(this->base_fs, save_fs, PathTool::RootPath, PathTool::RootPath, work_buf.get(), work_buf_size)); + R_TRY(fssystem::CopyDirectoryRecursively(this->base_fs, save_fs, fs::PathNormalizer::RootPath, fs::PathNormalizer::RootPath, work_buf.get(), work_buf_size)); return this->Commit(); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp index add60023d..7802e59e8 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp @@ -241,7 +241,7 @@ namespace ams::fssystem { dir_entry.type = fs::DirectoryEntryType_File; dir_entry.file_size = this->parent->meta_data->GetEntry(this->cur_index)->size; std::strncpy(dir_entry.name, this->parent->meta_data->GetEntryName(this->cur_index), sizeof(dir_entry.name) - 1); - dir_entry.name[sizeof(dir_entry.name) - 1] = StringTraits::NullTerminator; + dir_entry.name[sizeof(dir_entry.name) - 1] = fs::StringTraits::NullTerminator; } *out_count = entry_count; @@ -349,11 +349,11 @@ namespace ams::fssystem { template Result PartitionFileSystemCore::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { /* Validate preconditions. */ - R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); - R_UNLESS(PathTool::IsSeparator(path[0]), fs::ResultInvalidPathFormat()); + R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); + R_UNLESS(fs::PathNormalizer::IsSeparator(path[0]), fs::ResultInvalidPathFormat()); /* Check if the path is for a directory. */ - if (std::strncmp(path, PathTool::RootPath, sizeof(PathTool::RootPath)) == 0) { + if (std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0) { *out = fs::DirectoryEntryType_Directory; return ResultSuccess(); } @@ -384,8 +384,8 @@ namespace ams::fssystem { template Result PartitionFileSystemCore::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { /* Validate preconditions. */ - R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); - R_UNLESS(std::strncmp(path, PathTool::RootPath, sizeof(PathTool::RootPath)) == 0, fs::ResultPathNotFound()); + R_UNLESS(this->initialized, fs::ResultPreconditionViolation()); + R_UNLESS(std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0, fs::ResultPathNotFound()); /* Create and output the partition directory. */ std::unique_ptr directory = std::make_unique(this, mode); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp index 7ea7f723d..19fc51019 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp @@ -33,7 +33,7 @@ namespace ams::fssystem { SubDirectoryFileSystem::~SubDirectoryFileSystem() { if (this->base_path != nullptr) { - std::free(this->base_path); + fs::impl::Deallocate(this->base_path, this->base_path_len); } } @@ -44,25 +44,25 @@ namespace ams::fssystem { /* Normalize the path. */ char normalized_path[fs::EntryNameLengthMax + 2]; size_t normalized_path_len; - R_TRY(PathTool::Normalize(normalized_path, &normalized_path_len, bp, sizeof(normalized_path), this->IsUncPreserved())); + R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), bp, sizeof(normalized_path), this->IsUncPreserved())); /* Ensure terminating '/' */ - if (!PathTool::IsSeparator(normalized_path[normalized_path_len - 1])) { - AMS_ABORT_UNLESS(normalized_path_len + 2 <= sizeof(normalized_path)); - normalized_path[normalized_path_len] = StringTraits::DirectorySeparator; - normalized_path[normalized_path_len + 1] = StringTraits::NullTerminator; + if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) { + AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path)); + normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator; + normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator; - normalized_path_len++; + ++normalized_path_len; } /* Allocate new path. */ this->base_path_len = normalized_path_len + 1; - this->base_path = static_cast(std::malloc(this->base_path_len)); + this->base_path = static_cast(fs::impl::Allocate(this->base_path_len)); R_UNLESS(this->base_path != nullptr, fs::ResultAllocationFailureInSubDirectoryFileSystem()); /* Copy path in. */ std::memcpy(this->base_path, normalized_path, normalized_path_len); - this->base_path[normalized_path_len] = StringTraits::NullTerminator; + this->base_path[normalized_path_len] = fs::StringTraits::NullTerminator; return ResultSuccess(); } @@ -76,7 +76,7 @@ namespace ams::fssystem { /* Normalize it. */ const size_t prefix_size = this->base_path_len - 2; size_t normalized_len; - return PathTool::Normalize(out + prefix_size, &normalized_len, relative_path, out_size - prefix_size, this->IsUncPreserved()); + return fs::PathNormalizer::Normalize(out + prefix_size, std::addressof(normalized_len), relative_path, out_size - prefix_size, this->IsUncPreserved(), false); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp b/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp index 02783fc2a..760f3c25b 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp @@ -31,15 +31,15 @@ namespace ams::fssystem { /* Normalize the path. */ char normalized_path[fs::EntryNameLengthMax + 1]; size_t normalized_path_len; - R_TRY(PathTool::Normalize(normalized_path, &normalized_path_len, path, sizeof(normalized_path))); + R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), path, sizeof(normalized_path))); /* Repeatedly call CreateDirectory on each directory leading to the target. */ for (size_t i = 1; i < normalized_path_len; i++) { /* If we detect a separator, create the directory. */ - if (PathTool::IsSeparator(normalized_path[i])) { - normalized_path[i] = StringTraits::NullTerminator; + if (fs::PathNormalizer::IsSeparator(normalized_path[i])) { + normalized_path[i] = fs::StringTraits::NullTerminator; R_TRY(EnsureDirectory(fs, normalized_path)); - normalized_path[i] = StringTraits::DirectorySeparator; + normalized_path[i] = fs::StringTraits::DirectorySeparator; } } @@ -120,10 +120,10 @@ namespace ams::fssystem { /* Find previous separator, add null terminator */ char *cur = &dst_path_buf[len - 2]; - while (!PathTool::IsSeparator(*cur) && cur > dst_path_buf) { + while (!fs::PathNormalizer::IsSeparator(*cur) && cur > dst_path_buf) { cur--; } - cur[1] = StringTraits::NullTerminator; + cur[1] = fs::StringTraits::NullTerminator; return ResultSuccess(); }, diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index 2fae1e4fe..cac157fb2 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -40,5 +40,6 @@ #include #include #include +#include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp b/libraries/libvapours/include/vapours/util/util_character_encoding.hpp similarity index 58% rename from libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp rename to libraries/libvapours/include/vapours/util/util_character_encoding.hpp index b16d8ebc4..635b3e682 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp +++ b/libraries/libvapours/include/vapours/util/util_character_encoding.hpp @@ -13,14 +13,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #pragma once -#include "../fs/fs_common.hpp" -#include "../fs/fs_path_tool.hpp" +#include +#include -namespace ams::fssystem { +namespace ams::util { - namespace StringTraits = ::ams::fs::StringTraits; + enum CharacterEncodingResult { + CharacterEncodingResult_Success = 0, + CharacterEncodingResult_InsufficientLength = 1, + CharacterEncodingResult_InvalidFormat = 2, + }; - using PathTool = ::ams::fs::PathTool; + CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32 *dst, const char *src); + + CharacterEncodingResult PickOutCharacterFromUtf8String(char *dst, const char **str); } diff --git a/libraries/libvapours/source/util/util_character_encoding.cpp b/libraries/libvapours/source/util/util_character_encoding.cpp new file mode 100644 index 000000000..fb9f6b80b --- /dev/null +++ b/libraries/libvapours/source/util/util_character_encoding.cpp @@ -0,0 +1,154 @@ +/* + * 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 . + */ +#include + +namespace ams::util { + + namespace { + + constexpr inline int8_t Utf8NBytesInnerTable[0x100 + 1] = { + -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, + }; + + constexpr inline const char * const Utf8NBytesTable = static_cast(static_cast(Utf8NBytesInnerTable + 1)); + + } + + CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32 *dst, const char *src) { + /* Check pre-conditions. */ + AMS_ASSERT(dst != nullptr); + AMS_ASSERT(src != nullptr); + + /* Perform the conversion. */ + const unsigned char *p = reinterpret_cast(src); + switch (Utf8NBytesTable[p[0]]) { + case 1: + *dst = static_cast(p[0]); + return CharacterEncodingResult_Success; + case 2: + if ((p[0] & 0x1E) != 0) { + if (Utf8NBytesTable[p[1]] == 0) { + *dst = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); + return CharacterEncodingResult_Success; + } + } + break; + case 3: + if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0) { + const u32 c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0 && Utf8NBytesTable[p[3]] == 0) { + const u32 c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + break; + } + + /* We failed to convert. */ + return CharacterEncodingResult_InvalidFormat; + } + + CharacterEncodingResult PickOutCharacterFromUtf8String(char *dst, const char **str) { + /* Check pre-conditions. */ + AMS_ASSERT(dst != nullptr); + AMS_ASSERT(str != nullptr); + AMS_ASSERT(*str != nullptr); + + /* Clear the output. */ + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + + /* Perform the conversion. */ + const unsigned char *p = reinterpret_cast(*str); + u32 c = *p; + switch (Utf8NBytesTable[c]) { + case 1: + dst[0] = (*str)[0]; + ++(*str); + break; + case 2: + if ((p[0] & 0x1E) != 0) { + if (Utf8NBytesTable[p[1]] == 0) { + c = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + (*str) += 2; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 3: + if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0) { + c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + (*str) += 3; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0 && Utf8NBytesTable[p[3]] == 0) { + c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + dst[3] = (*str)[3]; + (*str) += 4; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + return CharacterEncodingResult_InvalidFormat; + } + + return CharacterEncodingResult_Success; + } + +} From 9ca1d3a7f71243fe85f6a4d22a841739fb565275 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 6 Dec 2020 21:20:42 -0800 Subject: [PATCH 08/29] loader: fix process handle management on create process error --- stratosphere/loader/source/ldr_process_creation.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 2ca46a53d..844e19651 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -464,13 +464,18 @@ namespace ams::ldr { Result CreateProcessImpl(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info, u32 flags, Handle reslimit_h) { /* Get CreateProcessParameter. */ svc::CreateProcessParameter param; - R_TRY(GetCreateProcessParameter(¶m, meta, flags, reslimit_h)); + R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, reslimit_h)); /* Decide on an NSO layout. */ - R_TRY(DecideAddressSpaceLayout(out, ¶m, nso_headers, has_nso, arg_info)); + R_TRY(DecideAddressSpaceLayout(out, std::addressof(param), nso_headers, has_nso, arg_info)); - /* Actually create process. const_cast necessary because libnx doesn't declare svcCreateProcess with const u32*. */ - return svcCreateProcess(out->process_handle.GetPointer(), ¶m, reinterpret_cast(meta->aci_kac), meta->aci->kac_size / sizeof(u32)); + /* Actually create process. */ + Handle process_handle; + R_TRY(svc::CreateProcess(std::addressof(process_handle), std::addressof(param), static_cast(meta->aci_kac), meta->aci->kac_size / sizeof(u32))); + + /* Set the output handle. */ + *out->process_handle.GetPointer() = process_handle; + return ResultSuccess(); } Result LoadNsoSegment(fs::FileHandle file, const NsoHeader::SegmentInfo *segment, size_t file_size, const u8 *file_hash, bool is_compressed, bool check_hash, uintptr_t map_base, uintptr_t map_end) { From 15396dbbc22e117622e6b558a7b8cca54853c6b3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 01:03:39 -0800 Subject: [PATCH 09/29] fs: add ProgramIndexMapInfo --- .../include/stratosphere/fs.hpp | 1 + .../fs/fs_program_index_map_info.hpp | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index c6b5bc537..4428ac11c 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -59,4 +59,5 @@ #include #include #include +#include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp new file mode 100644 index 000000000..5e67cd27b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp @@ -0,0 +1,30 @@ +/* + * 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::fs { + + struct ProgramIndexMapInfo { + ncm::ProgramId program_id; + ncm::ProgramId base_program_id; + u8 program_index; + u8 pad[0xF]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(ProgramIndexMapInfo) == 0x20); + +} From 121c981bb4256045aa8fd7c17a754e1057ae1b65 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 03:20:01 -0800 Subject: [PATCH 10/29] sept: be more forgiving about entrypoint --- sept/sept-primary/src/start.s | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sept/sept-primary/src/start.s b/sept/sept-primary/src/start.s index 3a525a9de..b5cb1c1e8 100644 --- a/sept/sept-primary/src/start.s +++ b/sept/sept-primary/src/start.s @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + .section .text.start, "ax", %progbits .arm .align 5 @@ -24,34 +24,34 @@ _start: mov r0, #0x0 ldr r1, =0x7000E400 str r0, [r1, #0x50] - + /* Tell pk1ldr normal reboot, no error */ str r0, [r1, #0x1B4] str r0, [r1, #0x840] - + /* Cleanup SVC handler address. */ ldr r0, =0x40004C30 ldr r1, =0x6000F208 str r0, [r1] - + /* Disable RCM forcefully */ mov r0, #0x4 ldr r1, =0x15DC ldr r2, =0xE020 bl ipatch_word - + /* Patch BCT signature check */ mov r0, #0x5 ldr r1, =0x4AEE ldr r2, =0xE05B bl ipatch_word - + /* Patch bootloader read */ mov r0, #0x6 ldr r1, =0x4E88 ldr r2, =0xE018 bl ipatch_word - + ldr r0, =__main_phys_start__ ldr r1, =__main_start__ mov r2, #0x0 @@ -62,17 +62,17 @@ _start: add r2, r2, #0x4 cmp r2, r3 bne copy_panic_payload - - + + /* Jump back to bootrom start. */ ldr r0, =0x101010 bx r0 - + /* Unused, but forces inclusion in binary. */ b main - - + + .section .text.ipatch_word, "ax", %progbits .arm .align 5 @@ -86,15 +86,15 @@ ipatch_word: orr r1, r1, r2 str r1, [r3, r0] bx lr - + .section .text.jump_to_main, "ax", %progbits .arm .align 5 .global jump_to_main .type jump_to_main, %function jump_to_main: - /* Insert 0x40 of NOPs, for version compatibility. */ -.rept 16 + /* Insert 0x240 of NOPs, for version compatibility. */ +.rept (0x240/4) nop .endr /* Just jump to main */ From 2de85c633adc530421031d51407a498c5282564a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 19:25:06 -0800 Subject: [PATCH 11/29] exo/meso/fusee: support dynamic control of log port/baud rate --- config_templates/exosphere.ini | 10 +++ exosphere/program/source/secmon_setup.cpp | 2 +- .../program/source/smc/secmon_smc_info.cpp | 4 ++ .../program/source/smc/secmon_smc_info.hpp | 19 ++--- .../smc/secmon_smc_power_management.cpp | 1 + fusee/fusee-secondary/src/exocfg.h | 12 +++- fusee/fusee-secondary/src/nxboot.c | 19 +++++ .../libexosphere/include/exosphere/log.hpp | 1 + ...ecmon_configuration_context.arch.arm64.hpp | 8 +++ .../secmon/secmon_monitor_context.hpp | 20 ++++-- libraries/libexosphere/source/log/log_api.cpp | 69 +++++++++--------- .../nintendo/nx/kern_k_system_control.hpp | 1 + .../include/mesosphere/kern_debug_log.hpp | 2 +- .../nintendo/nx/kern_k_system_control.cpp | 9 +++ .../board/nintendo/nx/kern_secure_monitor.hpp | 19 ++--- .../kern_debug_log_impl.board.nintendo_nx.cpp | 70 ++++++++++--------- ...kern_k_memory_layout.board.nintendo_nx.cpp | 16 ++--- 17 files changed, 183 insertions(+), 99 deletions(-) diff --git a/config_templates/exosphere.ini b/config_templates/exosphere.ini index dc7b3fde8..b60a3f31c 100644 --- a/config_templates/exosphere.ini +++ b/config_templates/exosphere.ini @@ -35,6 +35,14 @@ # mmc space, encrypted to prevent detection. This backup can be used # to prevent unrecoverable edits in emergencies. +# Key: log_port, default: 0. +# Desc: Controls what uart port exosphere will set up for logging. +# NOTE: 0 = UART-A, 1 = UART-B, 2 = UART-C, 3 = UART-D + +# Key: log_baud_rate, default: 115200 +# Desc: Controls the baud rate exosphere will set up for logging. +# NOTE: 0 is treated as equivalent to 115200. + [exosphere] debugmode=1 debugmode_user=0 @@ -43,3 +51,5 @@ enable_user_pmu_access=0 blank_prodinfo_sysmmc=0 blank_prodinfo_emummc=0 allow_writing_to_cal_sysmmc=0 +log_port=0 +log_baud_rate=115200 diff --git a/exosphere/program/source/secmon_setup.cpp b/exosphere/program/source/secmon_setup.cpp index bf47eec7d..836786252 100644 --- a/exosphere/program/source/secmon_setup.cpp +++ b/exosphere/program/source/secmon_setup.cpp @@ -960,7 +960,7 @@ namespace ams::secmon { } void SetupLogForBoot() { - log::Initialize(); + log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate()); log::SendText("OHAYO\n", 6); log::Flush(); } diff --git a/exosphere/program/source/smc/secmon_smc_info.cpp b/exosphere/program/source/smc/secmon_smc_info.cpp index 9c1e5ae20..e7b52edcc 100644 --- a/exosphere/program/source/smc/secmon_smc_info.cpp +++ b/exosphere/program/source/smc/secmon_smc_info.cpp @@ -282,6 +282,10 @@ namespace ams::secmon::smc { return SmcResult::NotInitialized; } break; + case ConfigItem::ExosphereLogConfiguration: + /* Get the log configuration. */ + args.r[1] = (static_cast(static_cast(secmon::GetLogPort())) << 32) | static_cast(secmon::GetLogBaudRate()); + break; default: return SmcResult::InvalidArgument; } diff --git a/exosphere/program/source/smc/secmon_smc_info.hpp b/exosphere/program/source/smc/secmon_smc_info.hpp index 7f33cbdba..12870324e 100644 --- a/exosphere/program/source/smc/secmon_smc_info.hpp +++ b/exosphere/program/source/smc/secmon_smc_info.hpp @@ -40,15 +40,16 @@ namespace ams::secmon::smc { Package2Hash = 17, /* Extension config items for exosphere. */ - ExosphereApiVersion = 65000, - ExosphereNeedsReboot = 65001, - ExosphereNeedsShutdown = 65002, - ExosphereGitCommitHash = 65003, - ExosphereHasRcmBugPatch = 65004, - ExosphereBlankProdInfo = 65005, - ExosphereAllowCalWrites = 65006, - ExosphereEmummcType = 65007, - ExospherePayloadAddress = 65008, + ExosphereApiVersion = 65000, + ExosphereNeedsReboot = 65001, + ExosphereNeedsShutdown = 65002, + ExosphereGitCommitHash = 65003, + ExosphereHasRcmBugPatch = 65004, + ExosphereBlankProdInfo = 65005, + ExosphereAllowCalWrites = 65006, + ExosphereEmummcType = 65007, + ExospherePayloadAddress = 65008, + ExosphereLogConfiguration = 65009, }; SmcResult SmcGetConfigUser(SmcArguments &args); diff --git a/exosphere/program/source/smc/secmon_smc_power_management.cpp b/exosphere/program/source/smc/secmon_smc_power_management.cpp index 7ed5f3377..6de49c6c8 100644 --- a/exosphere/program/source/smc/secmon_smc_power_management.cpp +++ b/exosphere/program/source/smc/secmon_smc_power_management.cpp @@ -409,6 +409,7 @@ namespace ams::secmon::smc { /* NOTE: Nintendo only does this on dev, but we will always do it. */ if (true /* !pkg1::IsProduction() */) { log::SendText("OYASUMI\n", 8); + log::Flush(); } /* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */ diff --git a/fusee/fusee-secondary/src/exocfg.h b/fusee/fusee-secondary/src/exocfg.h index 933ffad49..7aac28bb5 100644 --- a/fusee/fusee-secondary/src/exocfg.h +++ b/fusee/fusee-secondary/src/exocfg.h @@ -37,8 +37,12 @@ typedef struct { uint32_t magic; uint32_t target_firmware; - uint32_t flags; - uint32_t reserved[5]; + uint32_t flags[2]; + uint16_t lcd_vendor; + uint8_t reserved0; + uint8_t log_port; + uint32_t log_baud_rate; + uint32_t reserved1[2]; exo_emummc_config_t emummc_cfg; } exosphere_config_t; @@ -54,6 +58,8 @@ _Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), #define EXOSPHERE_BLANK_PRODINFO_SYSMMC_KEY "blank_prodinfo_sysmmc" #define EXOSPHERE_BLANK_PRODINFO_EMUMMC_KEY "blank_prodinfo_emummc" #define EXOSPHERE_ALLOW_WRITING_TO_CAL_SYSMMC_KEY "allow_writing_to_cal_sysmmc" +#define EXOSPHERE_LOG_PORT_KEY "log_port" +#define EXOSPHERE_LOG_BAUD_RATE_KEY "log_baud_rate" typedef struct { int debugmode; @@ -63,6 +69,8 @@ typedef struct { int blank_prodinfo_sysmmc; int blank_prodinfo_emummc; int allow_writing_to_cal_sysmmc; + int log_port; + int log_baud_rate; } exosphere_parse_cfg_t; #endif diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index d1a329c2d..e797ac01b 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -196,6 +196,20 @@ static int exosphere_ini_handler(void *user, const char *section, const char *na } else if (tmp == 0) { parse_cfg->allow_writing_to_cal_sysmmc = 0; } + } else if (strcmp(name, EXOSPHERE_LOG_PORT_KEY) == 0) { + sscanf(value, "%d", &tmp); + if (0 <= tmp && tmp < 4) { + parse_cfg->log_port = tmp; + } else { + parse_cfg->log_port = 0; + } + } else if (strcmp(name, EXOSPHERE_LOG_BAUD_RATE_KEY) == 0) { + sscanf(value, "%d", &tmp); + if (tmp > 0) { + parse_cfg->log_baud_rate = tmp; + } else { + parse_cfg->log_baud_rate = 115200; + } } else { return 0; } @@ -478,6 +492,8 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke .blank_prodinfo_sysmmc = 0, .blank_prodinfo_emummc = 0, .allow_writing_to_cal_sysmmc = 0, + .log_port = 0, + .log_baud_rate = 115200, }; /* If we have an ini to read, parse it. */ @@ -498,6 +514,9 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke if (parse_cfg.blank_prodinfo_emummc && is_emummc) exo_cfg.flags |= EXOSPHERE_FLAG_BLANK_PRODINFO; if (parse_cfg.allow_writing_to_cal_sysmmc) exo_cfg.flags |= EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC; + exo_cfg.log_port = parse_cfg.log_port; + exo_cfg.log_baud_rate = parse_cfg.log_baud_rate; + if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) { fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n"); } diff --git a/libraries/libexosphere/include/exosphere/log.hpp b/libraries/libexosphere/include/exosphere/log.hpp index 7ddde611d..cecf8d156 100644 --- a/libraries/libexosphere/include/exosphere/log.hpp +++ b/libraries/libexosphere/include/exosphere/log.hpp @@ -35,6 +35,7 @@ namespace ams::log { #endif void Initialize(); + void Initialize(uart::Port port, u32 baud_rate); void Finalize(); void Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp index bddcf1b75..aa231787f 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -116,6 +116,14 @@ namespace ams::secmon { return GetSecmonConfiguration().GetLcdVendor(); } + ALWAYS_INLINE uart::Port GetLogPort() { + return GetSecmonConfiguration().GetLogPort(); + } + + ALWAYS_INLINE u32 GetLogBaudRate() { + return GetSecmonConfiguration().GetLogBaudRate(); + } + ALWAYS_INLINE bool IsProduction() { return GetSecmonConfiguration().IsProduction(); } diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp index c29708018..f53a633d0 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #include namespace ams::secmon { @@ -39,8 +40,10 @@ namespace ams::secmon { ams::TargetFirmware target_firmware; u32 flags[2]; u16 lcd_vendor; - u16 reserved0; - u32 reserved1[3]; + u8 reserved0; + u8 log_port; + u32 log_baud_rate; + u32 reserved1[2]; EmummcConfiguration emummc_cfg; constexpr bool IsValid() const { return this->magic == Magic; } @@ -54,17 +57,20 @@ namespace ams::secmon { u8 hardware_type; u8 soc_type; u8 hardware_state; - u8 pad_0B[1]; + u8 log_port; u32 flags[2]; u16 lcd_vendor; u16 reserved0; - u32 reserved1[(0x80 - 0x18) / sizeof(u32)]; + u32 log_baud_rate; + u32 reserved1[(0x80 - 0x1C) / sizeof(u32)]; constexpr void CopyFrom(const SecureMonitorStorageConfiguration &storage) { this->target_firmware = storage.target_firmware; this->flags[0] = storage.flags[0]; this->flags[1] = storage.flags[1]; this->lcd_vendor = storage.lcd_vendor; + this->log_port = storage.log_port; + this->log_baud_rate = storage.log_baud_rate != 0 ? storage.log_baud_rate : 115200; } void SetFuseInfo() { @@ -78,9 +84,12 @@ namespace ams::secmon { constexpr fuse::HardwareType GetHardwareType() const { return static_cast(this->hardware_type); } constexpr fuse::SocType GetSocType() const { return static_cast(this->soc_type); } constexpr fuse::HardwareState GetHardwareState() const { return static_cast(this->hardware_state); } + constexpr uart::Port GetLogPort() const { return static_cast(this->log_port); } constexpr u16 GetLcdVendor() const { return this->lcd_vendor; } + constexpr u32 GetLogBaudRate() const { return this->log_baud_rate; } + constexpr bool IsProduction() const { return this->GetHardwareState() != fuse::HardwareState_Development; } constexpr bool IsDevelopmentFunctionEnabledForKernel() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel) != 0; } @@ -101,10 +110,11 @@ namespace ams::secmon { .hardware_type = {}, .soc_type = {}, .hardware_state = {}, - .pad_0B = {}, + .log_port = uart::Port_ReservedDebug, .flags = { SecureMonitorConfigurationFlag_Default, SecureMonitorConfigurationFlag_None }, .lcd_vendor = {}, .reserved0 = {}, + .log_baud_rate = 115200, .reserved1 = {}, }; diff --git a/libraries/libexosphere/source/log/log_api.cpp b/libraries/libexosphere/source/log/log_api.cpp index 068dddc20..5ce2831c2 100644 --- a/libraries/libexosphere/source/log/log_api.cpp +++ b/libraries/libexosphere/source/log/log_api.cpp @@ -19,58 +19,63 @@ namespace ams::log { namespace { - constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug; - constexpr inline int UartBaudRate = 115200; + constexpr inline uart::Port DefaultLogPort = uart::Port_ReservedDebug; + constexpr inline int DefaultBaudRate = 115200; + constinit uart::Port g_log_port = DefaultLogPort; constinit bool g_initialized_uart = false; - constexpr inline u32 UartPortFlags = [] { - if constexpr (UartLogPort == uart::Port_ReservedDebug) { - /* Logging to the debug port. */ - /* Don't invert transactions. */ - return uart::Flag_None; - } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { - /* Logging to left joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { - /* Logging to right joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - } else { - __builtin_unreachable(); + ALWAYS_INLINE u32 GetPortFlags(uart::Port port) { + switch (port) { + case uart::Port_ReservedDebug: + /* Logging to the debug port. */ + /* Don't invert transactions. */ + return uart::Flag_None; + case uart::Port_LeftJoyCon: + /* Logging to left joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + case uart::Port_RightJoyCon: + /* Logging to right joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + AMS_UNREACHABLE_DEFAULT_CASE(); } - }(); + } - ALWAYS_INLINE void SetupUart() { - if constexpr (UartLogPort == uart::Port_ReservedDebug) { - /* Logging to the debug port. */ - pinmux::SetupUartA(); - clkrst::EnableUartAClock(); - } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { + ALWAYS_INLINE void SetupUartClock(uart::Port port) { + /* The debug port must always be set up, for compatibility with official hos. */ + pinmux::SetupUartA(); + clkrst::EnableUartAClock(); + + /* If logging to a joy-con port, configure appropriately. */ + if (port == uart::Port_LeftJoyCon) { /* Logging to left joy-con (e.g. with Joyless). */ static_assert(uart::Port_LeftJoyCon == uart::Port_C); pinmux::SetupUartC(); clkrst::EnableUartCClock(); - } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { + } else if (port == uart::Port_RightJoyCon) { /* Logging to right joy-con (e.g. with Joyless). */ static_assert(uart::Port_RightJoyCon == uart::Port_B); pinmux::SetupUartB(); clkrst::EnableUartBClock(); - } else { - __builtin_unreachable(); } } } void Initialize() { + return Initialize(DefaultLogPort, DefaultBaudRate); + } + + void Initialize(uart::Port port, u32 baud_rate) { /* Initialize pinmux and clock for the target uart port. */ - SetupUart(); + SetupUartClock(port); /* Initialize the target uart port. */ - uart::Initialize(UartLogPort, UartBaudRate, UartPortFlags); + uart::Initialize(port, baud_rate, GetPortFlags(port)); /* Note that we've initialized. */ + g_log_port = port; g_initialized_uart = true; } @@ -84,7 +89,7 @@ namespace ams::log { const auto len = util::TVSNPrintf(log_buf, sizeof(log_buf), fmt, vl); if (g_initialized_uart) { - uart::SendText(UartLogPort, log_buf, len); + uart::SendText(g_log_port, log_buf, len); } } @@ -115,13 +120,13 @@ namespace ams::log { void SendText(const void *text, size_t size) { if (g_initialized_uart) { - uart::SendText(UartLogPort, text, size); + uart::SendText(g_log_port, text, size); } } void Flush() { if (g_initialized_uart) { - uart::WaitFlush(UartLogPort); + uart::WaitFlush(g_log_port); } } diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index c72015d01..f9d99aecf 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -30,6 +30,7 @@ namespace ams::kern::board::nintendo::nx { static size_t GetApplicationPoolSize(); static size_t GetAppletPoolSize(); static size_t GetMinimumNonSecureSystemPoolSize(); + static u8 GetDebugLogUartPort(); /* Randomness. */ static void GenerateRandomBytes(void *dst, size_t size); diff --git a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp index e2cde1342..4f19c19a6 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp @@ -40,7 +40,7 @@ namespace ams::kern { #ifndef MESOSPHERE_DEBUG_LOG_SELECTED #ifdef ATMOSPHERE_BOARD_NINTENDO_NX - #define MESOSPHERE_DEBUG_LOG_USE_UART_A + #define MESOSPHERE_DEBUG_LOG_USE_UART #else #error "Unknown board for Default Debug Log Source" #endif diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index a54bf2c13..df41785d5 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -409,6 +409,15 @@ namespace ams::kern::board::nintendo::nx { return MinimumSize; } + u8 KSystemControl::Init::GetDebugLogUartPort() { + /* Get the log configuration. */ + u64 value = 0; + smc::init::GetConfig(std::addressof(value), 1, smc::ConfigItem::ExosphereLogConfiguration); + + /* Extract the port. */ + return static_cast((value >> 32) & 0xFF); + } + void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { smc::init::CpuOn(core_id, entrypoint, arg); } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp index b7d17072e..22233b78f 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -55,15 +55,16 @@ namespace ams::kern::board::nintendo::nx::smc { Package2Hash = 17, /* Extension config items for exosphere. */ - ExosphereApiVersion = 65000, - ExosphereNeedsReboot = 65001, - ExosphereNeedsShutdown = 65002, - ExosphereGitCommitHash = 65003, - ExosphereHasRcmBugPatch = 65004, - ExosphereBlankProdInfo = 65005, - ExosphereAllowCalWrites = 65006, - ExosphereEmummcType = 65007, - ExospherePayloadAddress = 65008, + ExosphereApiVersion = 65000, + ExosphereNeedsReboot = 65001, + ExosphereNeedsShutdown = 65002, + ExosphereGitCommitHash = 65003, + ExosphereHasRcmBugPatch = 65004, + ExosphereBlankProdInfo = 65005, + ExosphereAllowCalWrites = 65006, + ExosphereEmummcType = 65007, + ExospherePayloadAddress = 65008, + ExosphereLogConfiguration = 65009, }; enum class SmcResult { diff --git a/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp index 470287b9b..9b516e29f 100644 --- a/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp +++ b/libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp @@ -18,10 +18,12 @@ namespace ams::kern { -#if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) +#if defined(MESOSPHERE_DEBUG_LOG_USE_UART) namespace { + constexpr bool DoSaveAndRestore = false; + enum UartRegister { UartRegister_THR = 0, UartRegister_IER = 1, @@ -38,13 +40,13 @@ namespace ams::kern { KVirtualAddress g_uart_address = 0; - constinit u32 g_saved_registers[5]; + [[maybe_unused]] constinit u32 g_saved_registers[5]; - NOINLINE u32 ReadUartRegister(UartRegister which) { + ALWAYS_INLINE u32 ReadUartRegister(UartRegister which) { return GetPointer(g_uart_address)[which]; } - NOINLINE void WriteUartRegister(UartRegister which, u32 value) { + ALWAYS_INLINE void WriteUartRegister(UartRegister which, u32 value) { GetPointer(g_uart_address)[which] = value; } @@ -86,43 +88,47 @@ namespace ams::kern { } void KDebugLogImpl::Save() { - /* Save LCR, IER, FCR. */ - g_saved_registers[0] = ReadUartRegister(UartRegister_LCR); - g_saved_registers[1] = ReadUartRegister(UartRegister_IER); - g_saved_registers[2] = ReadUartRegister(UartRegister_FCR); + if constexpr (DoSaveAndRestore) { + /* Save LCR, IER, FCR. */ + g_saved_registers[0] = ReadUartRegister(UartRegister_LCR); + g_saved_registers[1] = ReadUartRegister(UartRegister_IER); + g_saved_registers[2] = ReadUartRegister(UartRegister_FCR); - /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ - WriteUartRegister(UartRegister_LCR, 0x80); - ReadUartRegister(UartRegister_LCR); + /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ + WriteUartRegister(UartRegister_LCR, 0x80); + ReadUartRegister(UartRegister_LCR); - /* Save DLL/DLH. */ - g_saved_registers[3] = ReadUartRegister(UartRegister_DLL); - g_saved_registers[4] = ReadUartRegister(UartRegister_DLH); + /* Save DLL/DLH. */ + g_saved_registers[3] = ReadUartRegister(UartRegister_DLL); + g_saved_registers[4] = ReadUartRegister(UartRegister_DLH); - /* Restore Divisor Latch Access bit. */ - WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); - ReadUartRegister(UartRegister_LCR); + /* Restore Divisor Latch Access bit. */ + WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); + ReadUartRegister(UartRegister_LCR); + } } void KDebugLogImpl::Restore() { - /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ - WriteUartRegister(UartRegister_LCR, 0x80); - ReadUartRegister(UartRegister_LCR); + if constexpr (DoSaveAndRestore) { + /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ + WriteUartRegister(UartRegister_LCR, 0x80); + ReadUartRegister(UartRegister_LCR); - /* Restore DLL/DLH. */ - WriteUartRegister(UartRegister_DLL, g_saved_registers[3]); - WriteUartRegister(UartRegister_DLH, g_saved_registers[4]); - ReadUartRegister(UartRegister_DLH); + /* Restore DLL/DLH. */ + WriteUartRegister(UartRegister_DLL, g_saved_registers[3]); + WriteUartRegister(UartRegister_DLH, g_saved_registers[4]); + ReadUartRegister(UartRegister_DLH); - /* Restore Divisor Latch Access bit. */ - WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); - ReadUartRegister(UartRegister_LCR); + /* Restore Divisor Latch Access bit. */ + WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); + ReadUartRegister(UartRegister_LCR); - /* Restore IER and FCR. */ - WriteUartRegister(UartRegister_IER, g_saved_registers[1]); - WriteUartRegister(UartRegister_FCR, g_saved_registers[2] | 2); - WriteUartRegister(UartRegister_IRDA_CSR, 0x02); - ReadUartRegister(UartRegister_FCR); + /* Restore IER and FCR. */ + WriteUartRegister(UartRegister_IER, g_saved_registers[1]); + WriteUartRegister(UartRegister_FCR, g_saved_registers[2] | 2); + WriteUartRegister(UartRegister_IRDA_CSR, 0x02); + ReadUartRegister(UartRegister_FCR); + } } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) diff --git a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp index 8c051a15c..129edaba4 100644 --- a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -26,14 +26,14 @@ namespace ams::kern { constexpr size_t CarveoutSizeMax = 512_MB - CarveoutAlignment; ALWAYS_INLINE bool SetupUartPhysicalMemoryRegion() { - #if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #if defined(MESOSPHERE_DEBUG_LOG_USE_UART) + switch (KSystemControl::Init::GetDebugLogUartPort()) { + case 0: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 1: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 2: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 3: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + default: return false; + } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) return true; #else From f62330c73bdae125fb30ef51815979cff5f8f6cf Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 19:33:29 -0800 Subject: [PATCH 12/29] fusee: update for exo flags arr-type --- fusee/fusee-secondary/src/nxboot.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index e797ac01b..6a8cb02f7 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -506,13 +506,13 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke free(exosphere_ini); /* Apply parse config. */ - if (parse_cfg.debugmode) exo_cfg.flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV; - if (parse_cfg.debugmode_user) exo_cfg.flags |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER; - if (parse_cfg.disable_user_exception_handlers) exo_cfg.flags |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS; - if (parse_cfg.enable_user_pmu_access) exo_cfg.flags |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS; - if (parse_cfg.blank_prodinfo_sysmmc && !is_emummc) exo_cfg.flags |= EXOSPHERE_FLAG_BLANK_PRODINFO; - if (parse_cfg.blank_prodinfo_emummc && is_emummc) exo_cfg.flags |= EXOSPHERE_FLAG_BLANK_PRODINFO; - if (parse_cfg.allow_writing_to_cal_sysmmc) exo_cfg.flags |= EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC; + if (parse_cfg.debugmode) exo_cfg.flags[0] |= EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV; + if (parse_cfg.debugmode_user) exo_cfg.flags[0] |= EXOSPHERE_FLAG_IS_DEBUGMODE_USER; + if (parse_cfg.disable_user_exception_handlers) exo_cfg.flags[0] |= EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS; + if (parse_cfg.enable_user_pmu_access) exo_cfg.flags[0] |= EXOSPHERE_FLAG_ENABLE_USERMODE_PMU_ACCESS; + if (parse_cfg.blank_prodinfo_sysmmc && !is_emummc) exo_cfg.flags[0] |= EXOSPHERE_FLAG_BLANK_PRODINFO; + if (parse_cfg.blank_prodinfo_emummc && is_emummc) exo_cfg.flags[0] |= EXOSPHERE_FLAG_BLANK_PRODINFO; + if (parse_cfg.allow_writing_to_cal_sysmmc) exo_cfg.flags[0] |= EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC; exo_cfg.log_port = parse_cfg.log_port; exo_cfg.log_baud_rate = parse_cfg.log_baud_rate; From 58c3c8c19a441aa58d90c13442e09388f425f5d8 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 19:34:13 -0800 Subject: [PATCH 13/29] fusee: take three tries for a basic assignment --- fusee/fusee-secondary/src/nxboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 6a8cb02f7..415ec9f16 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -478,9 +478,9 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke const bool is_emummc = exo_emummc_cfg->base_cfg.magic == MAGIC_EMUMMC_CONFIG && exo_emummc_cfg->base_cfg.type != EMUMMC_TYPE_NONE; if (keygen_type) { - exo_cfg.flags = EXOSPHERE_FLAG_PERFORM_620_KEYGEN; + exo_cfg.flags[0] = EXOSPHERE_FLAG_PERFORM_620_KEYGEN; } else { - exo_cfg.flags = 0; + exo_cfg.flags[0] = 0; } /* Setup exosphere parse configuration with defaults. */ From abd7ad27202add34d1e8ce6f427d3be87f7cd712 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 8 Dec 2020 16:16:49 -0800 Subject: [PATCH 14/29] meso: properly initialize per-thread CFI-value for 11.x --- .../source/arch/arm64/kern_k_thread_context.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_thread_context.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_thread_context.cpp index f31d95972..04035e30d 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_thread_context.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_thread_context.cpp @@ -51,7 +51,7 @@ namespace ams::kern::arch::arm64 { cpu::InstructionMemoryBarrier(); } - uintptr_t SetupStackForUserModeThreadStarter(KVirtualAddress pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_64_bit) { + uintptr_t SetupStackForUserModeThreadStarter(KVirtualAddress pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, const bool is_64_bit) { /* NOTE: Stack layout on entry looks like following: */ /* SP */ /* | */ @@ -76,6 +76,11 @@ namespace ams::kern::arch::arm64 { MESOSPHERE_LOG("Creating User 32-Thread, %016lx\n", GetInteger(pc)); } + /* Set CFI-value. */ + if (is_64_bit) { + ctx->x[18] = KSystemControl::GenerateRandomU64() | 1; + } + /* Set stack pointer. */ if (is_64_bit) { ctx->sp = GetInteger(u_sp); From bcc7eed037c15319fc7f95abac6571685848dc04 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Dec 2020 05:59:54 -0800 Subject: [PATCH 15/29] kern: add debug thread dump --- .../libmesosphere/include/mesosphere.hpp | 1 + .../include/mesosphere/kern_build_config.hpp | 1 + .../include/mesosphere/kern_k_dump_object.hpp | 25 ++++++ .../include/mesosphere/kern_k_thread.hpp | 1 + .../source/kern_k_dump_object.cpp | 80 +++++++++++++++++++ .../libmesosphere/source/kern_k_thread.cpp | 34 ++++++++ .../source/svc/kern_svc_kernel_debug.cpp | 22 +++-- .../include/vapours/svc/svc_types_common.hpp | 2 +- 8 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp create mode 100644 libraries/libmesosphere/source/kern_k_dump_object.cpp diff --git a/libraries/libmesosphere/include/mesosphere.hpp b/libraries/libmesosphere/include/mesosphere.hpp index f5ff746ee..2c538e33c 100644 --- a/libraries/libmesosphere/include/mesosphere.hpp +++ b/libraries/libmesosphere/include/mesosphere.hpp @@ -54,6 +54,7 @@ #include #include #include +#include /* Miscellaneous objects. */ #include diff --git a/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp index 6f026f721..dcda97f6e 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp @@ -26,6 +26,7 @@ #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING #define MESOSPHERE_ENABLE_ASSERTIONS #define MESOSPHERE_ENABLE_DEBUG_PRINT +#define MESOSPHERE_ENABLE_KERNEL_STACK_USAGE #endif //#define MESOSPHERE_BUILD_FOR_TRACING diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp new file mode 100644 index 000000000..ab7cf9a0a --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -0,0 +1,25 @@ +/* + * 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 + +namespace ams::kern::KDumpObject { + + void DumpThread(); + void DumpThread(u64 thread_id); + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 20ea88ba8..ce3791061 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -533,6 +533,7 @@ namespace ams::kern { return this->termination_requested || this->GetRawState() == ThreadState_Terminated; } + size_t GetKernelStackUsage() const; public: /* Overridden parent functions. */ virtual u64 GetId() const override final { return this->GetThreadId(); } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp new file mode 100644 index 000000000..4aa24473b --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -0,0 +1,80 @@ +/* + * 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 . + */ +#include + +namespace ams::kern::KDumpObject { + + namespace { + + constexpr const char * const ThreadStates[] = { + [KThread::ThreadState_Initialized] = "Initialized", + [KThread::ThreadState_Waiting] = "Waiting", + [KThread::ThreadState_Runnable] = "Runnable", + [KThread::ThreadState_Terminated] = "Terminated", + }; + + void DumpThread(KThread *thread) { + if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { + MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", + thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], + thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), + thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); + + MESOSPHERE_LOG(" State: 0x%04x Suspend: 0x%04x Dpc: 0x%x\n", thread->GetRawState(), thread->GetSuspendFlags(), thread->GetDpc()); + + MESOSPHERE_LOG(" TLS: %p (%p)\n", GetVoidPointer(thread->GetThreadLocalRegionAddress()), thread->GetThreadLocalRegionHeapAddress()); + } else { + MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", + thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], + thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), + thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); + } + } + + } + + void DumpThread() { + MESOSPHERE_LOG("Dump Thread\n"); + + { + /* Lock the list. */ + KThread::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each thread. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpThread(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_LOG("\n"); + } + + void DumpThread(u64 thread_id) { + MESOSPHERE_LOG("Dump Thread\n"); + + { + /* Find and dump the target thread. */ + if (KThread *thread = KThread::GetThreadFromId(thread_id); thread != nullptr) { + ON_SCOPE_EXIT { thread->Close(); }; + DumpThread(thread); + } + } + + MESOSPHERE_LOG("\n"); + } + +} diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index f6f327d74..ea1316e58 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -24,6 +24,15 @@ namespace ams::kern { return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast; } + void InitializeKernelStack(uintptr_t stack_top) { + #if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE) + const uintptr_t stack_bottom = stack_top - PageSize; + std::memset(reinterpret_cast(stack_bottom), 0xCC, PageSize - sizeof(KThread::StackParameters)); + #else + MESOSPHERE_UNUSED(stack_top); + #endif + } + void CleanupKernelStack(uintptr_t stack_top) { const uintptr_t stack_bottom = stack_top - PageSize; @@ -153,6 +162,11 @@ namespace ams::kern { this->resource_limit_release_hint = 0; this->cpu_time = 0; + /* Setup our kernel stack. */ + if (type != ThreadType_Main) { + InitializeKernelStack(reinterpret_cast(kern_stack_top)); + } + /* Clear our stack parameters. */ std::memset(static_cast(std::addressof(this->GetStackParameters())), 0, sizeof(StackParameters)); @@ -803,6 +817,26 @@ namespace ams::kern { KScheduler::OnThreadStateChanged(this, old_state); } + size_t KThread::GetKernelStackUsage() const { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(this->kernel_stack_top != nullptr); + + #if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE) + const u8 *stack = static_cast(this->kernel_stack_top) - PageSize; + + size_t i; + for (i = 0; i < PageSize; ++i) { + if (stack[i] != 0xCC) { + break; + } + } + + return PageSize - i; + #else + return 0; + #endif + } + Result KThread::SetActivity(ams::svc::ThreadActivity activity) { /* Lock ourselves. */ KScopedLightLock lk(this->activity_pause_lock); diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 177f4a50d..c905f8017 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -22,19 +22,27 @@ namespace ams::kern::svc { namespace { void KernelDebug(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { - #ifdef ATMOSPHERE_BUILD_FOR_DEBUGGING + MESOSPHERE_UNUSED(kern_debug_type, arg0, arg1, arg2); + + #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING { - /* TODO: Implement Kernel Debugging. */ - } - #else - { - MESOSPHERE_UNUSED(kern_debug_type, arg0, arg1, arg2); + switch (kern_debug_type) { + case ams::svc::KernelDebugType_Thread: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpThread(); + } else { + KDumpObject::DumpThread(arg0); + } + break; + default: + break; + } } #endif } void ChangeKernelTraceState(ams::svc::KernelTraceState kern_trace_state) { - #ifdef ATMOSPHERE_BUILD_FOR_DEBUGGING + #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING { switch (kern_trace_state) { case ams::svc::KernelTraceState_Enabled: diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 0630fc017..c5aff199c 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -470,7 +470,7 @@ namespace ams::svc { }; enum KernelDebugType : u32 { - /* TODO */ + KernelDebugType_Thread = 0, }; enum KernelTraceState : u32 { From 16e2f46aede4294b491710f03bf466892aa2c36e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Dec 2020 06:45:19 -0800 Subject: [PATCH 16/29] fatal: prevent crash on fatal from currently-debugged process --- stratosphere/fatal/source/fatal_debug.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stratosphere/fatal/source/fatal_debug.cpp b/stratosphere/fatal/source/fatal_debug.cpp index 6a45f589a..b19fca621 100644 --- a/stratosphere/fatal/source/fatal_debug.cpp +++ b/stratosphere/fatal/source/fatal_debug.cpp @@ -170,17 +170,18 @@ namespace ams::fatal::srv { void TryCollectDebugInformation(ThrowContext *ctx, os::ProcessId process_id) { /* Try to debug the process. This may fail, if we called into ourself. */ - os::ManagedHandle debug_handle; - if (R_FAILED(svcDebugActiveProcess(debug_handle.GetPointer(), static_cast(process_id)))) { + Handle debug_handle; + if (R_FAILED(svcDebugActiveProcess(std::addressof(debug_handle), static_cast(process_id)))) { return; } + ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); }; /* First things first, check if process is 64 bits, and get list of thread infos. */ std::unordered_map thread_id_to_tls; { bool got_create_process = false; svc::DebugEventInfo d; - while (R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast(&d), debug_handle.Get()))) { + while (R_SUCCEEDED(svcGetDebugEvent(reinterpret_cast(&d), debug_handle))) { switch (d.type) { case svc::DebugEvent_CreateProcess: ctx->cpu_ctx.architecture = (d.info.create_process.flags & 1) ? CpuContext::Architecture_Aarch64 : CpuContext::Architecture_Aarch32; @@ -216,7 +217,7 @@ namespace ams::fatal::srv { /* We start by trying to get a list of threads. */ s32 thread_count; u64 thread_ids[0x60]; - if (R_FAILED(svc::GetThreadList(&thread_count, thread_ids, 0x60, debug_handle.Get()))) { + if (R_FAILED(svc::GetThreadList(&thread_count, thread_ids, 0x60, debug_handle))) { return; } @@ -227,7 +228,7 @@ namespace ams::fatal::srv { continue; } - if (IsThreadFatalCaller(ctx->result, debug_handle.Get(), cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) { + if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) { thread_id = cur_thread_id; thread_tls = thread_id_to_tls[thread_id]; found_fatal_caller = true; @@ -238,7 +239,7 @@ namespace ams::fatal::srv { return; } } - if (R_FAILED(svcGetDebugThreadContext(&thread_ctx, debug_handle.Get(), thread_id, svc::ThreadContextFlag_All))) { + if (R_FAILED(svcGetDebugThreadContext(&thread_ctx, debug_handle, thread_id, svc::ThreadContextFlag_All))) { return; } @@ -259,7 +260,7 @@ namespace ams::fatal::srv { /* Read a new frame. */ StackFrame cur_frame = {}; - if (R_FAILED(svcReadDebugProcessMemory(&cur_frame, debug_handle.Get(), cur_fp, sizeof(StackFrame)))) { + if (R_FAILED(svcReadDebugProcessMemory(&cur_frame, debug_handle, cur_fp, sizeof(StackFrame)))) { break; } @@ -271,7 +272,7 @@ namespace ams::fatal::srv { /* Try to read up to 0x100 of stack. */ ctx->stack_dump_base = 0; for (size_t sz = 0x100; sz > 0; sz -= 0x10) { - if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->stack_dump, debug_handle.Get(), thread_ctx.sp, sz))) { + if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->stack_dump, debug_handle, thread_ctx.sp, sz))) { ctx->stack_dump_base = thread_ctx.sp; ctx->stack_dump_size = sz; break; @@ -279,7 +280,7 @@ namespace ams::fatal::srv { } /* Try to read the first 0x100 of TLS. */ - if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->tls_dump, debug_handle.Get(), thread_tls, sizeof(ctx->tls_dump)))) { + if (R_SUCCEEDED(svcReadDebugProcessMemory(ctx->tls_dump, debug_handle, thread_tls, sizeof(ctx->tls_dump)))) { ctx->tls_address = thread_tls; } else { ctx->tls_address = 0; @@ -287,7 +288,7 @@ namespace ams::fatal::srv { } /* Parse the base address. */ - ctx->cpu_ctx.aarch64_ctx.SetBaseAddress(GetBaseAddress(ctx, &thread_ctx, debug_handle.Get())); + ctx->cpu_ctx.aarch64_ctx.SetBaseAddress(GetBaseAddress(ctx, &thread_ctx, debug_handle)); } } From af259eabdad45d8de74d97e7a78bce2f395c2cf6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Dec 2020 22:49:04 -0800 Subject: [PATCH 17/29] kern: implement thread call stack debug --- .../mesosphere/arch/arm64/kern_k_debug.hpp | 5 +- .../arch/arm64/kern_k_process_page_table.hpp | 4 + .../include/mesosphere/kern_k_dump_object.hpp | 3 + .../include/mesosphere/kern_k_thread.hpp | 22 +- .../source/arch/arm64/kern_k_debug.cpp | 537 ++++++++++++++++++ .../source/kern_k_dump_object.cpp | 44 ++ libraries/libmesosphere/source/kern_panic.cpp | 23 +- .../source/svc/kern_svc_exception.cpp | 10 +- .../source/svc/kern_svc_kernel_debug.cpp | 7 + .../include/vapours/svc/svc_types_common.hpp | 3 +- .../kernel_ldr/source/kern_loader_panic.cpp | 31 + 11 files changed, 657 insertions(+), 32 deletions(-) create mode 100644 mesosphere/kernel_ldr/source/kern_loader_panic.cpp diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_debug.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_debug.hpp index b9735db84..4dc3f9682 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_debug.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_debug.hpp @@ -44,6 +44,9 @@ namespace ams::kern::arch::arm64 { static uintptr_t GetProgramCounter(const KThread &thread); static void SetPreviousProgramCounter(); + static void PrintRegister(KThread *thread = nullptr); + static void PrintBacktrace(KThread *thread = nullptr); + static Result BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size); static Result SetHardwareBreakPoint(ams::svc::HardwareBreakPointRegisterName name, u64 flags, u64 value); @@ -61,8 +64,6 @@ namespace ams::kern::arch::arm64 { } } } - - /* TODO: This is a placeholder definition. */ }; } diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 52d56618b..48a9e8081 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -273,6 +273,10 @@ namespace ams::kern::arch::arm64 { return this->page_table.GetHeapPhysicalAddress(address); } + KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress address) const { + return this->page_table.GetHeapVirtualAddress(address); + } + KBlockInfoManager *GetBlockInfoManager() { return this->page_table.GetBlockInfoManager(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index ab7cf9a0a..6ef29e216 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -22,4 +22,7 @@ namespace ams::kern::KDumpObject { void DumpThread(); void DumpThread(u64 thread_id); + void DumpThreadCallStack(); + void DumpThreadCallStack(u64 thread_id); + } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index ce3791061..6f9fb4b9c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -49,11 +49,11 @@ namespace ams::kern { }; enum SuspendType : u32 { - SuspendType_Process = 0, - SuspendType_Thread = 1, - SuspendType_Debug = 2, - SuspendType_Unk3 = 3, - SuspendType_Init = 4, + SuspendType_Process = 0, + SuspendType_Thread = 1, + SuspendType_Debug = 2, + SuspendType_Backtrace = 3, + SuspendType_Init = 4, SuspendType_Count, }; @@ -67,13 +67,13 @@ namespace ams::kern { ThreadState_SuspendShift = 4, ThreadState_Mask = (1 << ThreadState_SuspendShift) - 1, - ThreadState_ProcessSuspended = (1 << (SuspendType_Process + ThreadState_SuspendShift)), - ThreadState_ThreadSuspended = (1 << (SuspendType_Thread + ThreadState_SuspendShift)), - ThreadState_DebugSuspended = (1 << (SuspendType_Debug + ThreadState_SuspendShift)), - ThreadState_Unk3Suspended = (1 << (SuspendType_Unk3 + ThreadState_SuspendShift)), - ThreadState_InitSuspended = (1 << (SuspendType_Init + ThreadState_SuspendShift)), + ThreadState_ProcessSuspended = (1 << (SuspendType_Process + ThreadState_SuspendShift)), + ThreadState_ThreadSuspended = (1 << (SuspendType_Thread + ThreadState_SuspendShift)), + ThreadState_DebugSuspended = (1 << (SuspendType_Debug + ThreadState_SuspendShift)), + ThreadState_BacktraceSuspended = (1 << (SuspendType_Backtrace + ThreadState_SuspendShift)), + ThreadState_InitSuspended = (1 << (SuspendType_Init + ThreadState_SuspendShift)), - ThreadState_SuspendFlagMask = ((1 << SuspendType_Count) - 1) << ThreadState_SuspendShift, + ThreadState_SuspendFlagMask = ((1 << SuspendType_Count) - 1) << ThreadState_SuspendShift, }; enum DpcFlag : u32 { diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp index b6286a02a..415e38c65 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp @@ -384,4 +384,541 @@ namespace ams::kern::arch::arm64 { #undef MESOSPHERE_SET_HW_WATCH_POINT #undef MESOSPHERE_SET_HW_BREAK_POINT + void KDebug::PrintRegister(KThread *thread) { + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + { + /* Treat no thread as current thread. */ + if (thread == nullptr) { + thread = GetCurrentThreadPointer(); + } + + /* Get the exception context. */ + KExceptionContext *e_ctx = GetExceptionContext(thread); + + /* Get the owner process. */ + if (auto *process = thread->GetOwnerProcess(); process != nullptr) { + /* Lock the owner process. */ + KScopedLightLock state_lk(process->GetStateLock()); + KScopedLightLock list_lk(process->GetListLock()); + + /* Suspend all the process's threads. */ + { + KScopedSchedulerLock sl; + + auto end = process->GetThreadList().end(); + for (auto it = process->GetThreadList().begin(); it != end; ++it) { + if (std::addressof(*it) != GetCurrentThreadPointer()) { + it->RequestSuspend(KThread::SuspendType_Backtrace); + } + } + } + + /* Print the registers. */ + MESOSPHERE_RELEASE_LOG("Registers\n"); + if ((e_ctx->psr & 0x10) == 0) { + /* 64-bit thread. */ + for (auto i = 0; i < 31; ++i) { + MESOSPHERE_RELEASE_LOG(" X[%2d]: 0x%016lx\n", i, e_ctx->x[i]); + } + MESOSPHERE_RELEASE_LOG(" SP: 0x%016lx\n", e_ctx->sp); + MESOSPHERE_RELEASE_LOG(" PC: 0x%016lx\n", e_ctx->pc - sizeof(u32)); + MESOSPHERE_RELEASE_LOG(" PSR: 0x%08x\n", e_ctx->psr); + MESOSPHERE_RELEASE_LOG(" TPIDR_EL0: 0x%016lx\n", e_ctx->tpidr); + } else { + /* 32-bit thread. */ + for (auto i = 0; i < 13; ++i) { + MESOSPHERE_RELEASE_LOG(" R[%2d]: 0x%08x\n", i, static_cast(e_ctx->x[i])); + } + MESOSPHERE_RELEASE_LOG(" SP: 0x%08x\n", static_cast(e_ctx->x[13])); + MESOSPHERE_RELEASE_LOG(" LR: 0x%08x\n", static_cast(e_ctx->x[14])); + MESOSPHERE_RELEASE_LOG(" PC: 0x%08x\n", static_cast(e_ctx->pc) - static_cast((e_ctx->psr & 0x20) ? sizeof(u16) : sizeof(u32))); + MESOSPHERE_RELEASE_LOG(" PSR: 0x%08x\n", e_ctx->psr); + MESOSPHERE_RELEASE_LOG(" TPIDR: 0x%08x\n", static_cast(e_ctx->tpidr)); + } + + /* Resume the threads that we suspended. */ + { + KScopedSchedulerLock sl; + + auto end = process->GetThreadList().end(); + for (auto it = process->GetThreadList().begin(); it != end; ++it) { + if (std::addressof(*it) != GetCurrentThreadPointer()) { + it->Resume(KThread::SuspendType_Backtrace); + } + } + } + } + } + #else + MESOSPHERE_UNUSED(thread); + #endif + } + + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + namespace { + + bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) { + const KMemoryRegion *cached = nullptr; + return KMemoryLayout::IsHeapPhysicalAddress(cached, phys_addr); + } + + template + bool ReadValue(T *out, KProcess *process, uintptr_t address) { + KPhysicalAddress phys_addr; + KMemoryInfo mem_info; + ams::svc::PageInfo page_info; + + if (!util::IsAligned(address, sizeof(T))) { + return false; + } + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), address))) { + return false; + } + if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { + return false; + } + if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), address)) { + return false; + } + if (!IsHeapPhysicalAddress(phys_addr)) { + return false; + } + + *out = *GetPointer(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); + return true; + } + + bool GetModuleName(char *dst, size_t dst_size, KProcess *process, uintptr_t base_address) { + /* Locate .rodata. */ + KMemoryInfo mem_info; + ams::svc::PageInfo page_info; + KMemoryState mem_state = KMemoryState_None; + + while (true) { + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address))) { + return false; + } + if (mem_state == KMemoryState_None) { + mem_state = mem_info.GetState(); + if (mem_state != KMemoryState_Code && mem_state != KMemoryState_AliasCode) { + return false; + } + } + if (mem_info.GetState() != mem_state) { + return false; + } + if (mem_info.GetPermission() == KMemoryPermission_UserRead) { + break; + } + base_address = mem_info.GetEndAddress(); + } + + /* Check that first value is 0. */ + u32 val; + if (!ReadValue(std::addressof(val), process, base_address)) { + return false; + } + if (val != 0) { + return false; + } + + /* Read the name length. */ + if (!ReadValue(std::addressof(val), process, base_address + sizeof(u32))) { + return false; + } + if (!(0 < val && val < dst_size)) { + return false; + } + const size_t name_len = val; + + /* Read the name, one character at a time. */ + for (size_t i = 0; i < name_len; ++i) { + if (!ReadValue(dst + i, process, base_address + 2 * sizeof(u32) + i)) { + return false; + } + if (!(0 < dst[i] && dst[i] <= 0x7F)) { + return false; + } + } + + /* NULL-terminate. */ + dst[name_len] = 0; + + return true; + } + + void PrintAddress(uintptr_t address) { + MESOSPHERE_RELEASE_LOG(" %p\n", reinterpret_cast(address)); + } + + void PrintAddressWithModuleName(uintptr_t address, bool has_module_name, const char *module_name, uintptr_t base_address) { + if (has_module_name) { + MESOSPHERE_RELEASE_LOG(" %p [%10s + %8lx]\n", reinterpret_cast(address), module_name, address - base_address); + } else { + MESOSPHERE_RELEASE_LOG(" %p [%10lx + %8lx]\n", reinterpret_cast(address), base_address, address - base_address); + } + } + + void PrintAddressWithSymbol(uintptr_t address, bool has_module_name, const char *module_name, uintptr_t base_address, const char *symbol_name, uintptr_t func_address) { + if (has_module_name) { + MESOSPHERE_RELEASE_LOG(" %p [%10s + %8lx] (%s + %lx)\n", reinterpret_cast(address), module_name, address - base_address, symbol_name, address - func_address); + } else { + MESOSPHERE_RELEASE_LOG(" %p [%10lx + %8lx] (%s + %lx)\n", reinterpret_cast(address), base_address, address - base_address, symbol_name, address - func_address); + } + } + + void PrintCodeAddress(KProcess *process, uintptr_t address, bool is_lr = true) { + /* Prepare to parse + print the address. */ + uintptr_t test_address = is_lr ? address - sizeof(u32) : address; + uintptr_t base_address = address; + uintptr_t dyn_address = 0; + uintptr_t sym_tab = 0; + uintptr_t str_tab = 0; + size_t num_sym = 0; + + u64 temp_64; + u32 temp_32; + + /* Locate the start of .text. */ + KMemoryInfo mem_info; + ams::svc::PageInfo page_info; + KMemoryState mem_state = KMemoryState_None; + while (true) { + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address))) { + return PrintAddress(address); + } + if (mem_state == KMemoryState_None) { + mem_state = mem_info.GetState(); + if (mem_state != KMemoryState_Code && mem_state != KMemoryState_AliasCode) { + return PrintAddress(address); + } + } else if (mem_info.GetState() != mem_state) { + return PrintAddress(address); + } + if (mem_info.GetPermission() != KMemoryPermission_UserReadExecute) { + return PrintAddress(address); + } + base_address = mem_info.GetAddress(); + + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address - 1))) { + return PrintAddress(address); + } + if (mem_info.GetState() != mem_state) { + break; + } + if (mem_info.GetPermission() != KMemoryPermission_UserReadExecute) { + break; + } + } + + /* Read the first instruction. */ + if (!ReadValue(std::addressof(temp_32), process, base_address)) { + return PrintAddress(address); + } + + /* Get the module name. */ + char module_name[0x20]; + const bool has_module_name = GetModuleName(module_name, sizeof(module_name), process, base_address); + + /* If the process is 32-bit, just print the module. */ + if (!process->Is64Bit()) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + if (temp_32 == 0) { + /* Module is dynamically loaded by rtld. */ + u32 mod_offset; + if (!ReadValue(std::addressof(mod_offset), process, base_address + sizeof(u32))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (temp_32 != 0x30444F4D) { /* MOD0 */ + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + sizeof(u32))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + dyn_address = base_address + mod_offset + temp_32; + } else if (temp_32 == 0x14000002) { + /* Module embeds rtld. */ + if (!ReadValue(std::addressof(temp_32), process, base_address + 0x5C)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (temp_32 != 0x94000002) { /* MOD0 */ + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (!ReadValue(std::addressof(temp_32), process, base_address + 0x60)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + dyn_address = base_address + 0x60 + temp_32; + } else { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + /* Locate tables inside .dyn. */ + for (size_t ofs = 0; /* ... */; ofs += 0x10) { + /* Read the DynamicTag. */ + if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (temp_64 == 0) { + /* We're done parsing .dyn. */ + break; + } else if (temp_64 == 4) { + /* We found DT_HASH */ + if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + /* Read nchain, to get the number of symbols. */ + if (!ReadValue(std::addressof(temp_32), process, base_address + temp_64 + sizeof(u32))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + num_sym = temp_32; + } else if (temp_64 == 5) { + /* We found DT_STRTAB */ + if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + str_tab = base_address + temp_64; + } else if (temp_64 == 6) { + /* We found DT_SYMTAB */ + if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + sym_tab = base_address + temp_64; + } + } + + /* Check that we found all the tables. */ + if (!(sym_tab != 0 && str_tab != 0 && num_sym != 0)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + /* Try to locate an appropriate symbol. */ + for (size_t i = 0; i < num_sym; ++i) { + /* Read the symbol from userspace. */ + struct { + u32 st_name; + u8 st_info; + u8 st_other; + u16 st_shndx; + u64 st_value; + u64 st_size; + } sym; + { + u64 x[sizeof(sym) / sizeof(u64)]; + for (size_t j = 0; j < util::size(x); ++j) { + if (!ReadValue(x + j, process, sym_tab + sizeof(sym) * i + sizeof(u64) * j)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + } + std::memcpy(std::addressof(sym), x, sizeof(sym)); + } + + /* Check the symbol is valid/STT_FUNC. */ + if (sym.st_shndx == 0 || ((sym.st_shndx & 0xFF00) == 0xFF00)) { + continue; + } + if ((sym.st_info & 0xF) != 2) { + continue; + } + + /* Check the address. */ + const uintptr_t func_start = base_address + sym.st_value; + if (func_start <= test_address && test_address < func_start + sym.st_size) { + /* Read the symbol name. */ + const uintptr_t sym_address = str_tab + sym.st_name; + char sym_name[0x80]; + sym_name[util::size(sym_name) - 1] = 0; + for (size_t j = 0; j < util::size(sym_name) - 1; ++j) { + if (!ReadValue(sym_name + j, process, sym_address + j)) { + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + if (sym_name[j] == 0) { + break; + } + } + + /* Print the symbol. */ + return PrintAddressWithSymbol(address, has_module_name, module_name, base_address, sym_name, func_start); + } + } + + /* Fall back to printing the module. */ + return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); + } + + } + #endif + + void KDebug::PrintBacktrace(KThread *thread) { + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + { + /* Treat no thread as current thread. */ + if (thread == nullptr) { + thread = GetCurrentThreadPointer(); + } + + /* Get the exception context. */ + KExceptionContext *e_ctx = GetExceptionContext(thread); + + /* Get the owner process. */ + if (auto *process = thread->GetOwnerProcess(); process != nullptr) { + /* Lock the owner process. */ + KScopedLightLock state_lk(process->GetStateLock()); + KScopedLightLock list_lk(process->GetListLock()); + + /* Suspend all the process's threads. */ + { + KScopedSchedulerLock sl; + + auto end = process->GetThreadList().end(); + for (auto it = process->GetThreadList().begin(); it != end; ++it) { + if (std::addressof(*it) != GetCurrentThreadPointer()) { + it->RequestSuspend(KThread::SuspendType_Backtrace); + } + } + } + + /* Print the backtrace. */ + MESOSPHERE_RELEASE_LOG("User Backtrace\n"); + if ((e_ctx->psr & 0x10) == 0) { + /* 64-bit thread. */ + PrintCodeAddress(process, e_ctx->pc, false); + PrintCodeAddress(process, e_ctx->x[30]); + + /* Walk the stack frames. */ + uintptr_t fp = static_cast(e_ctx->x[29]); + for (auto i = 0; i < 0x20 && fp != 0 && util::IsAligned(fp, 0x10); ++i) { + /* Read the next frame. */ + struct { + u64 fp; + u64 lr; + } stack_frame; + { + KMemoryInfo mem_info; + ams::svc::PageInfo page_info; + KPhysicalAddress phys_addr; + + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), fp))) { + break; + } + if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { + break; + } + if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { + break; + } + if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { + break; + } + if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), fp)) { + break; + } + if (!IsHeapPhysicalAddress(phys_addr)) { + break; + } + + u64 *frame_ptr = GetPointer(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); + stack_frame.fp = frame_ptr[0]; + stack_frame.lr = frame_ptr[1]; + } + + /* Print and advance. */ + PrintCodeAddress(process, stack_frame.lr); + fp = stack_frame.fp; + } + } else { + /* 32-bit thread. */ + PrintCodeAddress(process, e_ctx->pc, false); + PrintCodeAddress(process, e_ctx->x[14]); + + /* Walk the stack frames. */ + uintptr_t fp = static_cast(e_ctx->x[11]); + for (auto i = 0; i < 0x20 && fp != 0 && util::IsAligned(fp, 4); ++i) { + /* Read the next frame. */ + struct { + u32 fp; + u32 lr; + } stack_frame; + { + KMemoryInfo mem_info; + ams::svc::PageInfo page_info; + KPhysicalAddress phys_addr; + + /* Read FP */ + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), fp))) { + break; + } + if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { + break; + } + if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { + break; + } + if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { + break; + } + if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), fp)) { + break; + } + if (!IsHeapPhysicalAddress(phys_addr)) { + break; + } + + stack_frame.fp = *GetPointer(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); + + /* Read LR. */ + uintptr_t lr_ptr = (e_ctx->x[13] <= stack_frame.fp && stack_frame.fp < e_ctx->x[13] + PageSize) ? fp + 4 : fp - 4; + if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), lr_ptr))) { + break; + } + if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { + break; + } + if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { + break; + } + if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { + break; + } + if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), lr_ptr)) { + break; + } + if (!IsHeapPhysicalAddress(phys_addr)) { + break; + } + + stack_frame.lr = *GetPointer(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); + } + + /* Print and advance. */ + PrintCodeAddress(process, stack_frame.lr); + fp = stack_frame.fp; + } + } + + /* Resume the threads that we suspended. */ + { + KScopedSchedulerLock sl; + + auto end = process->GetThreadList().end(); + for (auto it = process->GetThreadList().begin(); it != end; ++it) { + if (std::addressof(*it) != GetCurrentThreadPointer()) { + it->Resume(KThread::SuspendType_Backtrace); + } + } + } + } + } + #else + MESOSPHERE_UNUSED(thread); + #endif + } + } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 4aa24473b..551b3f374 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -44,6 +44,19 @@ namespace ams::kern::KDumpObject { } } + void DumpThreadCallStack(KThread *thread) { + if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { + MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); + + KDebug::PrintRegister(thread); + KDebug::PrintBacktrace(thread); + } else { + MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); + } + } + } void DumpThread() { @@ -77,4 +90,35 @@ namespace ams::kern::KDumpObject { MESOSPHERE_LOG("\n"); } + void DumpThreadCallStack() { + MESOSPHERE_LOG("Dump Thread\n"); + + { + /* Lock the list. */ + KThread::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each thread. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpThreadCallStack(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_LOG("\n"); + } + + void DumpThreadCallStack(u64 thread_id) { + MESOSPHERE_LOG("Dump Thread\n"); + + { + /* Find and dump the target thread. */ + if (KThread *thread = KThread::GetThreadFromId(thread_id); thread != nullptr) { + ON_SCOPE_EXIT { thread->Close(); }; + DumpThreadCallStack(thread); + } + } + + MESOSPHERE_LOG("\n"); + } + } diff --git a/libraries/libmesosphere/source/kern_panic.cpp b/libraries/libmesosphere/source/kern_panic.cpp index 1dbbc54c9..ce9e2cdd0 100644 --- a/libraries/libmesosphere/source/kern_panic.cpp +++ b/libraries/libmesosphere/source/kern_panic.cpp @@ -97,25 +97,20 @@ namespace ams::kern { /* Print the state. */ MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id); - #ifdef ATMOSPHERE_ARCH_ARM64 - /* Print registers. */ - if (core_ctx != nullptr) { - MESOSPHERE_RELEASE_LOG(" Registers:\n"); - for (size_t i = 0; i < util::size(core_ctx->x); ++i) { - MESOSPHERE_RELEASE_LOG(" X[%02zx]: %p\n", i, reinterpret_cast(core_ctx->x[i])); - } - MESOSPHERE_RELEASE_LOG(" SP: %p\n", reinterpret_cast(core_ctx->x[30])); - } + /* Print registers and user backtrace. */ + KDebug::PrintRegister(); + KDebug::PrintBacktrace(); - /* Print backtrace. */ - MESOSPHERE_RELEASE_LOG(" Backtrace:\n"); + #ifdef ATMOSPHERE_ARCH_ARM64 + /* Print kernel backtrace. */ + MESOSPHERE_RELEASE_LOG("Backtrace:\n"); uintptr_t fp = core_ctx != nullptr ? core_ctx->x[29] : reinterpret_cast(__builtin_frame_address(0)); for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) { struct { uintptr_t fp; uintptr_t lr; } *stack_frame = reinterpret_cast(fp); - MESOSPHERE_RELEASE_LOG(" [%02zx]: %p\n", i, reinterpret_cast(stack_frame->lr)); + MESOSPHERE_RELEASE_LOG(" [%02zx]: %p\n", i, reinterpret_cast(stack_frame->lr)); fp = stack_frame->fp; } #endif @@ -137,7 +132,7 @@ namespace ams::kern { } - NORETURN void PanicImpl(const char *file, int line, const char *format, ...) { + NORETURN WEAK_SYMBOL void PanicImpl(const char *file, int line, const char *format, ...) { #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING /* Wait for it to be our turn to print. */ WaitCoreTicket(); @@ -158,7 +153,7 @@ namespace ams::kern { StopSystem(); } - NORETURN void PanicImpl() { + NORETURN WEAK_SYMBOL void PanicImpl() { StopSystem(); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_exception.cpp b/libraries/libmesosphere/source/svc/kern_svc_exception.cpp index f5c859a88..3f9940008 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_exception.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_exception.cpp @@ -21,16 +21,18 @@ namespace ams::kern::svc { namespace { - [[maybe_unused]] void PrintBreak(ams::svc::BreakReason break_reason) { + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + void PrintBreak(ams::svc::BreakReason break_reason) { /* Print that break was called. */ MESOSPHERE_RELEASE_LOG("%s: svc::Break(%d) was called, pid=%ld, tid=%ld\n", GetCurrentProcess().GetName(), static_cast(break_reason), GetCurrentProcess().GetId(), GetCurrentThread().GetId()); /* Print the current thread's registers. */ - /* TODO: KDebug::PrintRegisters(); */ + KDebug::PrintRegister(); /* Print a backtrace. */ - /* TODO: KDebug::PrintBacktrace(); */ + KDebug::PrintBacktrace(); } + #endif void Break(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) { /* Determine whether the break is only a notification. */ @@ -38,7 +40,7 @@ namespace ams::kern::svc { /* If the break isn't a notification, print it. */ if (!is_notification) { - #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) PrintBreak(break_reason); #endif } diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index c905f8017..18953df2f 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -34,6 +34,13 @@ namespace ams::kern::svc { KDumpObject::DumpThread(arg0); } break; + case ams::svc::KernelDebugType_ThreadCallStack: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpThreadCallStack(); + } else { + KDumpObject::DumpThreadCallStack(arg0); + } + break; default: break; } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index c5aff199c..64070e9ce 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -470,7 +470,8 @@ namespace ams::svc { }; enum KernelDebugType : u32 { - KernelDebugType_Thread = 0, + KernelDebugType_Thread = 0, + KernelDebugType_ThreadCallStack = 1, }; enum KernelTraceState : u32 { diff --git a/mesosphere/kernel_ldr/source/kern_loader_panic.cpp b/mesosphere/kernel_ldr/source/kern_loader_panic.cpp new file mode 100644 index 000000000..37c3f39cd --- /dev/null +++ b/mesosphere/kernel_ldr/source/kern_loader_panic.cpp @@ -0,0 +1,31 @@ +/* + * 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 . + */ +#include + +namespace ams::kern { + + /* This overrides the panic implementation from the kernel, to prevent linking debug print into kldr. */ + + NORETURN void PanicImpl(const char *file, int line, const char *format, ...) { + MESOSPHERE_UNUSED(file, line, format); + MESOSPHERE_INIT_ABORT(); + } + + NORETURN void PanicImpl() { + MESOSPHERE_INIT_ABORT(); + } + +} From 8a4bf6a0a817deedda52927a34dda15c262f1958 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 9 Dec 2020 23:44:36 -0800 Subject: [PATCH 18/29] kern: add handle table/process/suspend/resume debug --- .../include/mesosphere/kern_k_dump_object.hpp | 6 + .../mesosphere/kern_k_server_session.hpp | 2 + .../kern_k_synchronization_object.hpp | 2 +- .../include/mesosphere/kern_slab_helpers.hpp | 2 +- .../source/arch/arm64/kern_k_debug.cpp | 2 +- .../source/kern_k_dump_object.cpp | 165 ++++++++++++++++-- .../source/kern_k_server_session.cpp | 32 ++++ .../source/kern_k_synchronization_object.cpp | 2 +- .../source/svc/kern_svc_kernel_debug.cpp | 32 ++++ .../include/vapours/svc/svc_types_common.hpp | 6 + 10 files changed, 233 insertions(+), 18 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index 6ef29e216..4113fff1c 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -25,4 +25,10 @@ namespace ams::kern::KDumpObject { void DumpThreadCallStack(); void DumpThreadCallStack(u64 thread_id); + void DumpHandle(); + void DumpHandle(u64 process_id); + + void DumpProcess(); + void DumpProcess(u64 process_id); + } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp index 136a5dc6f..12979af04 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp @@ -50,6 +50,8 @@ namespace ams::kern { Result SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); void OnClientClosed(); + + void Dump(); private: bool IsSignaledImpl() const; void CleanupRequests(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp index 953c2fa4f..98dd5fe6e 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp @@ -46,7 +46,7 @@ namespace ams::kern { public: virtual void Finalize() override; virtual bool IsSignaled() const = 0; - virtual void DebugWaiters(); + virtual void DumpWaiters(); }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp index 9f62be183..e665c182d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp @@ -92,7 +92,7 @@ namespace ams::kern { virtual uintptr_t GetPostDestroyArgument() const { return 0; } size_t GetSlabIndex() const { - return s_slab_heap.GetIndex(static_cast(this)); + return s_slab_heap.GetObjectIndex(static_cast(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp index 415e38c65..5efe21b12 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp @@ -646,7 +646,7 @@ namespace ams::kern::arch::arm64 { if (!ReadValue(std::addressof(temp_32), process, base_address + 0x5C)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } - if (temp_32 != 0x94000002) { /* MOD0 */ + if (temp_32 != 0x94000002) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } if (!ReadValue(std::addressof(temp_32), process, base_address + 0x60)) { diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 551b3f374..06fe739c7 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -28,16 +28,16 @@ namespace ams::kern::KDumpObject { void DumpThread(KThread *thread) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); - MESOSPHERE_LOG(" State: 0x%04x Suspend: 0x%04x Dpc: 0x%x\n", thread->GetRawState(), thread->GetSuspendFlags(), thread->GetDpc()); + MESOSPHERE_RELEASE_LOG(" State: 0x%04x Suspend: 0x%04x Dpc: 0x%x\n", thread->GetRawState(), thread->GetSuspendFlags(), thread->GetDpc()); - MESOSPHERE_LOG(" TLS: %p (%p)\n", GetVoidPointer(thread->GetThreadLocalRegionAddress()), thread->GetThreadLocalRegionHeapAddress()); + MESOSPHERE_RELEASE_LOG(" TLS: %p (%p)\n", GetVoidPointer(thread->GetThreadLocalRegionAddress()), thread->GetThreadLocalRegionHeapAddress()); } else { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); @@ -46,21 +46,93 @@ namespace ams::kern::KDumpObject { void DumpThreadCallStack(KThread *thread) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); KDebug::PrintRegister(thread); KDebug::PrintBacktrace(thread); } else { - MESOSPHERE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", + MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); } } + void DumpHandle(const KProcess::ListAccessor &accessor, KProcess *process) { + MESOSPHERE_RELEASE_LOG("Process ID=%lu (%s)\n", process->GetId(), process->GetName()); + + const auto end = accessor.end(); + const auto &handle_table = process->GetHandleTable(); + const size_t max_handles = handle_table.GetMaxCount(); + for (size_t i = 0; i < max_handles; ++i) { + /* Get the object + handle. */ + ams::svc::Handle handle = ams::svc::InvalidHandle; + KScopedAutoObject obj = handle_table.GetObjectByIndex(std::addressof(handle), i); + if (obj.IsNotNull()) { + if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Client=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetClientSession())); + target->Dump(); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Server=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetServerSession())); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwnerProcess(); + const s32 owner_pid = target_owner != nullptr ? static_cast(target_owner->GetId()) : -1; + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d PID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target->GetId()), owner_pid); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target->GetId())); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + /* Find the owner. */ + KProcess *target_owner = nullptr; + for (auto it = accessor.begin(); it != end; ++it) { + if (static_cast(std::addressof(*it))->GetId() == target->GetOwnerProcessId()) { + target_owner = static_cast(std::addressof(*it)); + break; + } + } + + MESOSPHERE_ASSERT(target_owner != nullptr); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Size=%zu KB OwnerPID=%d (%s)\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetSize() / 1_KB, static_cast(target_owner->GetId()), target_owner->GetName()); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwner(); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + KProcess *target_owner = target->GetOwner(); + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s irq=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetInterruptId()); + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + if (KEvent *event = target->GetParent(); event != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Pair=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(event->GetReadableEvent())); + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + } else if (auto *target = obj->DynamicCast(); target != nullptr) { + if (KEvent *event = target->GetParent(); event != nullptr) { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Pair=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(event->GetWritableEvent())); + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + } else { + MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); + } + + if (auto *sync = obj->DynamicCast(); sync != nullptr) { + sync->DumpWaiters(); + } + } + } + + MESOSPHERE_RELEASE_LOG("%zu(max %zu)/%zu used.\n", handle_table.GetCount(), max_handles, handle_table.GetTableSize()); + MESOSPHERE_RELEASE_LOG("\n\n"); + } + + void DumpProcess(KProcess *process) { + MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); + } + } void DumpThread() { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ @@ -73,11 +145,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThread(u64 thread_id) { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ @@ -87,11 +159,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack() { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ @@ -104,11 +176,11 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack(u64 thread_id) { - MESOSPHERE_LOG("Dump Thread\n"); + MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ @@ -118,7 +190,72 @@ namespace ams::kern::KDumpObject { } } - MESOSPHERE_LOG("\n"); + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpHandle() { + MESOSPHERE_RELEASE_LOG("Dump Handle\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpHandle(accessor, static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpHandle(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Handle\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + /* Lock the list. */ + KProcess::ListAccessor accessor; + DumpHandle(accessor, process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpProcess() { + MESOSPHERE_RELEASE_LOG("Dump Process\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpProcess(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpProcess(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Process\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + DumpProcess(process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); } } diff --git a/libraries/libmesosphere/source/kern_k_server_session.cpp b/libraries/libmesosphere/source/kern_k_server_session.cpp index 712cca8b0..798209d43 100644 --- a/libraries/libmesosphere/source/kern_k_server_session.cpp +++ b/libraries/libmesosphere/source/kern_k_server_session.cpp @@ -1367,4 +1367,36 @@ namespace ams::kern { #pragma GCC pop_options + void KServerSession::Dump() { + MESOSPHERE_ASSERT_THIS(); + + KScopedLightLock lk(this->lock); + { + KScopedSchedulerLock sl; + MESOSPHERE_RELEASE_LOG("Dump Session %p\n", this); + + /* Dump current request. */ + bool has_request = false; + if (this->current_request != nullptr) { + KThread *thread = this->current_request->GetThread(); + const s32 thread_id = thread != nullptr ? static_cast(thread->GetId()) : -1; + MESOSPHERE_RELEASE_LOG(" CurrentReq %p Thread=%p ID=%d\n", this->current_request, thread, thread_id); + has_request = true; + } + + /* Dump all rqeuests in list. */ + for (auto it = this->request_list.begin(); it != this->request_list.end(); ++it) { + KThread *thread = it->GetThread(); + const s32 thread_id = thread != nullptr ? static_cast(thread->GetId()) : -1; + MESOSPHERE_RELEASE_LOG(" Req %p Thread=%p ID=%d\n", this->current_request, thread, thread_id); + has_request = true; + } + + /* If we didn't have any requests, print so. */ + if (!has_request) { + MESOSPHERE_RELEASE_LOG(" None\n"); + } + } + } + } diff --git a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp index bd5938b8e..774d0a60a 100644 --- a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp +++ b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp @@ -148,7 +148,7 @@ namespace ams::kern { } } - void KSynchronizationObject::DebugWaiters() { + void KSynchronizationObject::DumpWaiters() { MESOSPHERE_ASSERT_THIS(); /* If debugging, dump the list of waiters. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 18953df2f..86f9b5e84 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -41,6 +41,38 @@ namespace ams::kern::svc { KDumpObject::DumpThreadCallStack(arg0); } break; + case ams::svc::KernelDebugType_Handle: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpHandle(); + } else { + KDumpObject::DumpHandle(arg0); + } + break; + case ams::svc::KernelDebugType_Process: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpProcess(); + } else { + KDumpObject::DumpProcess(arg0); + } + break; + case ams::svc::KernelDebugType_SuspendProcess: + if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Paused))) { + MESOSPHERE_RELEASE_LOG("Suspend Process ID=%3lu\n", process->GetId()); + } + } + break; + case ams::svc::KernelDebugType_ResumeProcess: + if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Runnable))) { + MESOSPHERE_RELEASE_LOG("Resume Process ID=%3lu\n", process->GetId()); + } + } + break; default: break; } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 64070e9ce..af1b242b4 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -472,6 +472,12 @@ namespace ams::svc { enum KernelDebugType : u32 { KernelDebugType_Thread = 0, KernelDebugType_ThreadCallStack = 1, + + KernelDebugType_Handle = 3, + + KernelDebugType_Process = 7, + KernelDebugType_SuspendProcess = 8, + KernelDebugType_ResumeProcess = 9, }; enum KernelTraceState : u32 { From 0acd79c8c28130e544f68640987d0e043cb6791c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 10 Dec 2020 01:44:27 -0800 Subject: [PATCH 19/29] kern: implement port debug --- .../include/mesosphere/kern_k_client_port.hpp | 4 + .../include/mesosphere/kern_k_dump_object.hpp | 3 + .../include/mesosphere/kern_k_session.hpp | 2 + .../source/kern_k_dump_object.cpp | 109 ++++++++++++++++++ .../source/svc/kern_svc_kernel_debug.cpp | 7 ++ .../include/vapours/svc/svc_types_common.hpp | 13 ++- 6 files changed, 132 insertions(+), 6 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp index 5000f7626..fd11a4795 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp @@ -42,6 +42,10 @@ namespace ams::kern { constexpr const KPort *GetParent() const { return this->parent; } + ALWAYS_INLINE s32 GetNumSessions() const { return this->num_sessions; } + ALWAYS_INLINE s32 GetPeakSessions() const { return this->peak_sessions; } + ALWAYS_INLINE s32 GetMaxSessions() const { return this->max_sessions; } + bool IsLight() const; /* Overridden virtual functions. */ diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index 4113fff1c..376d22518 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -31,4 +31,7 @@ namespace ams::kern::KDumpObject { void DumpProcess(); void DumpProcess(u64 process_id); + void DumpPort(); + void DumpPort(u64 process_id); + } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp index b67f81e3a..a278391ca 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_session.hpp @@ -71,6 +71,8 @@ namespace ams::kern { KServerSession &GetServerSession() { return this->server; } const KClientSession &GetClientSession() const { return this->client; } const KServerSession &GetServerSession() const { return this->server; } + + const KClientPort *GetParent() const { return this->port; } }; } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 06fe739c7..96f35a196 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -129,6 +129,81 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); } + void DumpPort(const KProcess::ListAccessor &accessor, KProcess *process) { + MESOSPHERE_RELEASE_LOG("Dump Port Process ID=%lu (%s)\n", process->GetId(), process->GetName()); + + const auto end = accessor.end(); + const auto &handle_table = process->GetHandleTable(); + const size_t max_handles = handle_table.GetMaxCount(); + for (size_t i = 0; i < max_handles; ++i) { + /* Get the object + handle. */ + ams::svc::Handle handle = ams::svc::InvalidHandle; + KScopedAutoObject obj = handle_table.GetObjectByIndex(std::addressof(handle), i); + if (obj.IsNull()) { + continue; + } + + /* Process the object as a port. */ + if (auto *server = obj->DynamicCast(); server != nullptr) { + const KClientPort *client = std::addressof(server->GetParent()->GetClientPort()); + const uintptr_t port_name = server->GetParent()->GetName(); + + /* Get the port name. */ + char name[9] = {}; + { + /* Find the client port process. */ + KScopedAutoObject client_port_process; + { + for (auto it = accessor.begin(); it != end && client_port_process.IsNull(); ++it) { + KProcess *cur = static_cast(std::addressof(*it)); + for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { + ams::svc::Handle cur_h = ams::svc::InvalidHandle; + KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); + if (cur_o.IsNotNull()) { + if (cur_o.GetPointerUnsafe() == client) { + client_port_process = cur; + break; + } + } + } + } + } + + /* Read the port name. */ + if (client_port_process.IsNotNull()) { + if (R_FAILED(client_port_process->GetPageTable().CopyMemoryFromLinearToKernel(KProcessAddress(name), 8, port_name, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { + std::memset(name, 0, sizeof(name)); + } + for (size_t i = 0; i < 8 && name[i] != 0; i++) { + if (name[i] > 0x7F) { + std::memset(name, 0, sizeof(name)); + break; + } + } + } + MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Max=%3d Peak=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetMaxSessions(), client->GetPeakSessions()); + + /* Identify any sessions. */ + { + for (auto it = accessor.begin(); it != end && client_port_process.IsNull(); ++it) { + KProcess *cur = static_cast(std::addressof(*it)); + for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { + ams::svc::Handle cur_h = ams::svc::InvalidHandle; + KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); + if (cur_o.IsNull()) { + continue; + } + if (auto *session = cur_o->DynamicCast(); session != nullptr && session->GetParent()->GetParent() == client) { + MESOSPHERE_RELEASE_LOG(" Client %p Server %p %-12s: PID=%3lu\n", session, std::addressof(session->GetParent()->GetServerSession()), cur->GetName(), cur->GetId()); + } + } + } + } + } + } + } + } + } void DumpThread() { @@ -258,4 +333,38 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n"); } + void DumpPort() { + MESOSPHERE_RELEASE_LOG("Dump Port\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpPort(accessor, static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpPort(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Port\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + + /* Lock the list. */ + KProcess::ListAccessor accessor; + DumpPort(accessor, process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + } diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 86f9b5e84..632d7a9cf 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -73,6 +73,13 @@ namespace ams::kern::svc { } } break; + case ams::svc::KernelDebugType_Port: + if (arg0 == static_cast(-1)) { + KDumpObject::DumpPort(); + } else { + KDumpObject::DumpPort(arg0); + } + break; default: break; } diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index af1b242b4..5b4d14e26 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -470,14 +470,15 @@ namespace ams::svc { }; enum KernelDebugType : u32 { - KernelDebugType_Thread = 0, - KernelDebugType_ThreadCallStack = 1, + KernelDebugType_Thread = 0, + KernelDebugType_ThreadCallStack = 1, - KernelDebugType_Handle = 3, + KernelDebugType_Handle = 3, - KernelDebugType_Process = 7, - KernelDebugType_SuspendProcess = 8, - KernelDebugType_ResumeProcess = 9, + KernelDebugType_Process = 7, + KernelDebugType_SuspendProcess = 8, + KernelDebugType_ResumeProcess = 9, + KernelDebugType_Port = 10, }; enum KernelTraceState : u32 { From 1a6e003a5d49e3a70e90936897d36f19b1e984d7 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 10 Dec 2020 03:31:57 -0800 Subject: [PATCH 20/29] kern: add kernel object debug --- .../arch/arm64/kern_k_page_table_impl.hpp | 1 + .../arch/arm64/kern_k_process_page_table.hpp | 12 +- .../arm64/kern_k_supervisor_page_table.hpp | 4 + .../include/mesosphere/kern_k_dump_object.hpp | 2 + .../mesosphere/kern_k_memory_manager.hpp | 14 ++ .../include/mesosphere/kern_k_page_heap.hpp | 1 + .../mesosphere/kern_k_page_table_base.hpp | 17 +- .../include/mesosphere/kern_k_process.hpp | 5 + .../include/mesosphere/kern_k_slab_heap.hpp | 39 +++- .../include/mesosphere/kern_slab_helpers.hpp | 4 + .../arch/arm64/kern_k_page_table_impl.cpp | 23 ++ .../source/init/kern_init_slab_setup.cpp | 4 +- .../source/kern_k_dump_object.cpp | 200 +++++++++++++++++- .../libmesosphere/source/kern_k_page_heap.cpp | 25 +++ .../source/svc/kern_svc_kernel_debug.cpp | 3 + .../include/vapours/svc/svc_types_common.hpp | 2 +- 16 files changed, 341 insertions(+), 15 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp index 95c94dced..b82db110d 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp @@ -112,6 +112,7 @@ namespace ams::kern::arch::arm64 { L1PageTableEntry *Finalize(); void Dump(uintptr_t start, size_t size) const; + size_t CountPageTables() const; bool BeginTraversal(TraversalEntry *out_entry, TraversalContext *out_context, KProcessAddress address) const; bool ContinueTraversal(TraversalEntry *out_entry, TraversalContext *context) const; diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 48a9e8081..33c361c64 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -232,14 +232,18 @@ namespace ams::kern::arch::arm64 { return this->page_table.UnmapPhysicalMemoryUnsafe(address, size); } - void DumpTable() const { - return this->page_table.DumpTable(); - } - void DumpMemoryBlocks() const { return this->page_table.DumpMemoryBlocks(); } + void DumpPageTable() const { + return this->page_table.DumpPageTable(); + } + + size_t CountPageTables() const { + return this->page_table.CountPageTables(); + } + bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { return this->page_table.GetPhysicalAddress(out, address); } diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index 8e795aa7c..3854accf4 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -62,6 +62,10 @@ namespace ams::kern::arch::arm64 { } constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return this->ttbr0_identity[core_id]; } + + size_t CountPageTables() const { + return this->page_table.CountPageTables(); + } }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index 376d22518..ade036e75 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -25,6 +25,8 @@ namespace ams::kern::KDumpObject { void DumpThreadCallStack(); void DumpThreadCallStack(u64 thread_id); + void DumpKernelObject(); + void DumpHandle(); void DumpHandle(u64 process_id); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_memory_manager.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_manager.hpp index 86d133442..30c740eab 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_manager.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_memory_manager.hpp @@ -90,6 +90,8 @@ namespace ams::kern { size_t GetFreeSize() const { return this->heap.GetFreeSize(); } + void DumpFreeList() const { return this->heap.DumpFreeList(); } + constexpr size_t GetPageOffset(KVirtualAddress address) const { return this->heap.GetPageOffset(address); } constexpr size_t GetPageOffsetToEnd(KVirtualAddress address) const { return this->heap.GetPageOffsetToEnd(address); } @@ -247,12 +249,15 @@ namespace ams::kern { size_t GetFreeSize() { size_t total = 0; for (size_t i = 0; i < this->num_managers; i++) { + KScopedLightLock lk(this->pool_locks[this->managers[i].GetPool()]); total += this->managers[i].GetFreeSize(); } return total; } size_t GetFreeSize(Pool pool) { + KScopedLightLock lk(this->pool_locks[pool]); + constexpr Direction GetSizeDirection = Direction_FromFront; size_t total = 0; for (auto *manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr; manager = this->GetNextManager(manager, GetSizeDirection)) { @@ -260,6 +265,15 @@ namespace ams::kern { } return total; } + + void DumpFreeList(Pool pool) { + KScopedLightLock lk(this->pool_locks[pool]); + + constexpr Direction DumpDirection = Direction_FromFront; + for (auto *manager = this->GetFirstManager(pool, DumpDirection); manager != nullptr; manager = this->GetNextManager(manager, DumpDirection)) { + manager->DumpFreeList(); + } + } public: static size_t CalculateManagementOverheadSize(size_t region_size) { return Impl::CalculateManagementOverheadSize(region_size); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_heap.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_heap.hpp index 3f11d6e68..35ac503bd 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_heap.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_heap.hpp @@ -147,6 +147,7 @@ namespace ams::kern { } size_t GetFreeSize() const { return this->GetNumFreePages() * PageSize; } + void DumpFreeList() const; void UpdateUsedSize() { this->used_size = this->heap_size - (this->GetNumFreePages() * PageSize); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index f22d476c8..18e42d97d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -382,9 +382,9 @@ namespace ams::kern { Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size); Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size); - void DumpTable() const { - KScopedLightLock lk(this->general_lock); - this->GetImpl().Dump(GetInteger(this->address_space_start), this->address_space_end - this->address_space_start); + void DumpMemoryBlocksLocked() const { + MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); + this->memory_block_manager.DumpBlocks(); } void DumpMemoryBlocks() const { @@ -392,9 +392,14 @@ namespace ams::kern { this->DumpMemoryBlocksLocked(); } - void DumpMemoryBlocksLocked() const { - MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); - this->memory_block_manager.DumpBlocks(); + void DumpPageTable() const { + KScopedLightLock lk(this->general_lock); + this->GetImpl().Dump(GetInteger(this->address_space_start), this->address_space_end - this->address_space_start); + } + + size_t CountPageTables() const { + KScopedLightLock lk(this->general_lock); + return this->GetImpl().CountPageTables(); } public: KProcessAddress GetAddressSpaceStart() const { return this->address_space_start; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index accb4fe7b..2066325fc 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -305,6 +305,11 @@ namespace ams::kern { } } + const KDynamicPageManager &GetDynamicPageManager() const { return this->dynamic_page_manager; } + const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return this->memory_block_slab_manager; } + const KBlockInfoManager &GetBlockInfoManager() const { return this->block_info_manager; } + const KPageTableManager &GetPageTableManager() const { return this->page_table_manager; } + constexpr KThread *GetRunningThread(s32 core) const { return this->running_threads[core]; } constexpr u64 GetRunningThreadIdleCount(s32 core) const { return this->running_thread_idle_counts[core]; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_slab_heap.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_slab_heap.hpp index 494777700..0dfc84814 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_slab_heap.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_slab_heap.hpp @@ -140,7 +140,21 @@ namespace ams::kern { void *obj = this->GetImpl()->Allocate(); - /* TODO: under some debug define, track the peak for statistics, as N does? */ + /* Track the allocated peak. */ + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + if (AMS_LIKELY(obj != nullptr)) { + static_assert(std::atomic_ref::is_always_lock_free); + std::atomic_ref peak_ref(this->peak); + + const uintptr_t alloc_peak = reinterpret_cast(obj) + this->GetObjectSize(); + uintptr_t cur_peak = this->peak; + do { + if (alloc_peak <= cur_peak) { + break; + } + } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak)); + } + #endif return obj; } @@ -165,6 +179,29 @@ namespace ams::kern { uintptr_t GetSlabHeapAddress() const { return this->start; } + + size_t GetNumRemaining() const { + size_t remaining = 0; + + /* Only calculate the number of remaining objects under debug configuration. */ + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + while (true) { + auto *cur = this->GetImpl()->GetHead(); + remaining = 0; + + while (this->Contains(reinterpret_cast(cur))) { + ++remaining; + cur = cur->next; + } + + if (cur == nullptr) { + break; + } + } + #endif + + return remaining; + } }; template diff --git a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp index e665c182d..ce27e13c5 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp @@ -48,6 +48,8 @@ namespace ams::kern { static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } + + static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; template @@ -116,6 +118,8 @@ namespace ams::kern { static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } + + static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp index f2c8a8bdc..cd5ddb47a 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp @@ -431,5 +431,28 @@ namespace ams::kern::arch::arm64 { } } + size_t KPageTableImpl::CountPageTables() const { + size_t num_tables = 0; + + #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) + { + ++num_tables; + for (size_t l1_index = 0; l1_index < this->num_entries; ++l1_index) { + auto &l1_entry = this->table[l1_index]; + if (l1_entry.IsTable()) { + ++num_tables; + for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) { + auto *l2_entry = GetPointer(GetTableEntry(KMemoryLayout::GetLinearVirtualAddress(l1_entry.GetTable()), l2_index)); + if (l2_entry->IsTable()) { + ++num_tables; + } + } + } + } + } + #endif + + return num_tables; + } } diff --git a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp index 812623a24..804ab0a1e 100644 --- a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp @@ -22,7 +22,7 @@ namespace ams::kern::init { #define FOREACH_SLAB_TYPE(HANDLER, ...) \ HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ - HANDLER(KLinkedListNode, (SLAB_COUNT(KThread) * 17), ## __VA_ARGS__) \ + HANDLER(KLinkedListNode, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \ HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ @@ -77,7 +77,7 @@ namespace ams::kern::init { namespace test { - constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KLinkedListNode) * 17) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo)); + constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + sizeof(KLinkedListNode) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo)); static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize); } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 96f35a196..747829475 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -181,7 +181,7 @@ namespace ams::kern::KDumpObject { } } } - MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Max=%3d Peak=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetMaxSessions(), client->GetPeakSessions()); + MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Peak=%3d Max=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetPeakSessions(), client->GetMaxSessions()); /* Identify any sessions. */ { @@ -268,6 +268,204 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n"); } + void DumpKernelObject() { + MESOSPHERE_LOG("Dump Kernel Object\n"); + + { + /* Static slab heaps. */ + { + #define DUMP_KSLABOBJ(__OBJECT__) \ + MESOSPHERE_RELEASE_LOG(#__OBJECT__ "\n"); \ + MESOSPHERE_RELEASE_LOG(" Cur=%3zu Peak=%3zu Max=%3zu\n", __OBJECT__::GetSlabHeapSize() - __OBJECT__::GetNumRemaining(), __OBJECT__::GetPeakIndex(), __OBJECT__::GetSlabHeapSize()) + + DUMP_KSLABOBJ(KPageBuffer); + DUMP_KSLABOBJ(KEvent); + DUMP_KSLABOBJ(KInterruptEvent); + DUMP_KSLABOBJ(KProcess); + DUMP_KSLABOBJ(KThread); + DUMP_KSLABOBJ(KPort); + DUMP_KSLABOBJ(KSharedMemory); + DUMP_KSLABOBJ(KTransferMemory); + DUMP_KSLABOBJ(KDeviceAddressSpace); + DUMP_KSLABOBJ(KDebug); + DUMP_KSLABOBJ(KSession); + DUMP_KSLABOBJ(KLightSession); + DUMP_KSLABOBJ(KLinkedListNode); + DUMP_KSLABOBJ(KThreadLocalPage); + DUMP_KSLABOBJ(KObjectName); + DUMP_KSLABOBJ(KEventInfo); + DUMP_KSLABOBJ(KSessionRequest); + DUMP_KSLABOBJ(KResourceLimit); + DUMP_KSLABOBJ(KAlpha); + DUMP_KSLABOBJ(KBeta); + + #undef DUMP_KSLABOBJ + + } + MESOSPHERE_RELEASE_LOG("\n"); + + /* Dynamic slab heaps. */ + { + /* Memory block slabs. */ + { + MESOSPHERE_RELEASE_LOG("App Memory Block\n"); + auto &app = Kernel::GetApplicationMemoryBlockManager(); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", app.GetUsed(), app.GetPeak(), app.GetCount()); + MESOSPHERE_RELEASE_LOG("Sys Memory Block\n"); + auto &sys = Kernel::GetSystemMemoryBlockManager(); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", sys.GetUsed(), sys.GetPeak(), sys.GetCount()); + } + + /* KBlockInfo slab. */ + { + MESOSPHERE_RELEASE_LOG("KBlockInfo\n"); + auto &manager = Kernel::GetBlockInfoManager(); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); + } + + /* Page Table slab. */ + { + MESOSPHERE_RELEASE_LOG("Page Table\n"); + auto &manager = Kernel::GetPageTableManager(); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); + } + } + MESOSPHERE_RELEASE_LOG("\n"); + + /* Process resources. */ + { + KProcess::ListAccessor accessor; + + size_t process_pts = 0; + + const auto end = accessor.end(); + for (auto it = accessor.begin(); it != end; ++it) { + KProcess *process = static_cast(std::addressof(*it)); + + /* Count the number of threads. */ + int threads = 0; + { + KThread::ListAccessor thr_accessor; + const auto thr_end = thr_accessor.end(); + for (auto thr_it = thr_accessor.begin(); thr_it != thr_end; ++thr_it) { + KThread *thread = static_cast(std::addressof(*thr_it)); + if (thread->GetOwnerProcess() == process) { + ++threads; + } + } + } + + /* Count the number of events. */ + int events = 0; + { + KEvent::ListAccessor ev_accessor; + const auto ev_end = ev_accessor.end(); + for (auto ev_it = ev_accessor.begin(); ev_it != ev_end; ++ev_it) { + KEvent *event = static_cast(std::addressof(*ev_it)); + if (event->GetOwner() == process) { + ++events; + } + } + } + + size_t pts = process->GetPageTable().CountPageTables(); + process_pts += pts; + + MESOSPHERE_RELEASE_LOG("%-12s: PID=%3lu Thread %4d / Event %4d / PageTable %5zu\n", process->GetName(), process->GetId(), threads, events, pts); + if (process->GetTotalSystemResourceSize() != 0) { + MESOSPHERE_RELEASE_LOG(" System Resource\n"); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetDynamicPageManager().GetUsed(), process->GetDynamicPageManager().GetPeak(), process->GetDynamicPageManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Memory Block\n"); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetMemoryBlockSlabManager().GetUsed(), process->GetMemoryBlockSlabManager().GetPeak(), process->GetMemoryBlockSlabManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Page Table\n"); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetPageTableManager().GetUsed(), process->GetPageTableManager().GetPeak(), process->GetPageTableManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Block Info\n"); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetBlockInfoManager().GetUsed(), process->GetBlockInfoManager().GetPeak(), process->GetBlockInfoManager().GetCount()); + } + } + + MESOSPHERE_RELEASE_LOG("Process Page Table %zu\n", process_pts); + MESOSPHERE_RELEASE_LOG("Kernel Page Table %zu\n", Kernel::GetKernelPageTable().CountPageTables()); + } + MESOSPHERE_RELEASE_LOG("\n"); + + /* Resource limits. */ + { + auto &sys_rl = Kernel::GetSystemResourceLimit(); + + u64 cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_PhysicalMemoryMax); + u64 lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax); + MESOSPHERE_RELEASE_LOG("System ResourceLimit PhysicalMemory 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(lim >> 32), static_cast(lim)); + + cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax); + lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_ThreadCountMax); + MESOSPHERE_RELEASE_LOG("System ResourceLimit Thread %4lu / %4lu\n", cur, lim); + + cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_EventCountMax); + lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_EventCountMax); + MESOSPHERE_RELEASE_LOG("System ResourceLimit Event %4lu / %4lu\n", cur, lim); + + cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_TransferMemoryCountMax); + lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax); + MESOSPHERE_RELEASE_LOG("System ResourceLimit TransferMemory %4lu / %4lu\n", cur, lim); + + cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_SessionCountMax); + lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_SessionCountMax); + MESOSPHERE_RELEASE_LOG("System ResourceLimit Session %4lu / %4lu\n", cur, lim); + + { + KResourceLimit::ListAccessor accessor; + + const auto end = accessor.end(); + for (auto it = accessor.begin(); it != end; ++it) { + KResourceLimit *rl = static_cast(std::addressof(*it)); + cur = rl->GetCurrentValue(ams::svc::LimitableResource_PhysicalMemoryMax); + lim = rl->GetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax); + MESOSPHERE_RELEASE_LOG("ResourceLimit %zu PhysicalMemory 0x%01x_%08x / 0x%01x_%08x\n", rl->GetSlabIndex(), static_cast(cur >> 32), static_cast(cur), static_cast(lim >> 32), static_cast(lim)); + } + } + } + MESOSPHERE_RELEASE_LOG("\n"); + + /* Memory Manager. */ + { + auto &mm = Kernel::GetMemoryManager(); + u64 max = mm.GetSize(); + u64 cur = max - mm.GetFreeSize(); + MESOSPHERE_RELEASE_LOG("Kernel Heap Size 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(max >> 32), static_cast(max)); + MESOSPHERE_RELEASE_LOG("\n"); + + max = mm.GetSize(KMemoryManager::Pool_Application); + cur = max - mm.GetFreeSize(KMemoryManager::Pool_Application); + MESOSPHERE_RELEASE_LOG("Application 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(max >> 32), static_cast(max)); + mm.DumpFreeList(KMemoryManager::Pool_Application); + MESOSPHERE_RELEASE_LOG("\n"); + + max = mm.GetSize(KMemoryManager::Pool_Applet); + cur = max - mm.GetFreeSize(KMemoryManager::Pool_Applet); + MESOSPHERE_RELEASE_LOG("Applet 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(max >> 32), static_cast(max)); + mm.DumpFreeList(KMemoryManager::Pool_Applet); + MESOSPHERE_RELEASE_LOG("\n"); + + max = mm.GetSize(KMemoryManager::Pool_System); + cur = max - mm.GetFreeSize(KMemoryManager::Pool_System); + MESOSPHERE_RELEASE_LOG("System 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(max >> 32), static_cast(max)); + mm.DumpFreeList(KMemoryManager::Pool_System); + MESOSPHERE_RELEASE_LOG("\n"); + + max = mm.GetSize(KMemoryManager::Pool_SystemNonSecure); + cur = max - mm.GetFreeSize(KMemoryManager::Pool_SystemNonSecure); + MESOSPHERE_RELEASE_LOG("SystemNonSecure 0x%01x_%08x / 0x%01x_%08x\n", static_cast(cur >> 32), static_cast(cur), static_cast(max >> 32), static_cast(max)); + mm.DumpFreeList(KMemoryManager::Pool_SystemNonSecure); + MESOSPHERE_RELEASE_LOG("\n"); + } + MESOSPHERE_RELEASE_LOG("\n"); + + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + void DumpHandle() { MESOSPHERE_RELEASE_LOG("Dump Handle\n"); diff --git a/libraries/libmesosphere/source/kern_k_page_heap.cpp b/libraries/libmesosphere/source/kern_k_page_heap.cpp index 6199649e8..428a238e2 100644 --- a/libraries/libmesosphere/source/kern_k_page_heap.cpp +++ b/libraries/libmesosphere/source/kern_k_page_heap.cpp @@ -132,4 +132,29 @@ namespace ams::kern { return util::AlignUp(overhead_size, PageSize); } + void KPageHeap::DumpFreeList() const { + MESOSPHERE_RELEASE_LOG("KPageHeap::DumpFreeList %p\n", this); + + for (size_t i = 0; i < this->num_blocks; ++i) { + const size_t block_size = this->blocks[i].GetSize(); + const char *suffix; + size_t size; + if (block_size >= 1_GB) { + suffix = "GiB"; + size = block_size / 1_GB; + } else if (block_size >= 1_MB) { + suffix = "MiB"; + size = block_size / 1_MB; + } else if (block_size >= 1_KB) { + suffix = "KiB"; + size = block_size / 1_KB; + } else { + suffix = "B"; + size = block_size; + } + + MESOSPHERE_RELEASE_LOG(" %4zu %s block x %zu\n", size, suffix, this->blocks[i].GetNumFreeBlocks()); + } + } + } diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index 632d7a9cf..d16643cd6 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -41,6 +41,9 @@ namespace ams::kern::svc { KDumpObject::DumpThreadCallStack(arg0); } break; + case ams::svc::KernelDebugType_KernelObject: + KDumpObject::DumpKernelObject(); + break; case ams::svc::KernelDebugType_Handle: if (arg0 == static_cast(-1)) { KDumpObject::DumpHandle(); diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index 5b4d14e26..e5f048798 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -472,7 +472,7 @@ namespace ams::svc { enum KernelDebugType : u32 { KernelDebugType_Thread = 0, KernelDebugType_ThreadCallStack = 1, - + KernelDebugType_KernelObject = 2, KernelDebugType_Handle = 3, KernelDebugType_Process = 7, From 6df26d674cec2781f554e170ebcc78885e2b3346 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 10 Dec 2020 04:06:02 -0800 Subject: [PATCH 21/29] kern/sm: fix debug port output --- .../source/kern_k_dump_object.cpp | 29 ++++++++++--------- .../sm/source/impl/sm_service_manager.cpp | 3 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 747829475..4a5d72a25 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -181,21 +181,22 @@ namespace ams::kern::KDumpObject { } } } - MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Peak=%3d Max=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetPeakSessions(), client->GetMaxSessions()); + } - /* Identify any sessions. */ - { - for (auto it = accessor.begin(); it != end && client_port_process.IsNull(); ++it) { - KProcess *cur = static_cast(std::addressof(*it)); - for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { - ams::svc::Handle cur_h = ams::svc::InvalidHandle; - KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); - if (cur_o.IsNull()) { - continue; - } - if (auto *session = cur_o->DynamicCast(); session != nullptr && session->GetParent()->GetParent() == client) { - MESOSPHERE_RELEASE_LOG(" Client %p Server %p %-12s: PID=%3lu\n", session, std::addressof(session->GetParent()->GetServerSession()), cur->GetName(), cur->GetId()); - } + MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Peak=%3d Max=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetPeakSessions(), client->GetMaxSessions()); + + /* Identify any sessions. */ + { + for (auto it = accessor.begin(); it != end; ++it) { + KProcess *cur = static_cast(std::addressof(*it)); + for (size_t j = 0; j < cur->GetHandleTable().GetMaxCount(); ++j) { + ams::svc::Handle cur_h = ams::svc::InvalidHandle; + KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); + if (cur_o.IsNull()) { + continue; + } + if (auto *session = cur_o->DynamicCast(); session != nullptr && session->GetParent()->GetParent() == client) { + MESOSPHERE_RELEASE_LOG(" Client %p Server %p %-12s: PID=%3lu\n", session, std::addressof(session->GetParent()->GetServerSession()), cur->GetName(), cur->GetId()); } } } diff --git a/stratosphere/sm/source/impl/sm_service_manager.cpp b/stratosphere/sm/source/impl/sm_service_manager.cpp index b773ddab4..32542a58d 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.cpp +++ b/stratosphere/sm/source/impl/sm_service_manager.cpp @@ -628,8 +628,7 @@ namespace ams::sm::impl { /* Create mitm handles. */ { os::ManagedHandle hnd, port_hnd, qry_hnd, mitm_qry_hnd; - u64 x = 0; - R_TRY(svcCreatePort(hnd.GetPointer(), port_hnd.GetPointer(), service_info->max_sessions, service_info->is_light, reinterpret_cast(&x))); + R_TRY(svcCreatePort(hnd.GetPointer(), port_hnd.GetPointer(), service_info->max_sessions, service_info->is_light, service_info->name.name)); R_TRY(svcCreateSession(qry_hnd.GetPointer(), mitm_qry_hnd.GetPointer(), 0, 0)); /* Copy to output. */ From be8473cf6548afb9e1aabd18a95d4f866be1e455 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 10 Dec 2020 16:31:47 -0800 Subject: [PATCH 22/29] kern: implement memory debug --- .../arch/arm64/kern_k_process_page_table.hpp | 6 ++ .../arm64/kern_k_supervisor_page_table.hpp | 8 ++ .../include/mesosphere/kern_k_dump_object.hpp | 4 + .../mesosphere/kern_k_page_table_base.hpp | 7 ++ .../include/mesosphere/kern_k_process.hpp | 2 + .../source/kern_k_dump_object.cpp | 82 +++++++++++++++++++ .../source/kern_k_memory_block_manager.cpp | 2 +- .../source/kern_k_page_table_base.cpp | 33 ++++++++ .../source/svc/kern_svc_kernel_debug.cpp | 9 ++ .../include/vapours/svc/svc_types_common.hpp | 4 +- 10 files changed, 155 insertions(+), 2 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 33c361c64..ffeac1848 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -271,6 +271,12 @@ namespace ams::kern::arch::arm64 { size_t GetNormalMemorySize() const { return this->page_table.GetNormalMemorySize(); } + size_t GetCodeSize() const { return this->page_table.GetCodeSize(); } + size_t GetCodeDataSize() const { return this->page_table.GetCodeDataSize(); } + + size_t GetAliasCodeSize() const { return this->page_table.GetAliasCodeSize(); } + size_t GetAliasCodeDataSize() const { return this->page_table.GetAliasCodeDataSize(); } + u32 GetAllocateOption() const { return this->page_table.GetAllocateOption(); } KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const { diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp index 3854accf4..5cd8b0d90 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp @@ -63,6 +63,14 @@ namespace ams::kern::arch::arm64 { constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return this->ttbr0_identity[core_id]; } + void DumpMemoryBlocks() const { + return this->page_table.DumpMemoryBlocks(); + } + + void DumpPageTable() const { + return this->page_table.DumpPageTable(); + } + size_t CountPageTables() const { return this->page_table.CountPageTables(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp index ade036e75..5892534ec 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp @@ -30,6 +30,10 @@ namespace ams::kern::KDumpObject { void DumpHandle(); void DumpHandle(u64 process_id); + void DumpKernelMemory(); + void DumpMemory(); + void DumpMemory(u64 process_id); + void DumpProcess(); void DumpProcess(u64 process_id); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 18e42d97d..0f44b77b0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -301,6 +301,8 @@ namespace ams::kern { Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state); Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send); void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm); + + size_t GetSize(KMemoryState state) const; public: bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const { return this->GetImpl().GetPhysicalAddress(out, virt_addr); @@ -423,6 +425,11 @@ namespace ams::kern { return (this->current_heap_end - this->heap_region_start) + this->mapped_physical_memory_size; } + size_t GetCodeSize() const; + size_t GetCodeDataSize() const; + size_t GetAliasCodeSize() const; + size_t GetAliasCodeDataSize() const; + u32 GetAllocateOption() const { return this->allocate_option; } public: static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 2066325fc..f58fe89ce 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -170,6 +170,8 @@ namespace ams::kern { constexpr KProcessAddress GetEntryPoint() const { return this->code_address; } + constexpr size_t GetMainStackSize() const { return this->main_thread_stack_size; } + constexpr KMemoryManager::Pool GetMemoryPool() const { return this->memory_pool; } constexpr u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 4a5d72a25..9fa4484a2 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -125,6 +125,47 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n\n"); } + void DumpMemory(KProcess *process) { + const auto process_id = process->GetId(); + MESOSPHERE_RELEASE_LOG("Process ID=%3lu (%s)\n", process_id, process->GetName()); + + /* Dump the memory blocks. */ + process->GetPageTable().DumpMemoryBlocks(); + + /* Collect information about memory totals. */ + const size_t code = process->GetPageTable().GetCodeSize(); + const size_t code_data = process->GetPageTable().GetCodeDataSize(); + const size_t alias_code = process->GetPageTable().GetAliasCodeSize(); + const size_t alias_code_data = process->GetPageTable().GetAliasCodeDataSize(); + const size_t normal = process->GetPageTable().GetNormalMemorySize(); + const size_t main_stack = process->GetMainStackSize(); + + size_t shared = 0; + { + KSharedMemory::ListAccessor accessor; + const auto end = accessor.end(); + for (auto it = accessor.begin(); it != end; ++it) { + KSharedMemory *shared_mem = static_cast(std::addressof(*it)); + if (shared_mem->GetOwnerProcessId() == process_id) { + shared += shared_mem->GetSize(); + } + } + } + + /* Dump the totals. */ + MESOSPHERE_RELEASE_LOG("---\n"); + MESOSPHERE_RELEASE_LOG("Code %8zu KB\n", code / 1_KB); + MESOSPHERE_RELEASE_LOG("CodeData %8zu KB\n", code_data / 1_KB); + MESOSPHERE_RELEASE_LOG("AliasCode %8zu KB\n", alias_code / 1_KB); + MESOSPHERE_RELEASE_LOG("AliasCodeData %8zu KB\n", alias_code_data / 1_KB); + MESOSPHERE_RELEASE_LOG("Heap %8zu KB\n", normal / 1_KB); + MESOSPHERE_RELEASE_LOG("SharedMemory %8zu KB\n", shared / 1_KB); + MESOSPHERE_RELEASE_LOG("InitialStack %8zu KB\n", main_stack / 1_KB); + MESOSPHERE_RELEASE_LOG("---\n"); + MESOSPHERE_RELEASE_LOG("TOTAL %8zu KB\n", (code + code_data + alias_code + alias_code_data + normal + main_stack + shared) / 1_KB); + MESOSPHERE_RELEASE_LOG("\n\n"); + } + void DumpProcess(KProcess *process) { MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); } @@ -501,6 +542,47 @@ namespace ams::kern::KDumpObject { MESOSPHERE_RELEASE_LOG("\n"); } + void DumpKernelMemory() { + MESOSPHERE_RELEASE_LOG("Dump Kernel Memory Info\n"); + + { + Kernel::GetKernelPageTable().DumpMemoryBlocks(); + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpMemory() { + MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); + + { + /* Lock the list. */ + KProcess::ListAccessor accessor; + const auto end = accessor.end(); + + /* Dump each process. */ + for (auto it = accessor.begin(); it != end; ++it) { + DumpMemory(static_cast(std::addressof(*it))); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + + void DumpMemory(u64 process_id) { + MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); + + { + /* Find and dump the target process. */ + if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { + ON_SCOPE_EXIT { process->Close(); }; + DumpMemory(process); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); + } + void DumpProcess() { MESOSPHERE_RELEASE_LOG("Dump Process\n"); diff --git a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp index c6bcc2147..8cbbe4be7 100644 --- a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp @@ -81,7 +81,7 @@ namespace ams::kern { const char d = (info.attribute & KMemoryAttribute_DeviceShared) ? 'D' : '-'; const char u = (info.attribute & KMemoryAttribute_Uncached) ? 'U' : '-'; - MESOSPHERE_LOG("%p - %p (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.ipc_lock_count, info.device_use_count); + MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.ipc_lock_count, info.device_use_count); } } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 289b04fe5..b7805d94f 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -1018,6 +1018,39 @@ namespace ams::kern { return address; } + size_t KPageTableBase::GetSize(KMemoryState state) const { + /* Lock the table. */ + KScopedLightLock lk(this->general_lock); + + /* Iterate, counting blocks with the desired state. */ + size_t total_size = 0; + for (KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(this->address_space_start); it != this->memory_block_manager.end(); ++it) { + /* Get the memory info. */ + const KMemoryInfo info = it->GetMemoryInfo(); + if (info.GetState() == state) { + total_size += info.GetSize(); + } + } + + return total_size; + } + + size_t KPageTableBase::GetCodeSize() const { + return this->GetSize(KMemoryState_Code); + } + + size_t KPageTableBase::GetCodeDataSize() const { + return this->GetSize(KMemoryState_CodeData); + } + + size_t KPageTableBase::GetAliasCodeSize() const { + return this->GetSize(KMemoryState_AliasCode); + } + + size_t KPageTableBase::GetAliasCodeDataSize() const { + return this->GetSize(KMemoryState_AliasCodeData); + } + Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, KMemoryPermission perm) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp index d16643cd6..a94b35894 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp @@ -51,6 +51,15 @@ namespace ams::kern::svc { KDumpObject::DumpHandle(arg0); } break; + case ams::svc::KernelDebugType_Memory: + if (arg0 == static_cast(-2)) { + KDumpObject::DumpKernelMemory(); + } else if (arg0 == static_cast(-1)) { + KDumpObject::DumpMemory(); + } else { + KDumpObject::DumpMemory(arg0); + } + break; case ams::svc::KernelDebugType_Process: if (arg0 == static_cast(-1)) { KDumpObject::DumpProcess(); diff --git a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp index e5f048798..b533d4e03 100644 --- a/libraries/libvapours/include/vapours/svc/svc_types_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_types_common.hpp @@ -474,7 +474,9 @@ namespace ams::svc { KernelDebugType_ThreadCallStack = 1, KernelDebugType_KernelObject = 2, KernelDebugType_Handle = 3, - + KernelDebugType_Memory = 4, + KernelDebugType_PageTable = 5, + KernelDebugType_CpuUtilization = 6, KernelDebugType_Process = 7, KernelDebugType_SuspendProcess = 8, KernelDebugType_ResumeProcess = 9, From 7fb902d8fbdcdb1f631d3f5eedc568eadf7e3d9d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 02:59:09 -0800 Subject: [PATCH 23/29] kern: update for 11.0.1 --- .../kern_k_synchronization_object.hpp | 5 ++- .../source/kern_k_synchronization_object.cpp | 39 +++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp index 98dd5fe6e..f6a0da9ef 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp @@ -30,9 +30,10 @@ namespace ams::kern { KThread *thread; }; private: - ThreadListNode *thread_list_root; + ThreadListNode *thread_list_head; + ThreadListNode *thread_list_tail; protected: - constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list_root() { MESOSPHERE_ASSERT_THIS(); } + constexpr ALWAYS_INLINE explicit KSynchronizationObject() : KAutoObjectWithList(), thread_list_head(), thread_list_tail() { MESOSPHERE_ASSERT_THIS(); } virtual ~KSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); } virtual void OnFinalizeSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); } diff --git a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp index 774d0a60a..5fdefbf4b 100644 --- a/libraries/libmesosphere/source/kern_k_synchronization_object.cpp +++ b/libraries/libmesosphere/source/kern_k_synchronization_object.cpp @@ -81,8 +81,15 @@ namespace ams::kern { /* Add the waiters. */ for (auto i = 0; i < num_objects; ++i) { thread_nodes[i].thread = thread; - thread_nodes[i].next = objects[i]->thread_list_root; - objects[i]->thread_list_root = std::addressof(thread_nodes[i]); + thread_nodes[i].next = nullptr; + + if (objects[i]->thread_list_tail == nullptr) { + objects[i]->thread_list_head = std::addressof(thread_nodes[i]); + } else { + objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); + } + + objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); } /* Mark the thread as waiting. */ @@ -111,11 +118,22 @@ namespace ams::kern { for (auto i = 0; i < num_objects; ++i) { /* Unlink the object from the list. */ - ThreadListNode **link = std::addressof(objects[i]->thread_list_root); - while (*link != std::addressof(thread_nodes[i])) { - link = std::addressof((*link)->next); + ThreadListNode *prev_ptr = reinterpret_cast(std::addressof(objects[i]->thread_list_head)); + ThreadListNode *prev_val = nullptr; + ThreadListNode *prev, *tail_prev; + + do { + prev = prev_ptr; + prev_ptr = prev_ptr->next; + tail_prev = prev_val; + prev_val = prev_ptr; + } while (prev_ptr != std::addressof(thread_nodes[i])); + + if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { + objects[i]->thread_list_tail = tail_prev; } - *link = thread_nodes[i].next; + + prev->next = thread_nodes[i].next; if (objects[i] == synced_obj) { sync_index = i; @@ -139,7 +157,7 @@ namespace ams::kern { } /* Iterate over each thread. */ - for (auto *cur_node = this->thread_list_root; cur_node != nullptr; cur_node = cur_node->next) { + for (auto *cur_node = this->thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { KThread *thread = cur_node->thread; if (thread->GetState() == KThread::ThreadState_Waiting) { thread->SetSyncedObject(this, result); @@ -158,8 +176,7 @@ namespace ams::kern { MESOSPHERE_RELEASE_LOG("Threads waiting on %p:\n", this); - bool has_waiters = false; - for (auto *cur_node = this->thread_list_root; cur_node != nullptr; cur_node = cur_node->next) { + for (auto *cur_node = this->thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { KThread *thread = cur_node->thread; if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { @@ -167,12 +184,10 @@ namespace ams::kern { } else { MESOSPHERE_RELEASE_LOG(" %p tid=%ld (Kernel)\n", thread, thread->GetId()); } - - has_waiters = true; } /* If we didn't have any waiters, print so. */ - if (!has_waiters) { + if (this->thread_list_head != nullptr) { MESOSPHERE_RELEASE_LOG(" None\n"); } } From 734122f20a0cdc070f6d8d2a72a75340c7b9390b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:06:17 -0800 Subject: [PATCH 24/29] fusee: update for 11.0.1 --- fusee/fusee-secondary/src/kernel_patches.c | 38 +++++++++++++++++++ fusee/fusee-secondary/src/nxboot.c | 1 + .../include/stratosphere/hos/hos_types.hpp | 1 + .../include/vapours/ams/ams_target_firmware.h | 4 +- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fusee/fusee-secondary/src/kernel_patches.c b/fusee/fusee-secondary/src/kernel_patches.c index 2f2d89416..8e82de0a7 100644 --- a/fusee/fusee-secondary/src/kernel_patches.c +++ b/fusee/fusee-secondary/src/kernel_patches.c @@ -906,6 +906,35 @@ static const kernel_patch_t g_kernel_patches_1100[] = { } }; +static const kernel_patch_t g_kernel_patches_1101[] = { + { /* Send Message Process ID Patch. */ + .pattern_size = 0x1C, + .pattern = MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send), + .pattern_hook_offset = 0x0, + .payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1100, proc_id_send))/sizeof(instruction_t), + .branch_back_offset = 0x10, + .payload = MAKE_KERNEL_PATCH_NAME(1100, proc_id_send) + }, + { /* Receive Message Process ID Patch. */ + .pattern_size = 0x1C, + .pattern = MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv), + .pattern_hook_offset = 0x0, + .payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv))/sizeof(instruction_t), + .branch_back_offset = 0x10, + .payload = MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv) + }, + { /* svcControlCodeMemory Patch. */ + .payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1100, svc_control_codememory))/sizeof(instruction_t), + .payload = MAKE_KERNEL_PATCH_NAME(1100, svc_control_codememory), + .patch_offset = 0x2FD04, + }, + { /* System Memory Increase Patch. */ + .payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1100, system_memory_increase))/sizeof(instruction_t), + .payload = MAKE_KERNEL_PATCH_NAME(1100, system_memory_increase), + .patch_offset = 0x490C4, + } +}; + #define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers, /* Kernel Infos. */ @@ -1000,6 +1029,15 @@ static const kernel_info_t g_kernel_infos[] = { .embedded_ini_ptr = 0x180, .free_code_space_offset = 0x49EE8, KERNEL_PATCHES(1100) + }, + { /* 11.0.1. */ + .hash = {68B972B79755875E24958D990A77ABF1C5C1328067F0A2EC9CEFC322E342C04D, }, + .hash_offset = 0x1C4, + .hash_size = 0x69000 - 0x1C4, + .embedded_ini_offset = 0x69000, + .embedded_ini_ptr = 0x180, + .free_code_space_offset = 0x49EE8, + KERNEL_PATCHES(1101) } }; diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 415ec9f16..7400aa6b9 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -254,6 +254,7 @@ static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){ #define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0) if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_11_0_0) { + CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1); CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0); } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) { CHECK_NCA("26325de4db3909e0ef2379787c7e671d", 10_2_0); diff --git a/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp b/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp index e7017d824..7e9ce33d0 100644 --- a/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp @@ -59,6 +59,7 @@ namespace ams::hos { Version_10_1_0 = ::ams::TargetFirmware_10_1_0, Version_10_2_0 = ::ams::TargetFirmware_10_2_0, Version_11_0_0 = ::ams::TargetFirmware_11_0_0, + Version_11_0_1 = ::ams::TargetFirmware_11_0_1, Version_Current = ::ams::TargetFirmware_Current, diff --git a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h index fbb8b0f3b..cd6e4dc5f 100644 --- a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h +++ b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h @@ -57,8 +57,9 @@ #define ATMOSPHERE_TARGET_FIRMWARE_10_1_1 ATMOSPHERE_TARGET_FIRMWARE(10, 1, 1) #define ATMOSPHERE_TARGET_FIRMWARE_10_2_0 ATMOSPHERE_TARGET_FIRMWARE(10, 2, 0) #define ATMOSPHERE_TARGET_FIRMWARE_11_0_0 ATMOSPHERE_TARGET_FIRMWARE(11, 0, 0) +#define ATMOSPHERE_TARGET_FIRMWARE_11_0_1 ATMOSPHERE_TARGET_FIRMWARE(11, 0, 1) -#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_11_0_0 +#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_11_0_1 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0) #define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT @@ -108,6 +109,7 @@ namespace ams { TargetFirmware_10_1_1 = ATMOSPHERE_TARGET_FIRMWARE_10_1_1, TargetFirmware_10_2_0 = ATMOSPHERE_TARGET_FIRMWARE_10_2_0, TargetFirmware_11_0_0 = ATMOSPHERE_TARGET_FIRMWARE_11_0_0, + TargetFirmware_11_0_1 = ATMOSPHERE_TARGET_FIRMWARE_11_0_1, TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT, From 14a415c4b2feea4fb75482b19821977cf4cba758 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:06:47 -0800 Subject: [PATCH 25/29] ams: bump version to 0.16.1 --- libraries/libvapours/include/vapours/ams/ams_api_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/libvapours/include/vapours/ams/ams_api_version.h b/libraries/libvapours/include/vapours/ams/ams_api_version.h index a57ea0362..ff484afe2 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 16 -#define ATMOSPHERE_RELEASE_VERSION_MICRO 0 +#define ATMOSPHERE_RELEASE_VERSION_MICRO 1 #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 11 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0 -#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1 From 63e3c02688839b7336e186078dbe274a0405ba5a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:18:21 -0800 Subject: [PATCH 26/29] fusee/exo: support dynamic control of invert flag for logging --- config_templates/exosphere.ini | 4 +++ exosphere/program/source/secmon_setup.cpp | 2 +- fusee/fusee-secondary/src/exocfg.h | 6 ++++- fusee/fusee-secondary/src/kernel_patches.c | 2 +- fusee/fusee-secondary/src/nxboot.c | 9 +++++++ .../libexosphere/include/exosphere/log.hpp | 2 +- ...ecmon_configuration_context.arch.arm64.hpp | 4 +++ .../secmon/secmon_monitor_context.hpp | 8 ++++-- libraries/libexosphere/source/log/log_api.cpp | 25 +++---------------- 9 files changed, 35 insertions(+), 27 deletions(-) diff --git a/config_templates/exosphere.ini b/config_templates/exosphere.ini index b60a3f31c..e8dc82377 100644 --- a/config_templates/exosphere.ini +++ b/config_templates/exosphere.ini @@ -43,6 +43,9 @@ # Desc: Controls the baud rate exosphere will set up for logging. # NOTE: 0 is treated as equivalent to 115200. +# Key: log_inverted, default: 0. +# Desc: Controls whether the logging uart port is inverted. + [exosphere] debugmode=1 debugmode_user=0 @@ -53,3 +56,4 @@ blank_prodinfo_emummc=0 allow_writing_to_cal_sysmmc=0 log_port=0 log_baud_rate=115200 +log_inverted=0 diff --git a/exosphere/program/source/secmon_setup.cpp b/exosphere/program/source/secmon_setup.cpp index 836786252..5eabdbdd6 100644 --- a/exosphere/program/source/secmon_setup.cpp +++ b/exosphere/program/source/secmon_setup.cpp @@ -960,7 +960,7 @@ namespace ams::secmon { } void SetupLogForBoot() { - log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate()); + log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags()); log::SendText("OHAYO\n", 6); log::Flush(); } diff --git a/fusee/fusee-secondary/src/exocfg.h b/fusee/fusee-secondary/src/exocfg.h index 7aac28bb5..36cca04dc 100644 --- a/fusee/fusee-secondary/src/exocfg.h +++ b/fusee/fusee-secondary/src/exocfg.h @@ -34,13 +34,15 @@ #define EXOSPHERE_FLAG_BLANK_PRODINFO (1 << 5u) #define EXOSPHERE_FLAG_ALLOW_WRITING_TO_CAL_SYSMMC (1 << 6u) +#define EXOSPHERE_LOG_FLAG_INVERTED (1 << 0u) + typedef struct { uint32_t magic; uint32_t target_firmware; uint32_t flags[2]; uint16_t lcd_vendor; - uint8_t reserved0; uint8_t log_port; + uint8_t log_flags; uint32_t log_baud_rate; uint32_t reserved1[2]; exo_emummc_config_t emummc_cfg; @@ -60,6 +62,7 @@ _Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), #define EXOSPHERE_ALLOW_WRITING_TO_CAL_SYSMMC_KEY "allow_writing_to_cal_sysmmc" #define EXOSPHERE_LOG_PORT_KEY "log_port" #define EXOSPHERE_LOG_BAUD_RATE_KEY "log_baud_rate" +#define EXOSPHERE_LOG_INVERTED_KEY "log_inverted" typedef struct { int debugmode; @@ -71,6 +74,7 @@ typedef struct { int allow_writing_to_cal_sysmmc; int log_port; int log_baud_rate; + int log_inverted; } exosphere_parse_cfg_t; #endif diff --git a/fusee/fusee-secondary/src/kernel_patches.c b/fusee/fusee-secondary/src/kernel_patches.c index 8e82de0a7..6678f8008 100644 --- a/fusee/fusee-secondary/src/kernel_patches.c +++ b/fusee/fusee-secondary/src/kernel_patches.c @@ -1031,7 +1031,7 @@ static const kernel_info_t g_kernel_infos[] = { KERNEL_PATCHES(1100) }, { /* 11.0.1. */ - .hash = {68B972B79755875E24958D990A77ABF1C5C1328067F0A2EC9CEFC322E342C04D, }, + .hash = {0x68, 0xB9, 0x72, 0xB7, 0x97, 0x55, 0x87, 0x5E, 0x24, 0x95, 0x8D, 0x99, 0x0A, 0x77, 0xAB, 0xF1, 0xC5, 0xC1, 0x32, 0x80, 0x67, 0xF0, 0xA2, 0xEC, 0x9C, 0xEF, 0xC3, 0x22, 0xE3, 0x42, 0xC0, 0x4D, }, .hash_offset = 0x1C4, .hash_size = 0x69000 - 0x1C4, .embedded_ini_offset = 0x69000, diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 7400aa6b9..a53c6522b 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -210,6 +210,13 @@ static int exosphere_ini_handler(void *user, const char *section, const char *na } else { parse_cfg->log_baud_rate = 115200; } + } else if (strcmp(name, EXOSPHERE_LOG_INVERTED_KEY) == 0) { + sscanf(value, "%d", &tmp); + if (tmp == 1) { + parse_cfg->log_inverted = 1; + } else if (tmp == 0) { + parse_cfg->log_inverted = 0; + } } else { return 0; } @@ -495,6 +502,7 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke .allow_writing_to_cal_sysmmc = 0, .log_port = 0, .log_baud_rate = 115200, + .log_inverted = 0, }; /* If we have an ini to read, parse it. */ @@ -517,6 +525,7 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke exo_cfg.log_port = parse_cfg.log_port; exo_cfg.log_baud_rate = parse_cfg.log_baud_rate; + if (parse_cfg.log_inverted) exo_cfg.log_flags |= EXOSPHERE_LOG_FLAG_INVERTED; if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) { fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n"); diff --git a/libraries/libexosphere/include/exosphere/log.hpp b/libraries/libexosphere/include/exosphere/log.hpp index cecf8d156..2afd8e4a1 100644 --- a/libraries/libexosphere/include/exosphere/log.hpp +++ b/libraries/libexosphere/include/exosphere/log.hpp @@ -35,7 +35,7 @@ namespace ams::log { #endif void Initialize(); - void Initialize(uart::Port port, u32 baud_rate); + void Initialize(uart::Port port, u32 baud_rate, u32 flags); void Finalize(); void Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp index aa231787f..7e554676d 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -120,6 +120,10 @@ namespace ams::secmon { return GetSecmonConfiguration().GetLogPort(); } + ALWAYS_INLINE u8 GetLogFlags() { + return GetSecmonConfiguration().GetLogFlags(); + } + ALWAYS_INLINE u32 GetLogBaudRate() { return GetSecmonConfiguration().GetLogBaudRate(); } diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp index f53a633d0..6c974b1c7 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp @@ -40,8 +40,8 @@ namespace ams::secmon { ams::TargetFirmware target_firmware; u32 flags[2]; u16 lcd_vendor; - u8 reserved0; u8 log_port; + u8 log_flags; u32 log_baud_rate; u32 reserved1[2]; EmummcConfiguration emummc_cfg; @@ -60,7 +60,8 @@ namespace ams::secmon { u8 log_port; u32 flags[2]; u16 lcd_vendor; - u16 reserved0; + u8 log_flags; + u8 reserved0; u32 log_baud_rate; u32 reserved1[(0x80 - 0x1C) / sizeof(u32)]; @@ -70,6 +71,7 @@ namespace ams::secmon { this->flags[1] = storage.flags[1]; this->lcd_vendor = storage.lcd_vendor; this->log_port = storage.log_port; + this->log_flags = storage.log_flags; this->log_baud_rate = storage.log_baud_rate != 0 ? storage.log_baud_rate : 115200; } @@ -85,6 +87,7 @@ namespace ams::secmon { constexpr fuse::SocType GetSocType() const { return static_cast(this->soc_type); } constexpr fuse::HardwareState GetHardwareState() const { return static_cast(this->hardware_state); } constexpr uart::Port GetLogPort() const { return static_cast(this->log_port); } + constexpr u8 GetLogFlags() const { return this->log_flags; } constexpr u16 GetLcdVendor() const { return this->lcd_vendor; } @@ -113,6 +116,7 @@ namespace ams::secmon { .log_port = uart::Port_ReservedDebug, .flags = { SecureMonitorConfigurationFlag_Default, SecureMonitorConfigurationFlag_None }, .lcd_vendor = {}, + .log_flags = {}, .reserved0 = {}, .log_baud_rate = 115200, .reserved1 = {}, diff --git a/libraries/libexosphere/source/log/log_api.cpp b/libraries/libexosphere/source/log/log_api.cpp index 5ce2831c2..62b40ab04 100644 --- a/libraries/libexosphere/source/log/log_api.cpp +++ b/libraries/libexosphere/source/log/log_api.cpp @@ -20,28 +20,11 @@ namespace ams::log { namespace { constexpr inline uart::Port DefaultLogPort = uart::Port_ReservedDebug; + constexpr inline u32 DefaultLogFlags = static_cast(uart::Flag_None); constexpr inline int DefaultBaudRate = 115200; constinit uart::Port g_log_port = DefaultLogPort; constinit bool g_initialized_uart = false; - ALWAYS_INLINE u32 GetPortFlags(uart::Port port) { - switch (port) { - case uart::Port_ReservedDebug: - /* Logging to the debug port. */ - /* Don't invert transactions. */ - return uart::Flag_None; - case uart::Port_LeftJoyCon: - /* Logging to left joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - case uart::Port_RightJoyCon: - /* Logging to right joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - ALWAYS_INLINE void SetupUartClock(uart::Port port) { /* The debug port must always be set up, for compatibility with official hos. */ pinmux::SetupUartA(); @@ -64,15 +47,15 @@ namespace ams::log { } void Initialize() { - return Initialize(DefaultLogPort, DefaultBaudRate); + return Initialize(DefaultLogPort, DefaultBaudRate, DefaultLogFlags); } - void Initialize(uart::Port port, u32 baud_rate) { + void Initialize(uart::Port port, u32 baud_rate, u32 flags) { /* Initialize pinmux and clock for the target uart port. */ SetupUartClock(port); /* Initialize the target uart port. */ - uart::Initialize(port, baud_rate, GetPortFlags(port)); + uart::Initialize(port, baud_rate, flags); /* Note that we've initialized. */ g_log_port = port; From d8ae1d873c5433fde4d738e8d1311c144e4d5e56 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:22:28 -0800 Subject: [PATCH 27/29] ams: update changelog for 0.16.1 --- docs/changelog.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 67eda6326..87d381617 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,16 @@ # Changelog +## 0.16.1 ++ Support was added for 11.0.1. + + `mesosphère` was updated to reflect the latest official kernel behavior. + + A new svc::InfoType added in 11.0.0 was implemented (it wasn't discovered before 0.16.0 released). + + The new Control Flow Integrity (CFI) logic added in 11.0.0 kernel was implemented. ++ `fs` logic was refactored and cleaned up to reflect some newer sysmodule behavioral and structural changes. ++ `exosphère` was updated to allow dynamic control of what uart port is used for logging. + + This can be controlled by editing the `log_port`, `log_baud_rate`, and `log_inverted` fields in `exosphere.ini`. ++ `mesosphère` was updated to improve debugging capabilities (). + + This is still a work in progress, but developers may be interested. ++ A bug was fixed that caused `fatal` to fatal error if the fatal process was already being debugged. ++ Several issues were fixed, and usability and stability were improved. ## 0.16.0 + Support was added for 11.0.0. + `exosphère` was updated to reflect the latest official secure monitor behavior. From 17c8c390fc84d059b89f563a8fae6936649d0d45 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:48:34 -0800 Subject: [PATCH 28/29] kern: fix building debug config --- .../libmesosphere/source/kern_k_memory_block_manager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp index 8cbbe4be7..2a45306ad 100644 --- a/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_block_manager.cpp @@ -70,10 +70,10 @@ namespace ams::kern { } void DumpMemoryInfo(const KMemoryInfo &info) { - const char *state = GetMemoryStateName(info.state); - const char *perm = GetMemoryPermissionString(info); - const void *start = reinterpret_cast(info.GetAddress()); - const void *end = reinterpret_cast(info.GetLastAddress()); + const char *state = GetMemoryStateName(info.state); + const char *perm = GetMemoryPermissionString(info); + const uintptr_t start = info.GetAddress(); + const uintptr_t end = info.GetLastAddress(); const size_t kb = info.GetSize() / 1_KB; const char l = (info.attribute & KMemoryAttribute_Locked) ? 'L' : '-'; From ca2cc5e179265648a055cd11e26c769765d32149 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 11 Dec 2020 03:49:45 -0800 Subject: [PATCH 29/29] git subrepo push libraries subrepo: subdir: "libraries" merged: "5a18bea6" upstream: origin: "https://github.com/Atmosphere-NX/Atmosphere-libs" branch: "master" commit: "5a18bea6" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" --- libraries/.gitrepo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/.gitrepo b/libraries/.gitrepo index aa9cd1291..d04a7ab3d 100644 --- a/libraries/.gitrepo +++ b/libraries/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/Atmosphere-NX/Atmosphere-libs branch = master - commit = 2c3ccef17e9b267a5d9d232f1aba689f2c591b95 - parent = d2f48d5e36cb2ba4e8cc014238457bd75df81797 + commit = 5a18bea64545105c52d642d7789029b5ca875864 + parent = 17c8c390fc84d059b89f563a8fae6936649d0d45 method = merge cmdver = 0.4.1