From 82f3416799ede9ece1e785976f33ca750baf88e3 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 1 Oct 2021 00:36:18 -0700 Subject: [PATCH] os: implement SharedMemory, update AslrSpaceManager --- .../include/stratosphere/os.hpp | 1 + .../stratosphere/os/os_shared_memory.hpp | 86 ++++++++++ .../stratosphere/os/os_shared_memory_api.hpp | 38 +++++ .../os/os_shared_memory_types.hpp | 42 +++++ .../server/htcs_socket_service_object.cpp | 4 +- .../os/impl/os_address_space_allocator.cpp | 107 ++++++++---- .../os/impl/os_address_space_allocator.hpp | 54 ++++++ ...dress_space_allocator_forbidden_region.hpp | 26 +++ ...ddress_space_allocator_impl.os.horizon.hpp | 25 ++- .../impl/os_address_space_allocator_types.hpp | 44 ----- .../os_aslr_space_manager_impl.os.horizon.hpp | 24 ++- .../os/impl/os_aslr_space_manager_types.hpp | 68 ++++++-- .../os/impl/os_io_region_impl.os.horizon.cpp | 47 +++--- .../source/os/impl/os_resource_manager.hpp | 2 +- .../source/os/impl/os_shared_memory_impl.hpp | 30 ++++ .../impl/os_shared_memory_impl.os.horizon.cpp | 84 ++++++++++ .../os/impl/os_transfer_memory_impl.hpp | 2 +- .../os_transfer_memory_impl.os.horizon.cpp | 37 +++-- .../source/os/os_shared_memory.cpp | 157 ++++++++++++++++++ .../source/os/os_transfer_memory.cpp | 55 +----- 20 files changed, 737 insertions(+), 196 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_shared_memory.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_shared_memory_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_shared_memory_types.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_address_space_allocator_forbidden_region.hpp delete mode 100644 libraries/libstratosphere/source/os/impl/os_address_space_allocator_types.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_shared_memory_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/os/os_shared_memory.cpp diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 6e94c659e..a323b91e6 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_shared_memory.hpp b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory.hpp new file mode 100644 index 000000000..535086b6c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory.hpp @@ -0,0 +1,86 @@ +/* + * 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 + +namespace ams::os { + + class SharedMemory { + NON_COPYABLE(SharedMemory); + NON_MOVEABLE(SharedMemory); + private: + SharedMemoryType m_shared_memory; + public: + constexpr SharedMemory() : m_shared_memory{ .state = SharedMemoryType::State_NotInitialized } { + /* ... */ + } + + SharedMemory(size_t size, MemoryPermission my_perm, MemoryPermission other_perm) { + R_ABORT_UNLESS(CreateSharedMemory(std::addressof(m_shared_memory), size, my_perm, other_perm)); + } + + SharedMemory(size_t size, Handle handle, bool managed) { + this->Attach(size, handle, managed); + } + + ~SharedMemory() { + if (m_shared_memory.state == SharedMemoryType::State_NotInitialized) { + return; + } + DestroySharedMemory(std::addressof(m_shared_memory)); + } + + void Attach(size_t size, Handle handle, bool managed) { + return AttachSharedMemory(std::addressof(m_shared_memory), size, handle, managed); + } + + void *Map(MemoryPermission perm) { + return MapSharedMemory(std::addressof(m_shared_memory), perm); + } + + void Unmap() { + return UnmapSharedMemory(std::addressof(m_shared_memory)); + } + + void *GetMappedAddress() const { + return GetSharedMemoryAddress(std::addressof(m_shared_memory)); + } + + size_t GetSize() const { + return GetSharedMemorySize(std::addressof(m_shared_memory)); + } + + Handle GetHandle() const { + return GetSharedMemoryHandle(std::addressof(m_shared_memory)); + } + + operator SharedMemoryType &() { + return m_shared_memory; + } + + operator const SharedMemoryType &() const { + return m_shared_memory; + } + + SharedMemoryType *GetBase() { + return std::addressof(m_shared_memory); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_api.hpp new file mode 100644 index 000000000..6924759f8 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_api.hpp @@ -0,0 +1,38 @@ +/* + * 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::os { + + struct SharedMemoryType; + + Result CreateSharedMemory(SharedMemoryType *shared_memory, size_t size, MemoryPermission my_perm, MemoryPermission other_perm); + + void AttachSharedMemory(SharedMemoryType *shared_memory, size_t size, Handle handle, bool managed); + + void DestroySharedMemory(SharedMemoryType *shared_memory); + + void *MapSharedMemory(SharedMemoryType *shared_memory, MemoryPermission perm); + void UnmapSharedMemory(SharedMemoryType *shared_memory); + + void *GetSharedMemoryAddress(const SharedMemoryType *shared_memory); + size_t GetSharedMemorySize(const SharedMemoryType *shared_memory); + Handle GetSharedMemoryHandle(const SharedMemoryType *shared_memory); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_types.hpp new file mode 100644 index 000000000..c482a8800 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_shared_memory_types.hpp @@ -0,0 +1,42 @@ +/* + * 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::os { + + struct SharedMemoryType { + enum State { + State_NotInitialized = 0, + State_Initialized = 1, + State_Mapped = 2, + }; + + u8 state; + bool handle_managed; + bool allocated; + + void *address; + size_t size; + Handle handle; + + mutable impl::InternalCriticalSectionStorage cs_shared_memory; + }; + static_assert(std::is_trivial::value); + +} diff --git a/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp b/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp index bb0619cda..89d6b6cf0 100644 --- a/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp +++ b/libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp @@ -170,7 +170,7 @@ namespace ams::htcs::server { /* Attach the transfer memory. */ os::TransferMemoryType tmem; - R_ABORT_UNLESS(os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetValue(), true)); + os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetValue(), true); ON_SCOPE_EXIT { os::DestroyTransferMemory(std::addressof(tmem)); }; /* Map the transfer memory. */ @@ -201,7 +201,7 @@ namespace ams::htcs::server { /* Attach the transfer memory. */ os::TransferMemoryType tmem; - R_ABORT_UNLESS(os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetValue(), true)); + os::AttachTransferMemory(std::addressof(tmem), static_cast(aligned_size), mem_handle.GetValue(), true); ON_SCOPE_EXIT { os::DestroyTransferMemory(std::addressof(tmem)); }; /* Map the transfer memory. */ diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp index 7209bc96b..89a988e3f 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp @@ -14,73 +14,114 @@ * along with this program. If not, see . */ #include -#include "os_address_space_allocator_types.hpp" +#include "os_address_space_allocator.hpp" #include "os_rng_manager.hpp" namespace ams::os::impl { - AddressSpaceAllocator::AddressSpaceAllocator(uintptr_t sa, uintptr_t ea, size_t gsz) : cs() { - /* Check preconditions. */ - AMS_ASSERT(sa >= gsz); - AMS_ASSERT(ea + gsz >= ea); + template + AddressSpaceAllocatorBase::AddressSpaceAllocatorBase(u64 start_address, u64 end_address, SizeType guard_size, const AddressSpaceAllocatorForbiddenRegion *forbidden_regions, size_t num_forbidden_regions) : m_critical_section() { + /* Check pre-conditions. */ + AMS_ASSERT(start_address >= guard_size); + AMS_ASSERT(end_address + guard_size >= end_address); - this->guard_page_count = util::DivideUp(gsz, MemoryPageSize); - this->start_page = sa / MemoryPageSize; - this->end_page = (ea / MemoryPageSize) + this->guard_page_count; + /* Set member variables. */ + m_guard_page_count = util::DivideUp(guard_size, MemoryPageSize); + m_start_page = start_address / MemoryPageSize; + m_end_page = (end_address / MemoryPageSize) + m_guard_page_count; + + /* Check forbidden region count. */ + AMS_ASSERT(num_forbidden_regions <= MaxForbiddenRegions); + + /* Set forbidden regions. */ + for (size_t i = 0; i < num_forbidden_regions; ++i) { + if (const auto ®ion = forbidden_regions[i]; region.size > 0) { + /* Check region is valid. */ + AMS_ASSERT(util::IsAligned(region.address, MemoryPageSize)); + AMS_ASSERT(util::IsAligned(region.size, MemoryPageSize)); + AMS_ASSERT((region.address / MemoryPageSize) >= m_guard_page_count); + AMS_ASSERT(region.address < region.address + region.size); + + /* Set region. */ + const auto idx = m_forbidden_region_count++; + m_forbidden_region_start_pages[idx] = (region.address / MemoryPageSize) - m_guard_page_count; + m_forbidden_region_end_pages[idx] = ((region.address + region.size) / MemoryPageSize) + m_guard_page_count; + } + } } - bool AddressSpaceAllocator::GetNextNonOverlappedNodeUnsafe(uintptr_t page, size_t page_num) { - AMS_ASSERT(page < (page + page_num)); - - return CheckFreeSpace(page * MemoryPageSize, page_num * MemoryPageSize); + template + bool AddressSpaceAllocatorBase::CheckGuardSpace(AddressType address, SizeType size, SizeType guard_size) { + return this->CheckFreeSpace(address - guard_size, guard_size) && this->CheckFreeSpace(address + size, guard_size); } - void *AddressSpaceAllocator::AllocateSpace(size_t size, size_t align) { + template + bool AddressSpaceAllocatorBase::GetNextNonOverlappedNodeUnsafe(AddressType page, SizeType page_count) { + /* Check pre-conditions. */ + AMS_ASSERT(page < page + page_count); + + return this->CheckFreeSpace(page * MemoryPageSize, page_count * MemoryPageSize); + } + + template + AddressType AddressSpaceAllocatorBase::AllocateSpace(SizeType size, SizeType align, SizeType align_offset) { /* Check pre-conditions. */ AMS_ASSERT(align > 0); + AMS_ASSERT((align_offset & ~(align - 1)) == 0); + AMS_ASSERT(util::IsAligned(align_offset, MemoryPageSize)); + AMS_ASSERT(util::IsAligned(align, MemoryPageSize)); /* Determine the page count. */ - const size_t page_count = util::DivideUp(size, MemoryPageSize); + const SizeType page_count = util::DivideUp(size, MemoryPageSize); - /* Determine the alignment pages. */ - AMS_ASSERT(util::IsAligned(align, MemoryPageSize)); - const size_t align_page_count = align / MemoryPageSize; + /* Determine alignment page counts. */ + const SizeType align_offset_page_count = align_offset / MemoryPageSize; + const SizeType align_page_count = align / MemoryPageSize; - /* Check the page count. */ - if (page_count > this->end_page - this->guard_page_count) { - return nullptr; + /* Check page counts. */ + if (page_count + align_offset_page_count > m_end_page - m_guard_page_count) { + return 0; } /* Determine the range to look in. */ - const uintptr_t rand_start = util::DivideUp(this->start_page + this->guard_page_count, align_page_count); - const uintptr_t rand_end = (this->end_page - page_count - this->guard_page_count) / align_page_count; + const AddressType rand_start = (align_offset_page_count <= m_start_page + m_guard_page_count) ? util::DivideUp(m_start_page + m_guard_page_count - align_offset_page_count, align_page_count) : 0; + const AddressType rand_end = (m_end_page - page_count - align_offset_page_count - m_guard_page_count) / align_page_count; /* Check that we can find a space. */ if (rand_start > rand_end) { - return nullptr; + return 0; } - /* Try to find space up to 512 times. */ + /* Try to find a space up to 512 times. */ for (size_t i = 0; i < 512; ++i) { /* Acquire exclusive access before doing calculations. */ - std::scoped_lock lk(this->cs); + std::scoped_lock lk(m_critical_section); /* Determine a random page. */ - const uintptr_t target = ((GetRngManager().GenerateRandomU64() % (rand_end - rand_start + 1)) + rand_start) * align_page_count; - AMS_ASSERT(this->start_page <= target - this->guard_page_count && target + page_count + this->guard_page_count <= this->end_page); + const AddressType target = (((GetRngManager().GenerateRandomU64() % (rand_end - rand_start + 1)) + rand_start) * align_page_count) + align_offset_page_count; + AMS_ASSERT(m_start_page <= target - m_guard_page_count && target + page_count + m_guard_page_count <= m_end_page); + + /* Check that the page is not forbidden. */ + bool forbidden = false; + for (size_t j = 0; j < m_forbidden_region_count; ++j) { + if (m_forbidden_region_start_pages[j] < target + page_count && target < m_forbidden_region_end_pages[j]) { + forbidden = true; + break; + } + } /* If the page is valid, use it. */ - if (GetNextNonOverlappedNodeUnsafe(target - this->guard_page_count, page_count + 2 * this->guard_page_count)) { - return reinterpret_cast(target * MemoryPageSize); + if (!forbidden && this->GetNextNonOverlappedNodeUnsafe(target - m_guard_page_count, page_count + 2 * m_guard_page_count)) { + return target * MemoryPageSize; } } /* We failed to find space. */ - return nullptr; + return 0; } - bool AddressSpaceAllocator::CheckGuardSpace(uintptr_t address, size_t size, size_t guard_size) { - return CheckFreeSpace(address - guard_size, guard_size) && CheckFreeSpace(address + size, guard_size); - } + /* Instantiate template. */ + /* TODO: instantiate on 32-bit? */ + template class AddressSpaceAllocatorBase; } diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp new file mode 100644 index 000000000..54a023065 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp @@ -0,0 +1,54 @@ +/* + * 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 "os_address_space_allocator_forbidden_region.hpp" + +namespace ams::os::impl { + + template + class AddressSpaceAllocatorBase { + NON_COPYABLE(AddressSpaceAllocatorBase); + NON_MOVEABLE(AddressSpaceAllocatorBase); + private: + static constexpr size_t MaxForbiddenRegions = 2; + private: + InternalCriticalSection m_critical_section; + AddressType m_start_page; + AddressType m_end_page; + SizeType m_guard_page_count; + AddressType m_forbidden_region_start_pages[MaxForbiddenRegions]; + AddressType m_forbidden_region_end_pages[MaxForbiddenRegions]; + size_t m_forbidden_region_count; + public: + AddressSpaceAllocatorBase(u64 start_address, u64 end_address, SizeType guard_size, const AddressSpaceAllocatorForbiddenRegion *forbidden_regions, size_t num_forbidden_regions); + + AddressType AllocateSpace(SizeType size, SizeType align, SizeType align_offset); + + bool CheckGuardSpace(AddressType address, SizeType size, SizeType guard_size); + private: + bool GetNextNonOverlappedNodeUnsafe(AddressType page, SizeType page_count); + public: + virtual bool CheckFreeSpace(AddressType address, SizeType size) = 0; + }; + +} + +#ifdef ATMOSPHERE_OS_HORIZON + #include "os_address_space_allocator_impl.os.horizon.hpp" +#else + #error "Unknown OS for AddressSpaceAllocator" +#endif diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_forbidden_region.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_forbidden_region.hpp new file mode 100644 index 000000000..878ff15af --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_forbidden_region.hpp @@ -0,0 +1,26 @@ +/* + * 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::os::impl { + + struct AddressSpaceAllocatorForbiddenRegion { + u64 address; + u64 size; + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.os.horizon.hpp index 3c4e072a4..eddb32c7e 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.os.horizon.hpp @@ -18,15 +18,22 @@ namespace ams::os::impl { - inline bool CheckFreeSpace(uintptr_t address, size_t size) { - /* Query the memory. */ - svc::MemoryInfo memory_info; - svc::PageInfo page_info; - const auto result = svc::QueryMemory(std::addressof(memory_info), std::addressof(page_info), address); - R_ASSERT(result); - AMS_UNUSED(result); + class AddressSpaceAllocator final : public AddressSpaceAllocatorBase { + private: + using Base = AddressSpaceAllocatorBase; + public: + using Base::Base; + public: + virtual bool CheckFreeSpace(uintptr_t address, size_t size) override { + /* Query the memory. */ + svc::MemoryInfo memory_info; + svc::PageInfo page_info; + const auto result = svc::QueryMemory(std::addressof(memory_info), std::addressof(page_info), address); + R_ASSERT(result); + AMS_UNUSED(result); - return memory_info.state == svc::MemoryState_Free && address + size <= memory_info.addr + memory_info.size; - } + return memory_info.state == svc::MemoryState_Free && address + size <= memory_info.addr + memory_info.size; + } + }; } diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_types.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_types.hpp deleted file mode 100644 index ff602b115..000000000 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_types.hpp +++ /dev/null @@ -1,44 +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 - -#ifdef ATMOSPHERE_OS_HORIZON - #include "os_address_space_allocator_impl.os.horizon.hpp" -#else - #error "Unknown OS for AddressSpaceAllocatorImpl" -#endif - -namespace ams::os::impl { - - class AddressSpaceAllocator { - NON_COPYABLE(AddressSpaceAllocator); - NON_MOVEABLE(AddressSpaceAllocator); - private: - InternalCriticalSection cs; - uintptr_t start_page; - uintptr_t end_page; - size_t guard_page_count; - private: - bool GetNextNonOverlappedNodeUnsafe(uintptr_t page, size_t page_num); - public: - AddressSpaceAllocator(uintptr_t sa, uintptr_t ea, size_t gsz); - - void *AllocateSpace(size_t size, size_t align); - bool CheckGuardSpace(uintptr_t address, size_t size, size_t guard_size); - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.horizon.hpp index 76bcbd06a..ca00154c2 100644 --- a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.horizon.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include "os_address_space_allocator_forbidden_region.hpp" namespace ams::os::impl { @@ -28,22 +29,39 @@ namespace ams::os::impl { static constexpr u64 AslrSize64BitDeprecated = 0x0078000000ul; static constexpr u64 AslrBase64Bit = 0x0008000000ul; static constexpr u64 AslrSize64Bit = 0x7FF8000000ul; + + static constexpr size_t ForbiddenRegionCount = 2; private: static u64 GetAslrInfo(svc::InfoType type) { u64 value; R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), type, svc::PseudoHandle::CurrentProcess, 0)); + static_assert(std::same_as); AMS_ASSERT(value <= std::numeric_limits::max()); + return static_cast(value & std::numeric_limits::max()); } + private: + AddressSpaceAllocatorForbiddenRegion m_forbidden_regions[ForbiddenRegionCount]; public: - constexpr AslrSpaceManagerHorizonImpl() = default; + AslrSpaceManagerHorizonImpl() { + m_forbidden_regions[0] = { .address = GetHeapSpaceBeginAddress(), .size = GetHeapSpaceSize() }; + m_forbidden_regions[1] = { .address = GetAliasSpaceBeginAddress(), .size = GetAliasSpaceSize() }; + } + + const AddressSpaceAllocatorForbiddenRegion *GetForbiddenRegions() const { + return m_forbidden_regions; + } + + static size_t GetForbiddenRegionCount() { + return ForbiddenRegionCount; + } static u64 GetHeapSpaceBeginAddress() { return GetAslrInfo(svc::InfoType_HeapRegionAddress); } - static u64 GetHeapSpaceBeginSize() { + static u64 GetHeapSpaceSize() { return GetAslrInfo(svc::InfoType_HeapRegionSize); } @@ -51,7 +69,7 @@ namespace ams::os::impl { return GetAslrInfo(svc::InfoType_AliasRegionAddress); } - static u64 GetAliasSpaceBeginSize() { + static u64 GetAliasSpaceSize() { return GetAslrInfo(svc::InfoType_AliasRegionSize); } diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp index 19a51a9f2..eeb49cb39 100644 --- a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp @@ -15,8 +15,7 @@ */ #pragma once #include - -#include "os_address_space_allocator_types.hpp" +#include "os_address_space_allocator.hpp" #ifdef ATMOSPHERE_OS_HORIZON #include "os_aslr_space_manager_impl.os.horizon.hpp" @@ -29,26 +28,67 @@ namespace ams::os::impl { constexpr inline size_t AslrSpaceLargeAlign = 2_MB; constexpr inline size_t AslrSpaceGuardSize = 4 * MemoryPageSize; - class AslrSpaceManager { - NON_COPYABLE(AslrSpaceManager); - NON_MOVEABLE(AslrSpaceManager); + template + class AslrSpaceManagerTemplate { + NON_COPYABLE(AslrSpaceManagerTemplate); + NON_MOVEABLE(AslrSpaceManagerTemplate); private: - AddressSpaceAllocator allocator; - AslrSpaceManagerImpl impl; + Impl m_impl; + Allocator m_allocator; public: - AslrSpaceManager() : allocator(impl.GetAslrSpaceBeginAddress(), impl.GetAslrSpaceEndAddress(), AslrSpaceGuardSize) { /* ... */ } + AslrSpaceManagerTemplate() : m_impl(), m_allocator(m_impl.GetAslrSpaceBeginAddress(), m_impl.GetAslrSpaceEndAddress(), AslrSpaceGuardSize, m_impl.GetForbiddenRegions(), m_impl.GetForbiddenRegionCount()) { + /* ... */ + } - void *AllocateSpace(size_t size) { - void *address = this->allocator.AllocateSpace(size, AslrSpaceLargeAlign); - if (address == nullptr) { - address = this->allocator.AllocateSpace(size, MemoryPageSize); + uintptr_t AllocateSpace(size_t size) { + /* Try to allocate a large-aligned space, if we can. */ + if (size >= AslrSpaceLargeAlign) { + if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, 0); large_align != 0) { + return large_align; + } } - return address; + + /* Allocate a page-aligned space. */ + return m_allocator.AllocateSpace(size, MemoryPageSize, 0); } bool CheckGuardSpace(uintptr_t address, size_t size) { - return this->allocator.CheckGuardSpace(address, size, AslrSpaceGuardSize); + return m_allocator.CheckGuardSpace(address, size, AslrSpaceGuardSize); + } + + template + Result MapAtRandomAddress(uintptr_t *out, size_t size, MapFunction map_function, UnmapFunction unmap_function) { + /* Try to map up to 64 times. */ + for (int i = 0; i < 64; ++i) { + /* Reserve space to map the memory. */ + const uintptr_t map_address = this->AllocateSpace(size); + if (map_address == 0) { + break; + } + + /* Try to map. */ + R_TRY_CATCH(map_function(map_address, size)) { + /* If we failed to map at the address, retry. */ + R_CATCH(os::ResultInvalidCurrentMemoryState) { continue; } + } R_END_TRY_CATCH; + + /* Check guard space. */ + if (!this->CheckGuardSpace(map_address, size)) { + /* We don't have guard space, so unmap. */ + unmap_function(map_address, size); + continue; + } + + /* We mapped successfully. */ + *out = map_address; + return ResultSuccess(); + } + + /* We failed to map. */ + return os::ResultOutOfAddressSpace(); } }; + using AslrSpaceManager = AslrSpaceManagerTemplate; + } diff --git a/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp index a68bc22d0..039ebd3e8 100644 --- a/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp @@ -57,37 +57,28 @@ namespace ams::os::impl { /* Convert permission. */ const auto svc_perm = ConvertToSvcMemoryPermission(perm); - /* NOTE: It is unknown what algorithm Nintendo uses for mapping, so we're using */ - /* the transfer memory algorithm for now. */ + /* Map at a random address. */ + uintptr_t mapped_address; + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + [handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result { + R_TRY_CATCH(svc::MapIoRegion(handle, map_address, map_size, svc_perm)) { + /* TODO: What's the correct result for these? */ + // R_CONVERT(svc::ResultInvalidHandle, os::ResultInvalidHandle()) + // R_CONVERT(svc::ResultInvalidSize, os::Result???()) + // R_CONVERT(svc::ResultInvalidState, os::Result???()) + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; - /* Try to map up to 64 times. */ - for (int i = 0; i < 64; ++i) { - /* Reserve space to map the memory. */ - void *map_address = impl::GetAslrSpaceManager().AllocateSpace(size); - R_UNLESS(map_address != nullptr, os::ResultOutOfAddressSpace()); - - /* Try to map. */ - /* TODO: Result conversion/abort on unexpected result? */ - R_TRY_CATCH(svc::MapIoRegion(handle, reinterpret_cast(map_address), size, svc_perm)) { - /* If we failed to map at the address, retry. */ - R_CATCH(svc::ResultInvalidCurrentMemory) { continue; } - R_CATCH(svc::ResultInvalidMemoryRegion) { continue; } - } R_END_TRY_CATCH; - - /* Check guard space via aslr manager. */ - if (!impl::GetAslrSpaceManager().CheckGuardSpace(reinterpret_cast(map_address), size)) { - /* We don't have guard space, so unmap. */ - UnmapIoRegion(handle, map_address, size); - continue; + return ResultSuccess(); + }, + [handle](uintptr_t map_address, size_t map_size) -> void { + return IoRegionImpl::UnmapIoRegion(handle, reinterpret_cast(map_address), map_size); } + )); - /* We mapped successfully. */ - *out = map_address; - return ResultSuccess(); - } - - /* We failed to map. */ - return os::ResultOutOfAddressSpace(); + /* Return the address we mapped at. */ + *out = reinterpret_cast(mapped_address); + return ResultSuccess(); } void IoRegionImpl::UnmapIoRegion(Handle handle, void *address, size_t size) { diff --git a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp index 4b8472002..5f7d68df2 100644 --- a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp +++ b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp @@ -25,7 +25,7 @@ namespace ams::os::impl { class OsResourceManager { private: RngManager rng_manager{}; - AslrSpaceManager aslr_space_manager; + AslrSpaceManager aslr_space_manager{}; /* TODO */ ThreadManager thread_manager{}; /* TODO */ diff --git a/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.hpp b/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.hpp new file mode 100644 index 000000000..3069a2f77 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.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::os::impl { + + class SharedMemoryImpl { + public: + static Result Create(Handle *out, size_t size, MemoryPermission my_perm, MemoryPermission other_perm); + static void Close(Handle handle); + + static Result Map(void **out, Handle handle, size_t size, MemoryPermission perm); + static void Unmap(Handle handle, void *address, size_t size); + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp new file mode 100644 index 000000000..4fdf18519 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp @@ -0,0 +1,84 @@ +/* + * 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 +#include "os_shared_memory_impl.hpp" +#include "os_aslr_space_manager.hpp" + +namespace ams::os::impl { + + namespace { + + svc::MemoryPermission ConvertToSvcMemoryPermission(os::MemoryPermission perm) { + switch (perm) { + case os::MemoryPermission_None: return svc::MemoryPermission_None; + case os::MemoryPermission_ReadOnly: return svc::MemoryPermission_Read; + case os::MemoryPermission_WriteOnly: return svc::MemoryPermission_Write; + case os::MemoryPermission_ReadWrite: return svc::MemoryPermission_ReadWrite; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + } + + Result SharedMemoryImpl::Create(Handle *out, size_t size, MemoryPermission my_perm, MemoryPermission other_perm) { + /* Convert memory permissions. */ + const auto svc_my_perm = ConvertToSvcMemoryPermission(my_perm); + const auto svc_other_perm = ConvertToSvcMemoryPermission(other_perm); + + /* Create the memory. */ + svc::Handle handle; + R_TRY_CATCH(svc::CreateSharedMemory(std::addressof(handle), size, svc_my_perm, svc_other_perm)) { + R_CONVERT(svc::ResultOutOfHandles, os::ResultOutOfHandles()) + R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + *out = handle; + return ResultSuccess(); + } + + void SharedMemoryImpl::Close(Handle handle) { + R_ABORT_UNLESS(svc::CloseHandle(handle)); + } + + Result SharedMemoryImpl::Map(void **out, Handle handle, size_t size, MemoryPermission perm) { + /* Convert memory permission. */ + const auto svc_perm = ConvertToSvcMemoryPermission(perm); + + /* Map at a random address. */ + uintptr_t mapped_address; + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + [handle, svc_perm](uintptr_t map_address, size_t map_size) -> Result { + R_TRY_CATCH(svc::MapSharedMemory(handle, map_address, map_size, svc_perm)) { + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + return ResultSuccess(); + }, + [handle](uintptr_t map_address, size_t map_size) -> void { + return SharedMemoryImpl::Unmap(handle, reinterpret_cast(map_address), map_size); + } + )); + + /* Return the address we mapped at. */ + *out = reinterpret_cast(mapped_address); + return ResultSuccess(); + } + + void SharedMemoryImpl::Unmap(Handle handle, void *address, size_t size) { + R_ABORT_UNLESS(svc::UnmapSharedMemory(handle, reinterpret_cast(address), size)); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.hpp b/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.hpp index 39d18a5a6..7054fe84a 100644 --- a/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.hpp @@ -23,7 +23,7 @@ namespace ams::os::impl { static Result Create(Handle *out, void *address, size_t size, MemoryPermission perm); static void Close(Handle handle); - static Result Map(void **out, Handle handle, void *address, size_t size, MemoryPermission owner_perm); + static Result Map(void **out, Handle handle, size_t size, MemoryPermission owner_perm); static void Unmap(Handle handle, void *address, size_t size); }; diff --git a/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp index d67a87b79..0fb4260f6 100644 --- a/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp @@ -15,6 +15,7 @@ */ #include #include "os_transfer_memory_impl.hpp" +#include "os_aslr_space_manager.hpp" namespace ams::os::impl { @@ -34,7 +35,7 @@ namespace ams::os::impl { Result TransferMemoryImpl::Create(Handle *out, void *address, size_t size, MemoryPermission perm) { /* Convert memory permission. */ - auto svc_perm = ConvertToSvcMemoryPermission(perm); + const auto svc_perm = ConvertToSvcMemoryPermission(perm); /* Create the memory. */ svc::Handle handle; @@ -51,22 +52,30 @@ namespace ams::os::impl { R_ABORT_UNLESS(svc::CloseHandle(handle)); } - Result TransferMemoryImpl::Map(void **out, Handle handle, void *address, size_t size, MemoryPermission owner_perm) { - AMS_ASSERT(address != nullptr); - + Result TransferMemoryImpl::Map(void **out, Handle handle, size_t size, MemoryPermission owner_perm) { /* Convert memory permission. */ - auto svc_owner_perm = ConvertToSvcMemoryPermission(owner_perm); + const auto svc_owner_perm = ConvertToSvcMemoryPermission(owner_perm); - /* Map the memory. */ - R_TRY_CATCH(svc::MapTransferMemory(handle, reinterpret_cast(address), size, svc_owner_perm)) { - R_CONVERT(svc::ResultInvalidHandle, os::ResultInvalidHandle()) - R_CONVERT(svc::ResultInvalidSize, os::ResultInvalidTransferMemorySize()) - R_CONVERT(svc::ResultInvalidState, os::ResultInvalidTransferMemoryState()) - R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) - R_CONVERT(svc::ResultInvalidMemoryRegion, os::ResultInvalidCurrentMemoryState()) - } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + /* Map at a random address. */ + uintptr_t mapped_address; + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + [handle, svc_owner_perm](uintptr_t map_address, size_t map_size) -> Result { + R_TRY_CATCH(svc::MapTransferMemory(handle, map_address, map_size, svc_owner_perm)) { + R_CONVERT(svc::ResultInvalidHandle, os::ResultInvalidHandle()) + R_CONVERT(svc::ResultInvalidSize, os::ResultInvalidTransferMemorySize()) + R_CONVERT(svc::ResultInvalidState, os::ResultInvalidTransferMemoryState()) + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; - *out = address; + return ResultSuccess(); + }, + [handle](uintptr_t map_address, size_t map_size) -> void { + return TransferMemoryImpl::Unmap(handle, reinterpret_cast(map_address), map_size); + } + )); + + /* Return the address we mapped at. */ + *out = reinterpret_cast(mapped_address); return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/os/os_shared_memory.cpp b/libraries/libstratosphere/source/os/os_shared_memory.cpp new file mode 100644 index 000000000..879c292d8 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_shared_memory.cpp @@ -0,0 +1,157 @@ +/* + * 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 +#include "impl/os_thread_manager.hpp" +#include "impl/os_shared_memory_impl.hpp" + +namespace ams::os { + + namespace { + + void SetupSharedMemoryType(SharedMemoryType *shared_memory, size_t size, Handle handle, bool managed) { + /* Set members. */ + shared_memory->handle = handle; + shared_memory->size = size; + shared_memory->address = nullptr; + shared_memory->allocated = false; + + /* Set managed. */ + shared_memory->handle_managed = managed; + + /* Create the critical section. */ + util::ConstructAt(shared_memory->cs_shared_memory); + } + + } + + Result CreateSharedMemory(SharedMemoryType *shared_memory, size_t size, MemoryPermission my_perm, MemoryPermission other_perm) { + /* Check pre-conditions. */ + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + + /* Create the memory. */ + Handle handle; + R_TRY(impl::SharedMemoryImpl::Create(std::addressof(handle), size, my_perm, other_perm)); + + /* Setup the object. */ + SetupSharedMemoryType(shared_memory, size, handle, true); + + return ResultSuccess(); + } + + void AttachSharedMemory(SharedMemoryType *shared_memory, size_t size, Handle handle, bool managed) { + /* Check pre-conditions. */ + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + AMS_ASSERT(handle != svc::InvalidHandle); + + /* Setup the object. */ + SetupSharedMemoryType(shared_memory, size, handle, managed); + } + + void DestroySharedMemory(SharedMemoryType *shared_memory) { + /* Unmap the shared memory, if required. */ + if (shared_memory->state == SharedMemoryType::State_Mapped) { + UnmapSharedMemory(shared_memory); + } + + /* Check the state. */ + AMS_ASSERT(shared_memory->state == SharedMemoryType::State_Initialized); + + /* Set state to not initialized. */ + shared_memory->state = SharedMemoryType::State_NotInitialized; + + /* Close the handle, if it's managed. */ + if (shared_memory->handle_managed) { + impl::SharedMemoryImpl::Close(shared_memory->handle); + } + shared_memory->handle_managed = false; + + /* Clear members. */ + shared_memory->address = nullptr; + shared_memory->size = 0; + shared_memory->handle = svc::InvalidHandle; + + /* Destroy the critical section. */ + util::DestroyAt(shared_memory->cs_shared_memory); + } + + void *MapSharedMemory(SharedMemoryType *shared_memory, MemoryPermission perm) { + /* Lock the current thread, and then the shared memory. */ + std::scoped_lock thread_lk(util::GetReference(impl::GetCurrentThread()->cs_thread)); + std::scoped_lock lk(util::GetReference(shared_memory->cs_shared_memory)); + + /* Ensure we're in a mappable state. */ + AMS_ASSERT(shared_memory->state == SharedMemoryType::State_Initialized); + + /* Try to map. */ + void *mapped_address; + if (R_FAILED(impl::SharedMemoryImpl::Map(std::addressof(mapped_address), shared_memory->handle, shared_memory->size, perm))) { + return nullptr; + } + + /* Set fields now that we've mapped successfully. */ + shared_memory->allocated = true; + shared_memory->address = mapped_address; + shared_memory->state = SharedMemoryType::State_Mapped; + + return mapped_address; + } + + void UnmapSharedMemory(SharedMemoryType *shared_memory) { + /* Lock the memory. */ + std::scoped_lock lk(util::GetReference(shared_memory->cs_shared_memory)); + + /* If the memory isn't mapped, we can't unmap it. */ + if (shared_memory->state != SharedMemoryType::State_Mapped) { + return; + } + + /* Unmap the memory. */ + impl::SharedMemoryImpl::Unmap(shared_memory->handle, shared_memory->address, shared_memory->size); + + /* Unmapped memory is necessarily not allocated. */ + if (shared_memory->allocated) { + shared_memory->allocated = false; + } + + /* Clear the address. */ + shared_memory->address = nullptr; + shared_memory->state = SharedMemoryType::State_Initialized; + } + + void *GetSharedMemoryAddress(const SharedMemoryType *shared_memory) { + /* Check pre-conditions. */ + AMS_ASSERT(shared_memory->state == SharedMemoryType::State_Initialized || shared_memory->state == SharedMemoryType::State_Mapped); + + return shared_memory->address; + } + + size_t GetSharedMemorySize(const SharedMemoryType *shared_memory) { + /* Check pre-conditions. */ + AMS_ASSERT(shared_memory->state == SharedMemoryType::State_Initialized || shared_memory->state == SharedMemoryType::State_Mapped); + + return shared_memory->size; + } + + Handle GetSharedMemoryHandle(const SharedMemoryType *shared_memory) { + /* Check pre-conditions. */ + AMS_ASSERT(shared_memory->state == SharedMemoryType::State_Initialized || shared_memory->state == SharedMemoryType::State_Mapped); + + return shared_memory->handle; + } + +} diff --git a/libraries/libstratosphere/source/os/os_transfer_memory.cpp b/libraries/libstratosphere/source/os/os_transfer_memory.cpp index 43242954e..51f155e9a 100644 --- a/libraries/libstratosphere/source/os/os_transfer_memory.cpp +++ b/libraries/libstratosphere/source/os/os_transfer_memory.cpp @@ -16,25 +16,11 @@ #include #include "impl/os_thread_manager.hpp" #include "impl/os_transfer_memory_impl.hpp" -#include "impl/os_aslr_space_manager_types.hpp" -#include "impl/os_aslr_space_manager.hpp" namespace ams::os { namespace { - Result MapTransferMemoryWithAddressUnsafe(TransferMemoryType *tmem, void *address, os::MemoryPermission owner_perm) { - /* Map the transfer memory. */ - void *mapped_address = nullptr; - R_TRY(impl::TransferMemoryImpl::Map(std::addressof(mapped_address), tmem->handle, address, tmem->size, owner_perm)); - - /* Set fields now that we've mapped. */ - tmem->address = mapped_address; - tmem->state = TransferMemoryType::State_Mapped; - - return ResultSuccess(); - } - inline void SetupTransferMemoryType(TransferMemoryType *tmem, size_t size, Handle handle, bool managed) { /* Set members. */ tmem->handle = handle; @@ -127,41 +113,16 @@ namespace ams::os { /* Ensure we're in a mappable state. */ AMS_ASSERT(tmem->state == TransferMemoryType::State_Created); - /* Try to map up to 64 times. */ - for (int i = 0; i < 64; ++i) { - /* Reserve space to map the memory. */ - void *map_address = impl::GetAslrSpaceManager().AllocateSpace(tmem->size); - R_UNLESS(map_address != nullptr, os::ResultOutOfAddressSpace()); + /* Map. */ + void *mapped_address; + R_TRY(impl::TransferMemoryImpl::Map(std::addressof(mapped_address), tmem->handle, tmem->size, owner_perm)); - /* Mark allocated. */ - tmem->allocated = true; - auto alloc_guard = SCOPE_GUARD { tmem->allocated = false; }; + /* Set fields now that we've mapped. */ + tmem->allocated = true; + tmem->address = mapped_address; + tmem->state = TransferMemoryType::State_Mapped; - /* Try to map. */ - R_TRY_CATCH(MapTransferMemoryWithAddressUnsafe(tmem, map_address, owner_perm)) { - /* If we failed to map at the address, retry. */ - R_CATCH(os::ResultInvalidCurrentMemoryState) { continue; } - } R_END_TRY_CATCH; - - /* Check guard space via aslr manager. */ - if (!impl::GetAslrSpaceManager().CheckGuardSpace(reinterpret_cast(tmem->address), tmem->size)) { - /* NOTE: Nintendo bug here. If this case occurs, they will return ResultSuccess() without actually mapping the transfer memory. */ - /* This is because they basically do if (!os::ResultInvalidCurrentMemoryState::Includes(result)) { return result; }, and */ - /* ResultSuccess() is not included by ResultInvalidCurrentMemoryState. */ - - /* We will do better than them, and will not falsely return ResultSuccess(). */ - impl::TransferMemoryImpl::Unmap(tmem->handle, tmem->address, tmem->size); - continue; - } - - /* We mapped successfully. */ - alloc_guard.Cancel(); - *out = tmem->address; - return ResultSuccess(); - } - - /* We failed to map. */ - return os::ResultOutOfAddressSpace(); + return ResultSuccess(); } void UnmapTransferMemory(TransferMemoryType *tmem) {