mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
os: do not use deprecated libnx ::virtmemReserve api
This commit is contained in:
parent
c98f4f1ff6
commit
1ea49bdae3
8 changed files with 340 additions and 3 deletions
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "os_address_space_allocator_types.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);
|
||||
|
||||
this->guard_page_count = util::DivideUp(gsz, MemoryPageSize);
|
||||
this->start_page = sa / MemoryPageSize;
|
||||
this->end_page = (ea / MemoryPageSize) + this->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);
|
||||
}
|
||||
|
||||
void *AddressSpaceAllocator::AllocateSpace(size_t size, size_t align) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(align > 0);
|
||||
|
||||
/* Determine the page count. */
|
||||
const size_t page_count = util::DivideUp(size, MemoryPageSize);
|
||||
|
||||
/* Determine the alignment pages. */
|
||||
AMS_ASSERT(util::IsAligned(align, MemoryPageSize));
|
||||
const size_t align_page_count = align / MemoryPageSize;
|
||||
|
||||
/* Check the page count. */
|
||||
if (page_count > this->end_page - this->guard_page_count) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Check that we can find a space. */
|
||||
if (rand_start > rand_end) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Try to find 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* If the page is valid, use it. */
|
||||
if (GetNextNonOverlappedNodeUnsafe(target - this->guard_page_count, page_count + 2 * this->guard_page_count)) {
|
||||
return reinterpret_cast<void *>(target * MemoryPageSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* We failed to find space. */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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);
|
||||
AMS_ASSERT(R_SUCCEEDED(result));
|
||||
|
||||
return memory_info.state == svc::MemoryState_Free && address + size <= memory_info.addr + memory_info.size;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "os_aslr_space_manager_types.hpp"
|
||||
#include "os_resource_manager.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
ALWAYS_INLINE AslrSpaceManager &GetAslrSpaceManager() {
|
||||
return GetResourceManager().GetAslrSpaceManager();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class AslrSpaceManagerHorizonImpl {
|
||||
NON_COPYABLE(AslrSpaceManagerHorizonImpl);
|
||||
NON_MOVEABLE(AslrSpaceManagerHorizonImpl);
|
||||
private:
|
||||
static constexpr u64 AslrBase32Bit = 0x0000200000ul;
|
||||
static constexpr u64 AslrSize32Bit = 0x003FE00000ul;
|
||||
static constexpr u64 AslrBase64BitDeprecated = 0x0008000000ul;
|
||||
static constexpr u64 AslrSize64BitDeprecated = 0x0078000000ul;
|
||||
static constexpr u64 AslrBase64Bit = 0x0008000000ul;
|
||||
static constexpr u64 AslrSize64Bit = 0x7FF8000000ul;
|
||||
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<size_t, uintptr_t>);
|
||||
AMS_ASSERT(value <= std::numeric_limits<size_t>::max());
|
||||
return static_cast<u64>(value & std::numeric_limits<size_t>::max());
|
||||
}
|
||||
public:
|
||||
constexpr AslrSpaceManagerHorizonImpl() = default;
|
||||
|
||||
static u64 GetHeapSpaceBeginAddress() {
|
||||
return GetAslrInfo(svc::InfoType_HeapRegionAddress);
|
||||
}
|
||||
|
||||
static u64 GetHeapSpaceBeginSize() {
|
||||
return GetAslrInfo(svc::InfoType_HeapRegionSize);
|
||||
}
|
||||
|
||||
static u64 GetAliasSpaceBeginAddress() {
|
||||
return GetAslrInfo(svc::InfoType_AliasRegionAddress);
|
||||
}
|
||||
|
||||
static u64 GetAliasSpaceBeginSize() {
|
||||
return GetAslrInfo(svc::InfoType_AliasRegionSize);
|
||||
}
|
||||
|
||||
static u64 GetAslrSpaceBeginAddress() {
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0 || svc::IsKernelMesosphere()) {
|
||||
return GetAslrInfo(svc::InfoType_AslrRegionAddress);
|
||||
} else {
|
||||
if (GetHeapSpaceBeginAddress() < AslrBase64BitDeprecated || GetAliasSpaceBeginAddress() < AslrBase64BitDeprecated) {
|
||||
return AslrBase32Bit;
|
||||
} else {
|
||||
return AslrBase64BitDeprecated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u64 GetAslrSpaceEndAddress() {
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0 || svc::IsKernelMesosphere()) {
|
||||
return GetAslrInfo(svc::InfoType_AslrRegionAddress) + GetAslrInfo(svc::InfoType_AslrRegionSize);
|
||||
} else {
|
||||
if (GetHeapSpaceBeginAddress() < AslrBase64BitDeprecated || GetAliasSpaceBeginAddress() < AslrBase64BitDeprecated) {
|
||||
return AslrBase32Bit + AslrSize32Bit;
|
||||
} else {
|
||||
return AslrBase64BitDeprecated + AslrSize64BitDeprecated;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using AslrSpaceManagerImpl = AslrSpaceManagerHorizonImpl;
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "os_address_space_allocator_types.hpp"
|
||||
|
||||
#ifdef ATMOSPHERE_OS_HORIZON
|
||||
#include "os_aslr_space_manager_impl.os.horizon.hpp"
|
||||
#else
|
||||
#error "Unknown OS for AslrSpaceManagerImpl"
|
||||
#endif
|
||||
|
||||
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);
|
||||
private:
|
||||
AddressSpaceAllocator allocator;
|
||||
AslrSpaceManagerImpl impl;
|
||||
public:
|
||||
AslrSpaceManager() : allocator(impl.GetAslrSpaceBeginAddress(), impl.GetAslrSpaceEndAddress(), AslrSpaceGuardSize) { /* ... */ }
|
||||
|
||||
void *AllocateSpace(size_t size) {
|
||||
void *address = this->allocator.AllocateSpace(size, AslrSpaceLargeAlign);
|
||||
if (address == nullptr) {
|
||||
address = this->allocator.AllocateSpace(size, MemoryPageSize);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
bool CheckGuardSpace(uintptr_t address, size_t size) {
|
||||
return this->allocator.CheckGuardSpace(address, size, AslrSpaceGuardSize);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -18,12 +18,14 @@
|
|||
#include "os_rng_manager_impl.hpp"
|
||||
#include "os_thread_manager_types.hpp"
|
||||
#include "os_tick_manager_impl.hpp"
|
||||
#include "os_aslr_space_manager_types.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
||||
class OsResourceManager {
|
||||
private:
|
||||
RngManager rng_manager{};
|
||||
AslrSpaceManager aslr_space_manager;
|
||||
/* TODO */
|
||||
ThreadManager thread_manager{};
|
||||
/* TODO */
|
||||
|
@ -33,6 +35,7 @@ namespace ams::os::impl {
|
|||
OsResourceManager() = default;
|
||||
|
||||
constexpr ALWAYS_INLINE RngManager &GetRngManager() { return this->rng_manager; }
|
||||
constexpr ALWAYS_INLINE AslrSpaceManager &GetAslrSpaceManager() { return this->aslr_space_manager; }
|
||||
constexpr ALWAYS_INLINE ThreadManager &GetThreadManager() { return this->thread_manager; }
|
||||
constexpr ALWAYS_INLINE TickManager &GetTickManager() { return this->tick_manager; }
|
||||
};
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <stratosphere.hpp>
|
||||
#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 {
|
||||
|
||||
|
@ -131,7 +133,7 @@ namespace ams::os {
|
|||
for (int i = 0; i < 64; ++i) {
|
||||
/* Reserve space to map the memory. */
|
||||
/* TODO: os::AslrSpaceManager */
|
||||
void *map_address = ::virtmemReserve(tmem->size);
|
||||
void *map_address = impl::GetAslrSpaceManager().AllocateSpace(tmem->size);
|
||||
R_UNLESS(map_address != nullptr, os::ResultOutOfAddressSpace());
|
||||
|
||||
/* Mark allocated. */
|
||||
|
@ -144,8 +146,13 @@ namespace ams::os {
|
|||
R_CATCH(os::ResultInvalidCurrentMemoryState) { continue; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* TODO: Check guard space via aslr manager. */
|
||||
if (false /* !impl::GetAslrSpaceManager()->CheckGuardSpace(reinterpret_cast<uintptr_t>(tmem->address), tmem->size) */) {
|
||||
/* Check guard space via aslr manager. */
|
||||
if (!impl::GetAslrSpaceManager().CheckGuardSpace(reinterpret_cast<uintptr_t>(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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue