From e4e278bb3df7dad44748d76c7c3ae6a886e29e5f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 18 Jan 2021 06:18:14 -0800 Subject: [PATCH] util::unique_lock, update loader to new sf semantics --- .../fssrv_filesystem_interface_adapter.hpp | 10 +- .../fssrv_storage_interface_adapter.hpp | 2 +- .../fssrv_filesystem_interface_adapter.cpp | 8 +- .../fssystem/fssystem_key_slot_cache.hpp | 10 +- libraries/libvapours/include/vapours/util.hpp | 1 + .../include/vapours/util/util_mutex_utils.hpp | 141 ++++++++++++++++++ .../loader/source/ldr_loader_service.hpp | 2 +- stratosphere/loader/source/ldr_main.cpp | 125 +++++++++++++--- .../loader/source/ldr_process_creation.cpp | 2 +- 9 files changed, 262 insertions(+), 39 deletions(-) create mode 100644 libraries/libvapours/include/vapours/util/util_mutex_utils.hpp diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp index 79243f49f..8acf9c2f1 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp @@ -42,9 +42,9 @@ namespace ams::fssrv::impl { private: ams::sf::SharedPointer parent_filesystem; std::unique_ptr base_file; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; public: - FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema); + FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); ~FileInterfaceAdapter(); private: void InvalidateCache(); @@ -64,9 +64,9 @@ namespace ams::fssrv::impl { private: ams::sf::SharedPointer parent_filesystem; std::unique_ptr base_dir; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; public: - DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema); + DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); ~DirectoryInterfaceAdapter(); public: /* Command API */ @@ -79,7 +79,7 @@ namespace ams::fssrv::impl { NON_COPYABLE(FileSystemInterfaceAdapter); private: std::shared_ptr base_fs; - std::unique_lock mount_count_semaphore; + util::unique_lock mount_count_semaphore; os::ReadWriteLock invalidation_lock; bool open_count_limited; bool deep_retry_enabled = false; diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp index c1a74b42f..7f442da3f 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp @@ -32,7 +32,7 @@ namespace ams::fssrv::impl { private: /* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */ std::shared_ptr base_storage; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; os::ReadWriteLock invalidation_lock; /* TODO: DataStorageContext. */ bool deep_retry_enabled = false; diff --git a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp index 70800f9f3..f465b79dc 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp @@ -19,7 +19,7 @@ namespace ams::fssrv::impl { - FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema) + FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) : parent_filesystem(parent, true), base_file(std::move(file)), open_count_semaphore(std::move(sema)) { /* ... */ @@ -89,7 +89,7 @@ namespace ams::fssrv::impl { return ResultSuccess(); } - DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema) + DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) : parent_filesystem(parent, true), base_dir(std::move(dir)), open_count_semaphore(std::move(sema)) { /* ... */ @@ -236,7 +236,7 @@ namespace ams::fssrv::impl { Result FileSystemInterfaceAdapter::OpenFile(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { auto read_lock = this->AcquireCacheInvalidationReadLock(); - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; if (this->open_count_limited) { /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ AMS_ABORT_UNLESS(false); @@ -264,7 +264,7 @@ namespace ams::fssrv::impl { Result FileSystemInterfaceAdapter::OpenDirectory(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { auto read_lock = this->AcquireCacheInvalidationReadLock(); - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; if (this->open_count_limited) { /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ AMS_ABORT_UNLESS(false); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp b/libraries/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp index 89cad629e..6b4f92345 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp @@ -22,10 +22,10 @@ namespace ams::fssystem { NON_COPYABLE(KeySlotCacheAccessor); NON_MOVEABLE(KeySlotCacheAccessor); private: - std::unique_lock lk; + util::unique_lock lk; const s32 slot_index; public: - KeySlotCacheAccessor(s32 idx, std::unique_lock &&l) : lk(std::move(l)), slot_index(idx) { /* ... */ } + KeySlotCacheAccessor(s32 idx, util::unique_lock &&l) : lk(std::move(l)), slot_index(idx) { /* ... */ } s32 GetKeySlotIndex() const { return this->slot_index; } }; @@ -79,7 +79,7 @@ namespace ams::fssystem { } Result Find(std::unique_ptr *out, const void *key, size_t key_size, s32 key2) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); KeySlotCacheEntryList *lists[2] = { std::addressof(this->high_priority_mru_list), std::addressof(this->low_priority_mru_list) }; for (auto list : lists) { @@ -100,12 +100,12 @@ namespace ams::fssystem { } void AddEntry(KeySlotCacheEntry *entry) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); this->low_priority_mru_list.push_front(*entry); } private: Result AllocateFromLru(std::unique_ptr *out, KeySlotCacheEntryList &dst_list, const void *key, size_t key_size, s32 key2) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); KeySlotCacheEntryList &src_list = this->low_priority_mru_list.empty() ? this->high_priority_mru_list : this->low_priority_mru_list; AMS_ASSERT(!src_list.empty()); diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index 7260a93e3..0a7702eda 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/util/util_mutex_utils.hpp b/libraries/libvapours/include/vapours/util/util_mutex_utils.hpp new file mode 100644 index 000000000..780c994c9 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_mutex_utils.hpp @@ -0,0 +1,141 @@ +/* + * 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::util { + + template + class unique_lock { + NON_COPYABLE(unique_lock); + public: + using mutex_type = _Mutex; + private: + mutex_type *m_mutex; + bool m_owns; + public: + unique_lock() noexcept : m_mutex(nullptr), m_owns(false) { /* ... */ } + + explicit unique_lock(mutex_type &m) noexcept : m_mutex(std::addressof(m)), m_owns(false) { + this->lock(); + m_owns = true; + } + + unique_lock(mutex_type &m, std::defer_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(false) { /* ... */ } + unique_lock(mutex_type &m, std::try_to_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock()) { /* ... */ } + unique_lock(mutex_type &m, std::adopt_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(true) { /* ... */ } + + template + unique_lock(mutex_type &m, const std::chrono::time_point<_Clock, _Duration> &time) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock_until(time)) { /* ... */ } + + template + unique_lock(mutex_type &m, const std::chrono::duration<_Rep, _Period> &time) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock_for(time)) { /* ... */ } + + ~unique_lock() noexcept { + if (m_owns) { + this->unlock(); + } + } + + unique_lock(unique_lock &&rhs) noexcept : m_mutex(rhs.m_mutex), m_owns(rhs.m_owns) { + rhs.m_mutex = nullptr; + rhs.m_owns = false; + } + + unique_lock &operator=(unique_lock &&rhs) noexcept { + if (m_owns) { + this->unlock(); + } + + unique_lock(std::move(rhs)).swap(*this); + + rhs.m_mutex = nullptr; + rhs.m_owns = false; + + return *this; + } + + void lock() noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + + m_mutex->lock(); + m_owns = true; + } + + bool try_lock() noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + + m_owns = m_mutex->try_lock(); + return m_owns; + } + + template + bool try_lock_until(const std::chrono::time_point<_Clock, _Duration> &time) noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + m_owns = m_mutex->try_lock_until(time); + return m_owns; + } + + template + bool try_lock_for(const std::chrono::duration<_Rep, _Period> &time) noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + m_owns = m_mutex->try_lock_for(time); + return m_owns; + } + + + void unlock() noexcept { + AMS_ABORT_UNLESS(m_owns); + if (m_mutex) { + m_mutex->unlock(); + m_owns = false; + } + } + + void swap(unique_lock &rhs) noexcept { + std::swap(m_mutex, rhs.m_mutex); + std::swap(m_owns, rhs.m_owns); + } + + mutex_type *release() noexcept { + mutex_type *ret = m_mutex; + m_mutex = nullptr; + m_owns = false; + return ret; + } + + bool owns_lock() const noexcept { + return m_owns; + } + + explicit operator bool() const noexcept { + return this->owns_lock(); + } + + mutex_type *mutex() const noexcept { + return m_mutex; + } + }; + + template + inline void swap(unique_lock<_Mutex> &lhs, unique_lock<_Mutex> &rhs) noexcept { return lhs.swap(rhs); } + +} diff --git a/stratosphere/loader/source/ldr_loader_service.hpp b/stratosphere/loader/source/ldr_loader_service.hpp index b525fda29..89605fbb4 100644 --- a/stratosphere/loader/source/ldr_loader_service.hpp +++ b/stratosphere/loader/source/ldr_loader_service.hpp @@ -18,7 +18,7 @@ namespace ams::ldr { - class LoaderService final { + class LoaderService { public: /* Official commands. */ Result CreateProcess(sf::OutMoveHandle proc_h, PinId id, u32 flags, sf::CopyHandle reslimit_h); diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index 73de30843..18009d109 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -23,7 +23,7 @@ extern "C" { u32 __nx_applet_type = AppletType_None; u32 __nx_fs_num_sessions = 1; - #define INNER_HEAP_SIZE 0x8000 + #define INNER_HEAP_SIZE 0x0 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -35,6 +35,9 @@ extern "C" { alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize]; u64 __nx_exception_stack_size = sizeof(__nx_exception_stack); void __libnx_exception_handler(ThreadExceptionDump *ctx); + + void *__libnx_thread_alloc(size_t size); + void __libnx_thread_free(void *mem); } namespace ams { @@ -55,6 +58,78 @@ void __libnx_exception_handler(ThreadExceptionDump *ctx) { ams::CrashHandler(ctx); } +namespace ams::ldr { + + namespace { + + constinit u8 g_heap_memory[16_KB]; + lmem::HeapHandle g_server_heap_handle; + constinit ams::sf::ExpHeapAllocator g_server_allocator; + + void *Allocate(size_t size) { + return lmem::AllocateFromExpHeap(g_server_heap_handle, size); + } + + void Deallocate(void *p, size_t size) { + return lmem::FreeToExpHeap(g_server_heap_handle, p); + } + + void InitializeHeap() { + g_server_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_None); + g_server_allocator.Attach(g_server_heap_handle); + } + + } + + namespace { + + struct ServerOptions { + static constexpr size_t PointerBufferSize = 0x400; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; + + /* ldr:pm, ldr:shel, ldr:dmnt. */ + enum PortIndex { + PortIndex_ProcessManager, + PortIndex_Shell, + PortIndex_DebugMonitor, + PortIndex_Count, + }; + + constexpr sm::ServiceName ProcessManagerServiceName = sm::ServiceName::Encode("ldr:pm"); + constexpr size_t ProcessManagerMaxSessions = 1; + + constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("ldr:shel"); + constexpr size_t ShellMaxSessions = 3; + + constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ldr:dmnt"); + constexpr size_t DebugMonitorMaxSessions = 3; + + constinit sf::UnmanagedServiceObject g_pm_service; + constinit sf::UnmanagedServiceObject g_shell_service; + constinit sf::UnmanagedServiceObject g_dmnt_service; + + constexpr size_t MaxSessions = ProcessManagerMaxSessions + ShellMaxSessions + DebugMonitorMaxSessions + 1; + + using ServerManager = ams::sf::hipc::ServerManager; + + ServerManager g_server_manager; + + void RegisterServiceSessions() { + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_pm_service.GetShared(), ProcessManagerServiceName, ProcessManagerMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_shell_service.GetShared(), ShellServiceName, ShellMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_dmnt_service.GetShared(), DebugMonitorServiceName, DebugMonitorMaxSessions)); + } + + void LoopProcess() { + g_server_manager.LoopProcess(); + } + + } + +} + void __libnx_initheap(void) { void* addr = nx_inner_heap; size_t size = nx_inner_heap_size; @@ -65,11 +140,15 @@ void __libnx_initheap(void) { fake_heap_start = (char*)addr; fake_heap_end = (char*)addr + size; + + ams::ldr::InitializeHeap(); } void __appInit(void) { hos::InitializeForStratosphere(); + fs::SetAllocator(ldr::Allocate, ldr::Deallocate); + /* Initialize services we need. */ sm::DoWithSession([&]() { R_ABORT_UNLESS(fsInitialize()); @@ -89,28 +168,32 @@ void __appExit(void) { fsExit(); } -namespace { +namespace ams { - struct ServerOptions { - static constexpr size_t PointerBufferSize = 0x400; - static constexpr size_t MaxDomains = 0; - static constexpr size_t MaxDomainObjects = 0; - }; + void *Malloc(size_t size) { + AMS_ABORT("ams::Malloc was called"); + } - constexpr sm::ServiceName ProcessManagerServiceName = sm::ServiceName::Encode("ldr:pm"); - constexpr size_t ProcessManagerMaxSessions = 1; + void Free(void *ptr) { + AMS_ABORT("ams::Free was called"); + } - constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("ldr:shel"); - constexpr size_t ShellMaxSessions = 3; +} - constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ldr:dmnt"); - constexpr size_t DebugMonitorMaxSessions = 3; +void *operator new(size_t size) { + return ldr::Allocate(size); +} - /* ldr:pm, ldr:shel, ldr:dmnt. */ - constexpr size_t NumServers = 3; - constexpr size_t MaxSessions = ProcessManagerMaxSessions + ShellMaxSessions + DebugMonitorMaxSessions + 1; - sf::hipc::ServerManager g_server_manager; +void operator delete(void *p) { + return ldr::Deallocate(p, 0); +} +void *__libnx_thread_alloc(size_t size) { + AMS_ABORT("__libnx_thread_alloc was called"); +} + +void __libnx_thread_free(void *mem) { + AMS_ABORT("__libnx_thread_free was called"); } int main(int argc, char **argv) @@ -128,13 +211,11 @@ int main(int argc, char **argv) ldr::SetDevelopmentForAntiDowngradeCheck(spl::IsDevelopment()); ldr::SetDevelopmentForAcidSignatureCheck(spl::IsDevelopment()); - /* Add services to manager. */ - R_ABORT_UNLESS((g_server_manager.RegisterServer(ProcessManagerServiceName, ProcessManagerMaxSessions))); - R_ABORT_UNLESS((g_server_manager.RegisterServer(ShellServiceName, ShellMaxSessions))); - R_ABORT_UNLESS((g_server_manager.RegisterServer(DebugMonitorServiceName, DebugMonitorMaxSessions))); + /* Register the loader services. */ + ldr::RegisterServiceSessions(); /* Loop forever, servicing our services. */ - g_server_manager.LoopProcess(); + ldr::LoopProcess(); return 0; } diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 844e19651..a6a7e2b05 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -654,7 +654,7 @@ namespace ams::ldr { fssystem::DestroyExternalCode(loc.program_id); /* Note that we've created the program. */ - SetLaunchedProgram(loc.program_id); + SetLaunchedBootProgram(loc.program_id); /* Move the process handle to output. */ *out = info.process_handle.Move();