diff --git a/libstratosphere/include/stratosphere/os.hpp b/libstratosphere/include/stratosphere/os.hpp index 7133512c..e43a4884 100644 --- a/libstratosphere/include/stratosphere/os.hpp +++ b/libstratosphere/include/stratosphere/os.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/libstratosphere/include/stratosphere/os/os_memory_common.hpp b/libstratosphere/include/stratosphere/os/os_memory_common.hpp index 3668a2ab..523d2d12 100644 --- a/libstratosphere/include/stratosphere/os/os_memory_common.hpp +++ b/libstratosphere/include/stratosphere/os/os_memory_common.hpp @@ -23,11 +23,13 @@ namespace ams::os { constexpr inline size_t MemoryBlockUnitSize = 0x200000; enum MemoryPermission { - MemoryPermission_None = (0 << 0), - MemoryPermission_ReadOnly = (1 << 0), - MemoryPermission_WriteOnly = (1 << 1), + MemoryPermission_None = (0 << 0), + MemoryPermission_ReadOnly = (1 << 0), + MemoryPermission_WriteOnly = (1 << 1), + MemoryPermission_ExecuteOnly = (1 << 2), - MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, + MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, + MemoryPermission_ReadExecute = MemoryPermission_ReadOnly | MemoryPermission_ExecuteOnly, }; #if defined(ATMOSPHERE_OS_HORIZON) diff --git a/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp b/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp new file mode 100644 index 00000000..aea5f1a0 --- /dev/null +++ b/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 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 { + + Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size); + void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size); + + Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm); + +} diff --git a/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp b/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp index f4d6b000..dc0517f6 100644 --- a/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp +++ b/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp @@ -46,10 +46,10 @@ namespace ams::os::impl { /* ... */ } - uintptr_t AllocateSpace(size_t size) { + uintptr_t AllocateSpace(size_t size, size_t align_offset) { /* 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) { + if (align_offset || size >= AslrSpaceLargeAlign) { + if (auto large_align = m_allocator.AllocateSpace(size, AslrSpaceLargeAlign, align_offset & (AslrSpaceLargeAlign - 1)); large_align != 0) { return large_align; } } @@ -63,11 +63,11 @@ namespace ams::os::impl { } template - Result MapAtRandomAddress(uintptr_t *out, size_t size, MapFunction map_function, UnmapFunction unmap_function) { + Result MapAtRandomAddress(uintptr_t *out, MapFunction map_function, UnmapFunction unmap_function, size_t size, size_t align_offset) { /* 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); + const uintptr_t map_address = this->AllocateSpace(size, align_offset); if (map_address == 0) { break; } diff --git a/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp b/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp index ed5112d5..a798f888 100644 --- a/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp +++ b/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp @@ -59,7 +59,7 @@ namespace ams::os::impl { /* Map at a random address. */ uintptr_t mapped_address; - R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), [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? */ @@ -73,7 +73,9 @@ namespace ams::os::impl { }, [handle](uintptr_t map_address, size_t map_size) -> void { return IoRegionImpl::UnmapIoRegion(handle, reinterpret_cast(map_address), map_size); - } + }, + size, + 0 )); /* Return the address we mapped at. */ diff --git a/libstratosphere/source/os/impl/os_process_memory_impl.hpp b/libstratosphere/source/os/impl/os_process_memory_impl.hpp new file mode 100644 index 00000000..faf035fe --- /dev/null +++ b/libstratosphere/source/os/impl/os_process_memory_impl.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 ProcessMemoryImpl { + public: + static Result Map(void **out, NativeHandle handle, u64 process_address, size_t size); + static void Unmap(void *mapped_memory, NativeHandle handle, u64 process_address, size_t size); + + static Result SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm); + }; + +} \ No newline at end of file diff --git a/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp b/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp new file mode 100644 index 00000000..fc836391 --- /dev/null +++ b/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 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_process_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_ReadWrite: return svc::MemoryPermission_ReadWrite; + case os::MemoryPermission_ReadExecute: return svc::MemoryPermission_ReadExecute; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + } + + Result ProcessMemoryImpl::Map(void **out, NativeHandle handle, u64 process_address, size_t size) { + /* Map at a random address. */ + uintptr_t mapped_address; + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), + [handle, process_address](uintptr_t map_address, size_t map_size) -> Result { + R_TRY_CATCH(svc::MapProcessMemory(map_address, handle, process_address, map_size)) { + R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + R_SUCCEED(); + }, + [handle, process_address](uintptr_t map_address, size_t map_size) -> void { + return ProcessMemoryImpl::Unmap(reinterpret_cast(map_address), handle, process_address, map_size); + }, + size, + process_address + )); + + /* Return the address we mapped at. */ + *out = reinterpret_cast(mapped_address); + R_SUCCEED(); + } + + void ProcessMemoryImpl::Unmap(void *mapped_memory, NativeHandle handle, u64 process_address, size_t size) { + R_ABORT_UNLESS(svc::UnmapProcessMemory(reinterpret_cast(mapped_memory), handle, process_address, size)); + } + + Result ProcessMemoryImpl::SetMemoryPermission(NativeHandle handle, u64 process_address, u64 size, MemoryPermission perm) { + /* Set the process memory permission. */ + R_TRY_CATCH(svc::SetProcessMemoryPermission(handle, process_address, size, ConvertToSvcMemoryPermission(perm))) { + R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + R_SUCCEED(); + } + +} diff --git a/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp b/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp index 799ef001..b336576f 100644 --- a/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp +++ b/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp @@ -59,7 +59,7 @@ namespace ams::os::impl { /* Map at a random address. */ uintptr_t mapped_address; - R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), [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()) @@ -69,7 +69,9 @@ namespace ams::os::impl { }, [handle](uintptr_t map_address, size_t map_size) -> void { return SharedMemoryImpl::Unmap(handle, reinterpret_cast(map_address), map_size); - } + }, + size, + 0 )); /* Return the address we mapped at. */ diff --git a/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp b/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp index 025d46d2..459c6942 100644 --- a/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp +++ b/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp @@ -58,7 +58,7 @@ namespace ams::os::impl { /* Map at a random address. */ uintptr_t mapped_address; - R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), size, + R_TRY(impl::GetAslrSpaceManager().MapAtRandomAddress(std::addressof(mapped_address), [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()) @@ -71,7 +71,9 @@ namespace ams::os::impl { }, [handle](uintptr_t map_address, size_t map_size) -> void { return TransferMemoryImpl::Unmap(handle, reinterpret_cast(map_address), map_size); - } + }, + size, + 0 )); /* Return the address we mapped at. */ diff --git a/libstratosphere/source/os/os_process_memory.cpp b/libstratosphere/source/os/os_process_memory.cpp new file mode 100644 index 00000000..65d023db --- /dev/null +++ b/libstratosphere/source/os/os_process_memory.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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_process_memory_impl.hpp" + +namespace ams::os { + + Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size) { + R_RETURN(::ams::os::impl::ProcessMemoryImpl::Map(out, handle, process_address, process_size)); + } + + void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size) { + return ::ams::os::impl::ProcessMemoryImpl::Unmap(mapped_memory, handle, process_address, process_size); + } + + Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm) { + R_RETURN(::ams::os::impl::ProcessMemoryImpl::SetMemoryPermission(handle, process_address, process_size, perm)); + } + +}