mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
os: implement MemoryHeapManager, SetMemoryAttribute
This commit is contained in:
parent
4e112de223
commit
a65b6df8d2
26 changed files with 1120 additions and 13 deletions
|
@ -21,7 +21,8 @@
|
||||||
#include <stratosphere/os/os_memory_common.hpp>
|
#include <stratosphere/os/os_memory_common.hpp>
|
||||||
#include <stratosphere/os/os_memory_fence.hpp>
|
#include <stratosphere/os/os_memory_fence.hpp>
|
||||||
#include <stratosphere/os/os_memory_permission.hpp>
|
#include <stratosphere/os/os_memory_permission.hpp>
|
||||||
#include <stratosphere/os/os_memory_heap_api.hpp>
|
#include <stratosphere/os/os_memory_attribute.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_heap.hpp>
|
||||||
#include <stratosphere/os/os_virtual_address_memory.hpp>
|
#include <stratosphere/os/os_virtual_address_memory.hpp>
|
||||||
#include <stratosphere/os/os_native_handle.hpp>
|
#include <stratosphere/os/os_native_handle.hpp>
|
||||||
#include <stratosphere/os/os_process_handle_api.hpp>
|
#include <stratosphere/os/os_process_handle_api.hpp>
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_common_types.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
enum MemoryAttribute {
|
||||||
|
MemoryAttribute_Normal,
|
||||||
|
MemoryAttribute_Uncached,
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetMemoryAttribute(uintptr_t address, size_t size, MemoryAttribute attr);
|
||||||
|
|
||||||
|
}
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
namespace ams::os {
|
namespace ams::os {
|
||||||
|
|
||||||
constexpr inline size_t MemoryPageSize = 0x1000;
|
|
||||||
|
|
||||||
constexpr inline size_t MemoryBlockUnitSize = 0x200000;
|
|
||||||
|
|
||||||
enum MemoryPermission {
|
enum MemoryPermission {
|
||||||
MemoryPermission_None = (0 << 0),
|
MemoryPermission_None = (0 << 0),
|
||||||
MemoryPermission_ReadOnly = (1 << 0),
|
MemoryPermission_ReadOnly = (1 << 0),
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_heap_common.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_heap_api.hpp>
|
|
@ -16,10 +16,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
#include <stratosphere/os/os_common_types.hpp>
|
#include <stratosphere/os/os_common_types.hpp>
|
||||||
#include <stratosphere/os/os_memory_common.hpp>
|
#include <stratosphere/os/os_memory_heap_common.hpp>
|
||||||
|
|
||||||
namespace ams::os {
|
namespace ams::os {
|
||||||
|
|
||||||
|
Result SetMemoryHeapSize(size_t size);
|
||||||
|
|
||||||
|
uintptr_t GetMemoryHeapAddress();
|
||||||
|
size_t GetMemoryHeapSize();
|
||||||
|
|
||||||
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size);
|
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size);
|
||||||
void FreeMemoryBlock(uintptr_t address, size_t size);
|
void FreeMemoryBlock(uintptr_t address, size_t size);
|
||||||
|
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_common_types.hpp>
|
||||||
|
#include <stratosphere/os/os_memory_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
constexpr inline size_t MemoryHeapUnitSize = 2_MB;
|
||||||
|
constexpr inline size_t MemoryBlockUnitSize = 2_MB;
|
||||||
|
|
||||||
|
constexpr inline size_t MemoryPageSize = 4_KB;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||||
|
/* Determine svc arguments. */
|
||||||
|
u32 svc_mask = svc::MemoryAttribute_Uncached;
|
||||||
|
u32 svc_attr = 0;
|
||||||
|
|
||||||
|
switch (attr) {
|
||||||
|
case os::MemoryAttribute_Normal: svc_attr = 0; break;
|
||||||
|
case os::MemoryAttribute_Uncached: svc_attr = svc::MemoryAttribute_Uncached; break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop, setting attribute. */
|
||||||
|
auto cur_address = address;
|
||||||
|
auto remaining = size;
|
||||||
|
while (remaining > 0) {
|
||||||
|
/* Query the memory. */
|
||||||
|
svc::MemoryInfo mem_info;
|
||||||
|
svc::PageInfo page_info;
|
||||||
|
R_ABORT_UNLESS(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), cur_address));
|
||||||
|
|
||||||
|
/* Determine the current size. */
|
||||||
|
const size_t cur_size = std::min<size_t>(mem_info.base_address + mem_info.size - cur_address, remaining);
|
||||||
|
|
||||||
|
/* Set the attribute, if necessary. */
|
||||||
|
if (mem_info.attribute != svc_attr) {
|
||||||
|
if (const auto res = svc::SetMemoryAttribute(address, size, svc_mask, svc_attr); R_FAILED(res)) {
|
||||||
|
/* NOTE: Nintendo logs here. */
|
||||||
|
R_ABORT_UNLESS(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_address += cur_size;
|
||||||
|
remaining -= cur_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||||
|
/* TODO: Should this do anything? */
|
||||||
|
AMS_UNUSED(address, size, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||||
|
/* TODO: Should this do anything? */
|
||||||
|
AMS_UNUSED(address, size, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryAttributeImpl(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||||
|
/* TODO: Should this do anything? */
|
||||||
|
AMS_UNUSED(address, size, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "os_memory_heap_manager.hpp"
|
||||||
|
#include "os_thread_manager.hpp"
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
Result MemoryHeapManager::SetHeapSize(size_t size) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryHeapUnitSize));
|
||||||
|
|
||||||
|
/* Acquire locks. */
|
||||||
|
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||||
|
std::scoped_lock lk2(m_cs);
|
||||||
|
|
||||||
|
/* If we need to, expand the heap. */
|
||||||
|
if (size > m_heap_size) {
|
||||||
|
/* Set the new heap size. */
|
||||||
|
uintptr_t address = 0;
|
||||||
|
R_TRY(m_impl.SetHeapSize(std::addressof(address), size));
|
||||||
|
R_UNLESS(address != 0, os::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* Check that the new heap address is consistent. */
|
||||||
|
if (m_heap_size == 0) {
|
||||||
|
AMS_ASSERT(util::IsAligned(address, MemoryHeapUnitSize));
|
||||||
|
} else {
|
||||||
|
AMS_ASSERT(address == m_heap_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the new heap address. */
|
||||||
|
this->AddToFreeSpaceUnsafe(address + m_heap_size, size - m_heap_size);
|
||||||
|
|
||||||
|
/* Set our heap address. */
|
||||||
|
m_heap_address = address;
|
||||||
|
m_heap_size = size;
|
||||||
|
} else if (size < m_heap_size) {
|
||||||
|
/* We're shrinking the heap, so we need to remove memory blocks. */
|
||||||
|
const uintptr_t end_address = m_heap_address + size;
|
||||||
|
const size_t remove_size = m_heap_size - size;
|
||||||
|
|
||||||
|
/* Get the end of the heap. */
|
||||||
|
auto it = m_free_memory_list.end();
|
||||||
|
--it;
|
||||||
|
R_UNLESS(it != m_free_memory_list.end(), os::ResultBusy());
|
||||||
|
|
||||||
|
/* Check that the block can be decommitted. */
|
||||||
|
R_UNLESS(it->GetAddress() <= end_address, os::ResultBusy());
|
||||||
|
R_UNLESS(it->GetSize() >= remove_size, os::ResultBusy());
|
||||||
|
|
||||||
|
/* Adjust the last node. */
|
||||||
|
if (const size_t node_size = it->GetSize() - remove_size; node_size == 0) {
|
||||||
|
m_free_memory_list.erase(it);
|
||||||
|
it->Clean();
|
||||||
|
} else {
|
||||||
|
it->SetSize(node_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the reduced heap size. */
|
||||||
|
uintptr_t address = 0;
|
||||||
|
R_ABORT_UNLESS(m_impl.SetHeapSize(std::addressof(address), size));
|
||||||
|
|
||||||
|
/* Set our heap address. */
|
||||||
|
m_heap_size = size;
|
||||||
|
if (size == 0) {
|
||||||
|
m_heap_address = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MemoryHeapManager::AllocateFromHeap(uintptr_t *out_address, size_t size) {
|
||||||
|
/* Acquire locks. */
|
||||||
|
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||||
|
std::scoped_lock lk2(m_cs);
|
||||||
|
|
||||||
|
/* Find free space. */
|
||||||
|
auto it = this->FindFreeSpaceUnsafe(size);
|
||||||
|
R_UNLESS(it != m_free_memory_list.end(), os::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* If necessary, split the memory block. */
|
||||||
|
if (it->GetSize() > size) {
|
||||||
|
this->SplitFreeMemoryNodeUnsafe(it, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the block. */
|
||||||
|
m_free_memory_list.erase(it);
|
||||||
|
it->Clean();
|
||||||
|
|
||||||
|
/* Increment the used heap size. */
|
||||||
|
m_used_heap_size += size;
|
||||||
|
|
||||||
|
/* Set the output address. */
|
||||||
|
*out_address = it->GetAddress();
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryHeapManager::ReleaseToHeap(uintptr_t address, size_t size) {
|
||||||
|
/* Acquire locks. */
|
||||||
|
std::scoped_lock lk1(util::GetReference(::ams::os::impl::GetCurrentThread()->cs_thread));
|
||||||
|
std::scoped_lock lk2(m_cs);
|
||||||
|
|
||||||
|
/* Check pre-condition. */
|
||||||
|
AMS_ABORT_UNLESS(this->IsRegionAllocatedMemoryUnsafe(address, size));
|
||||||
|
|
||||||
|
/* Restore the permissions on the memory. */
|
||||||
|
os::SetMemoryPermission(address, size, MemoryPermission_ReadWrite);
|
||||||
|
os::SetMemoryAttribute(address, size, MemoryAttribute_Normal);
|
||||||
|
|
||||||
|
/* Add the memory back to our free list. */
|
||||||
|
this->AddToFreeSpaceUnsafe(address, size);
|
||||||
|
|
||||||
|
/* Decrement the used heap size. */
|
||||||
|
m_used_heap_size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryHeapManager::FreeMemoryList::iterator MemoryHeapManager::FindFreeSpaceUnsafe(size_t size) {
|
||||||
|
/* Find the best fit candidate. */
|
||||||
|
auto best = m_free_memory_list.end();
|
||||||
|
|
||||||
|
for (auto it = m_free_memory_list.begin(); it != m_free_memory_list.end(); ++it) {
|
||||||
|
if (const size_t node_size = it->GetSize(); node_size >= size) {
|
||||||
|
if (best == m_free_memory_list.end() || node_size < best->GetSize()) {
|
||||||
|
best = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryHeapManager::FreeMemoryList::iterator MemoryHeapManager::ConcatenatePreviousFreeMemoryNodeUnsafe(FreeMemoryList::iterator node) {
|
||||||
|
/* Get the previous node. */
|
||||||
|
auto prev = node;
|
||||||
|
--prev;
|
||||||
|
|
||||||
|
/* If there's no previous, we're done. */
|
||||||
|
if (prev == m_free_memory_list.end() || node == m_free_memory_list.end()) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, if the previous isn't contiguous, we can't merge. */
|
||||||
|
if (prev->GetAddress() + prev->GetSize() != node->GetAddress()) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, increase the size of the previous node, and remove the current node. */
|
||||||
|
prev->SetSize(prev->GetSize() + node->GetSize());
|
||||||
|
m_free_memory_list.erase(node);
|
||||||
|
node->Clean();
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryHeapManager::SplitFreeMemoryNodeUnsafe(FreeMemoryList::iterator it, size_t size) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(it->GetSize() > size);
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||||
|
|
||||||
|
/* Create new node. */
|
||||||
|
auto *new_node = std::construct_at(reinterpret_cast<FreeMemoryNode *>(it->GetAddress() + size));
|
||||||
|
new_node->SetSize(it->GetSize() - size);
|
||||||
|
|
||||||
|
/* Set the old node's size. */
|
||||||
|
it->SetSize(size);
|
||||||
|
|
||||||
|
/* Insert the new node. */
|
||||||
|
m_free_memory_list.insert(++it, *new_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryHeapManager::AddToFreeSpaceUnsafe(uintptr_t address, size_t size) {
|
||||||
|
/* Create new node. */
|
||||||
|
auto *new_node = std::construct_at(reinterpret_cast<FreeMemoryNode *>(address));
|
||||||
|
new_node->SetSize(size);
|
||||||
|
|
||||||
|
/* Find the appropriate place to insert the node. */
|
||||||
|
auto it = m_free_memory_list.begin();
|
||||||
|
for (/* ... */; it != m_free_memory_list.end(); ++it) {
|
||||||
|
if (address < it->GetAddress()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert the new node. */
|
||||||
|
it = m_free_memory_list.insert(it, *new_node);
|
||||||
|
|
||||||
|
/* Perform coalescing as relevant. */
|
||||||
|
it = this->ConcatenatePreviousFreeMemoryNodeUnsafe(it);
|
||||||
|
this->ConcatenatePreviousFreeMemoryNodeUnsafe(++it);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryHeapManager::IsRegionAllocatedMemoryUnsafe(uintptr_t address, size_t size) {
|
||||||
|
/* Look for a node containing the region. */
|
||||||
|
for (auto it = m_free_memory_list.begin(); it != m_free_memory_list.end(); ++it) {
|
||||||
|
const uintptr_t node_address = it->GetAddress();
|
||||||
|
const size_t node_size = it->GetSize();
|
||||||
|
|
||||||
|
if (node_address < address + size && address < node_address + node_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "os_memory_heap_manager_types.hpp"
|
||||||
|
#include "os_resource_manager.hpp"
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
ALWAYS_INLINE MemoryHeapManager &GetMemoryHeapManager() {
|
||||||
|
return GetResourceManager().GetMemoryHeapManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
class MemoryHeapManagerHorizonImpl {
|
||||||
|
public:
|
||||||
|
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||||
|
R_TRY_CATCH(svc::SetHeapSize(out, size)) {
|
||||||
|
R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory())
|
||||||
|
R_CONVERT(svc::ResultLimitReached, os::ResultOutOfMemory())
|
||||||
|
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfMemory())
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using MemoryHeapManagerImpl = MemoryHeapManagerHorizonImpl;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
class MemoryHeapManagerLinuxImpl {
|
||||||
|
NON_COPYABLE(MemoryHeapManagerLinuxImpl);
|
||||||
|
NON_MOVEABLE(MemoryHeapManagerLinuxImpl);
|
||||||
|
private:
|
||||||
|
uintptr_t m_real_reserved_address;
|
||||||
|
size_t m_real_reserved_size;
|
||||||
|
uintptr_t m_aligned_reserved_heap_address;
|
||||||
|
size_t m_aligned_reserved_heap_size;
|
||||||
|
size_t m_committed_size;
|
||||||
|
public:
|
||||||
|
MemoryHeapManagerLinuxImpl() : m_real_reserved_address(0), m_real_reserved_size(0), m_aligned_reserved_heap_address(0), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||||
|
/* Reserve a 32 GB region of virtual address space. */
|
||||||
|
constexpr size_t TargetReservedSize = 32_GB;
|
||||||
|
const auto reserved = ::mmap(nullptr, TargetReservedSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||||
|
|
||||||
|
m_real_reserved_address = reinterpret_cast<uintptr_t>(reserved);
|
||||||
|
m_real_reserved_size = TargetReservedSize;
|
||||||
|
|
||||||
|
m_aligned_reserved_heap_address = util::AlignUp(m_real_reserved_address, MemoryHeapUnitSize);
|
||||||
|
m_aligned_reserved_heap_size = m_real_reserved_size - MemoryHeapUnitSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||||
|
/* Check that we have a reserved address. */
|
||||||
|
R_UNLESS(m_real_reserved_address != 0, os::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* If necessary, commit the new memory. */
|
||||||
|
if (size > m_committed_size) {
|
||||||
|
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||||
|
} else if (size < m_committed_size) {
|
||||||
|
/* Otherwise, decommit. */
|
||||||
|
this->DecommitMemory(m_aligned_reserved_heap_address + size, m_committed_size - size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the committed size. */
|
||||||
|
m_committed_size = size;
|
||||||
|
|
||||||
|
/* Set the out address. */
|
||||||
|
*out = m_aligned_reserved_heap_address;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool CommitMemory(size_t size) {
|
||||||
|
const auto res = ::mprotect(reinterpret_cast<void *>(m_aligned_reserved_heap_address), size, PROT_READ | PROT_WRITE);
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecommitMemory(uintptr_t address, size_t size) {
|
||||||
|
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using MemoryHeapManagerImpl = MemoryHeapManagerLinuxImpl;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
class MemoryHeapManagerMacosImpl {
|
||||||
|
NON_COPYABLE(MemoryHeapManagerMacosImpl);
|
||||||
|
NON_MOVEABLE(MemoryHeapManagerMacosImpl);
|
||||||
|
private:
|
||||||
|
uintptr_t m_real_reserved_address;
|
||||||
|
size_t m_real_reserved_size;
|
||||||
|
uintptr_t m_aligned_reserved_heap_address;
|
||||||
|
size_t m_aligned_reserved_heap_size;
|
||||||
|
size_t m_committed_size;
|
||||||
|
public:
|
||||||
|
MemoryHeapManagerMacosImpl() : m_real_reserved_address(0), m_real_reserved_size(0), m_aligned_reserved_heap_address(0), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||||
|
/* Reserve a 32 GB region of virtual address space. */
|
||||||
|
constexpr size_t TargetReservedSize = 32_GB;
|
||||||
|
const auto reserved = ::mmap(nullptr, TargetReservedSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||||
|
|
||||||
|
m_real_reserved_address = reinterpret_cast<uintptr_t>(reserved);
|
||||||
|
m_real_reserved_size = TargetReservedSize;
|
||||||
|
|
||||||
|
m_aligned_reserved_heap_address = util::AlignUp(m_real_reserved_address, MemoryHeapUnitSize);
|
||||||
|
m_aligned_reserved_heap_size = m_real_reserved_size - MemoryHeapUnitSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||||
|
/* Check that we have a reserved address. */
|
||||||
|
R_UNLESS(m_real_reserved_address != 0, os::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* If necessary, commit the new memory. */
|
||||||
|
if (size > m_committed_size) {
|
||||||
|
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||||
|
} else if (size < m_committed_size) {
|
||||||
|
/* Otherwise, decommit. */
|
||||||
|
this->DecommitMemory(m_aligned_reserved_heap_address + size, m_committed_size - size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the committed size. */
|
||||||
|
m_committed_size = size;
|
||||||
|
|
||||||
|
/* Set the out address. */
|
||||||
|
*out = m_aligned_reserved_heap_address;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool CommitMemory(size_t size) {
|
||||||
|
const auto res = ::mprotect(reinterpret_cast<void *>(m_aligned_reserved_heap_address), size, PROT_READ | PROT_WRITE);
|
||||||
|
return res == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecommitMemory(uintptr_t address, size_t size) {
|
||||||
|
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
AMS_ABORT_UNLESS(reserved != MAP_FAILED);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using MemoryHeapManagerImpl = MemoryHeapManagerMacosImpl;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <stratosphere/windows.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
class MemoryHeapManagerWindowsImpl {
|
||||||
|
NON_COPYABLE(MemoryHeapManagerWindowsImpl);
|
||||||
|
NON_MOVEABLE(MemoryHeapManagerWindowsImpl);
|
||||||
|
private:
|
||||||
|
LPVOID m_real_reserved_address;
|
||||||
|
size_t m_real_reserved_size;
|
||||||
|
LPVOID m_aligned_reserved_heap_address;
|
||||||
|
size_t m_aligned_reserved_heap_size;
|
||||||
|
size_t m_committed_size;
|
||||||
|
public:
|
||||||
|
MemoryHeapManagerWindowsImpl() : m_real_reserved_address(nullptr), m_real_reserved_size(0), m_aligned_reserved_heap_address(nullptr), m_aligned_reserved_heap_size(0), m_committed_size(0) {
|
||||||
|
/* Define target size. */
|
||||||
|
constexpr size_t TargetReservedSize = 32_GB;
|
||||||
|
|
||||||
|
/* Allocate appropriate amount of virtual space. */
|
||||||
|
size_t reserved_size = 0;
|
||||||
|
size_t reserved_addend = TargetReservedSize;
|
||||||
|
while (reserved_addend >= MemoryHeapUnitSize) {
|
||||||
|
if (this->ReserveVirtualSpace(0, reserved_size + reserved_addend)) {
|
||||||
|
this->ReleaseVirtualSpace();
|
||||||
|
|
||||||
|
reserved_size += reserved_addend;
|
||||||
|
if (reserved_size >= TargetReservedSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved_addend /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reserve virtual space. */
|
||||||
|
AMS_ABORT_UNLESS(this->ReserveVirtualSpace(0, reserved_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetHeapSize(uintptr_t *out, size_t size) {
|
||||||
|
/* Check that we have a reserved address. */
|
||||||
|
R_UNLESS(m_real_reserved_address != nullptr, os::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* If necessary, commit the new memory. */
|
||||||
|
if (size > m_committed_size) {
|
||||||
|
R_UNLESS(this->CommitMemory(size), os::ResultOutOfMemory());
|
||||||
|
} else if (size < m_committed_size) {
|
||||||
|
/* Otherwise, decommit. */
|
||||||
|
this->DecommitMemory(reinterpret_cast<uintptr_t>(m_aligned_reserved_heap_address) + size, m_committed_size - size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the committed size. */
|
||||||
|
m_committed_size = size;
|
||||||
|
|
||||||
|
/* Set the out address. */
|
||||||
|
*out = reinterpret_cast<uintptr_t>(m_aligned_reserved_heap_address);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool ReserveVirtualSpace(uintptr_t address, size_t size) {
|
||||||
|
AMS_ABORT_UNLESS(m_real_reserved_address == nullptr);
|
||||||
|
AMS_ABORT_UNLESS(m_real_reserved_size == 0);
|
||||||
|
|
||||||
|
size_t reserve_size = util::AlignUp(size, MemoryHeapUnitSize);
|
||||||
|
if constexpr (constexpr size_t VirtualAllocUnitSize = 64_KB; MemoryHeapUnitSize > VirtualAllocUnitSize) {
|
||||||
|
reserve_size += MemoryHeapUnitSize - VirtualAllocUnitSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPVOID res = ::VirtualAlloc(reinterpret_cast<LPVOID>(address), reserve_size, MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if (res == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_real_reserved_address = res;
|
||||||
|
m_real_reserved_size = reserve_size;
|
||||||
|
|
||||||
|
m_aligned_reserved_heap_address = reinterpret_cast<LPVOID>(util::AlignUp(reinterpret_cast<uintptr_t>(m_real_reserved_address), MemoryHeapUnitSize));
|
||||||
|
m_aligned_reserved_heap_size = size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseVirtualSpace() {
|
||||||
|
if (m_real_reserved_address != nullptr) {
|
||||||
|
auto res = ::VirtualFree(m_real_reserved_address, 0, MEM_RELEASE);
|
||||||
|
AMS_ASSERT(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
|
||||||
|
m_real_reserved_address = nullptr;
|
||||||
|
m_real_reserved_size = 0;
|
||||||
|
|
||||||
|
m_aligned_reserved_heap_address = nullptr;
|
||||||
|
m_aligned_reserved_heap_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommitMemory(size_t size) {
|
||||||
|
LPVOID address = ::VirtualAlloc(m_aligned_reserved_heap_address, static_cast<SIZE_T>(size), MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (address == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AMS_ABORT_UNLESS(address == m_aligned_reserved_heap_address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecommitMemory(uintptr_t address, size_t size) {
|
||||||
|
auto res = ::VirtualFree(reinterpret_cast<LPVOID>(address), static_cast<SIZE_T>(size), MEM_DECOMMIT);
|
||||||
|
AMS_ASSERT(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using MemoryHeapManagerImpl = MemoryHeapManagerWindowsImpl;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
|
#include "os_memory_heap_manager_impl.os.horizon.hpp"
|
||||||
|
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||||
|
#include "os_memory_heap_manager_impl.os.windows.hpp"
|
||||||
|
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||||
|
#include "os_memory_heap_manager_impl.os.linux.hpp"
|
||||||
|
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||||
|
#include "os_memory_heap_manager_impl.os.macos.hpp"
|
||||||
|
#else
|
||||||
|
#error "Unknown OS for MemoryHeapManagerImpl"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
class MemoryHeapManager;
|
||||||
|
|
||||||
|
class FreeMemoryNode {
|
||||||
|
private:
|
||||||
|
friend class MemoryHeapManager;
|
||||||
|
private:
|
||||||
|
util::IntrusiveListNode m_node;
|
||||||
|
size_t m_size;
|
||||||
|
public:
|
||||||
|
ALWAYS_INLINE uintptr_t GetAddress() const { return reinterpret_cast<uintptr_t>(this); }
|
||||||
|
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||||
|
ALWAYS_INLINE void SetSize(size_t size) { m_size = size; }
|
||||||
|
ALWAYS_INLINE void Clean() { std::memset(reinterpret_cast<void *>(this), 0, sizeof(FreeMemoryNode)); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(FreeMemoryNode) == sizeof(util::IntrusiveListNode) + sizeof(size_t));
|
||||||
|
|
||||||
|
class MemoryHeapManager {
|
||||||
|
NON_COPYABLE(MemoryHeapManager);
|
||||||
|
NON_MOVEABLE(MemoryHeapManager);
|
||||||
|
private:
|
||||||
|
using FreeMemoryList = typename util::IntrusiveListMemberTraits<&FreeMemoryNode::m_node>::ListType;
|
||||||
|
private:
|
||||||
|
uintptr_t m_heap_address;
|
||||||
|
size_t m_heap_size;
|
||||||
|
size_t m_used_heap_size;
|
||||||
|
FreeMemoryList m_free_memory_list;
|
||||||
|
InternalCriticalSection m_cs;
|
||||||
|
MemoryHeapManagerImpl m_impl;
|
||||||
|
public:
|
||||||
|
MemoryHeapManager() : m_heap_address(0), m_heap_size(0), m_used_heap_size(0) { /* ... */ }
|
||||||
|
|
||||||
|
Result SetHeapSize(size_t size);
|
||||||
|
|
||||||
|
Result AllocateFromHeap(uintptr_t *out_address, size_t size);
|
||||||
|
void ReleaseToHeap(uintptr_t address, size_t size);
|
||||||
|
|
||||||
|
bool IsRegionInMemoryHeap(uintptr_t address, size_t size) const {
|
||||||
|
return m_heap_address <= address && (address + size) <= (m_heap_address + m_heap_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetHeapAddress() const { return m_heap_address; }
|
||||||
|
size_t GetHeapSize() const { return m_heap_size; }
|
||||||
|
size_t GetUsedHeapSize() const { return m_used_heap_size; }
|
||||||
|
private:
|
||||||
|
FreeMemoryList::iterator FindFreeSpaceUnsafe(size_t size);
|
||||||
|
FreeMemoryList::iterator ConcatenatePreviousFreeMemoryNodeUnsafe(FreeMemoryList::iterator node);
|
||||||
|
void SplitFreeMemoryNodeUnsafe(FreeMemoryList::iterator it, size_t size);
|
||||||
|
void AddToFreeSpaceUnsafe(uintptr_t address, size_t size);
|
||||||
|
bool IsRegionAllocatedMemoryUnsafe(uintptr_t address, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||||
|
switch (perm) {
|
||||||
|
case MemoryPermission_None:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadOnly:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadWrite:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||||
|
switch (perm) {
|
||||||
|
case MemoryPermission_None:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadOnly:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadWrite:
|
||||||
|
{
|
||||||
|
auto res = ::mprotect(reinterpret_cast<void *>(address), size, PROT_READ | PROT_WRITE);
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <stratosphere/windows.hpp>
|
||||||
|
|
||||||
|
namespace ams::os::impl {
|
||||||
|
|
||||||
|
void SetMemoryPermissionImpl(uintptr_t address, size_t size, MemoryPermission perm) {
|
||||||
|
DWORD old;
|
||||||
|
|
||||||
|
uintptr_t cur_address = address;
|
||||||
|
size_t remaining = size;
|
||||||
|
while (remaining > 0) {
|
||||||
|
const size_t cur_size = std::min<size_t>(remaining, 2_GB);
|
||||||
|
switch (perm) {
|
||||||
|
case MemoryPermission_None:
|
||||||
|
{
|
||||||
|
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(address), static_cast<DWORD>(cur_size), PAGE_NOACCESS, std::addressof(old));
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadOnly:
|
||||||
|
{
|
||||||
|
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(address), static_cast<DWORD>(cur_size), PAGE_READONLY, std::addressof(old));
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MemoryPermission_ReadWrite:
|
||||||
|
{
|
||||||
|
auto res = ::VirtualProtect(reinterpret_cast<LPVOID>(address), static_cast<DWORD>(cur_size), PAGE_READWRITE, std::addressof(old));
|
||||||
|
AMS_ABORT_UNLESS(res);
|
||||||
|
AMS_UNUSED(res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_address += cur_size;
|
||||||
|
remaining -= cur_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@
|
||||||
#include "os_aslr_space_manager_types.hpp"
|
#include "os_aslr_space_manager_types.hpp"
|
||||||
#include "os_tls_manager_types.hpp"
|
#include "os_tls_manager_types.hpp"
|
||||||
#include "os_giant_lock_types.hpp"
|
#include "os_giant_lock_types.hpp"
|
||||||
|
#include "os_memory_heap_manager_types.hpp"
|
||||||
#include "os_vamm_manager_types.hpp"
|
#include "os_vamm_manager_types.hpp"
|
||||||
|
|
||||||
namespace ams::os::impl {
|
namespace ams::os::impl {
|
||||||
|
@ -34,7 +35,7 @@ namespace ams::os::impl {
|
||||||
ThreadManager m_thread_manager{};
|
ThreadManager m_thread_manager{};
|
||||||
//TlsManager m_tls_manager{};
|
//TlsManager m_tls_manager{};
|
||||||
TickManager m_tick_manager{};
|
TickManager m_tick_manager{};
|
||||||
/* TODO */
|
MemoryHeapManager m_memory_heap_manager;
|
||||||
VammManager m_vamm_manager;
|
VammManager m_vamm_manager;
|
||||||
GiantLock m_giant_lock{};
|
GiantLock m_giant_lock{};
|
||||||
public:
|
public:
|
||||||
|
@ -46,6 +47,7 @@ namespace ams::os::impl {
|
||||||
constexpr ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { return m_stack_guard_manager; }
|
constexpr ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { return m_stack_guard_manager; }
|
||||||
//constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_manager; }
|
//constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_manager; }
|
||||||
constexpr ALWAYS_INLINE TickManager &GetTickManager() { return m_tick_manager; }
|
constexpr ALWAYS_INLINE TickManager &GetTickManager() { return m_tick_manager; }
|
||||||
|
constexpr ALWAYS_INLINE MemoryHeapManager &GetMemoryHeapManager() { return m_memory_heap_manager; }
|
||||||
constexpr ALWAYS_INLINE VammManager &GetVammManager() { return m_vamm_manager; }
|
constexpr ALWAYS_INLINE VammManager &GetVammManager() { return m_vamm_manager; }
|
||||||
constexpr ALWAYS_INLINE GiantLock &GetGiantLock() { return m_giant_lock; }
|
constexpr ALWAYS_INLINE GiantLock &GetGiantLock() { return m_giant_lock; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,8 @@ namespace ams::os::impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
||||||
R_UNLESS(::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE) == 0, os::ResultBusy());
|
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
R_UNLESS(reserved != MAP_FAILED, os::ResultBusy());
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ namespace ams::os::impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
||||||
R_UNLESS(::mprotect(reinterpret_cast<void *>(address), size, PROT_NONE) == 0, os::ResultBusy());
|
const auto reserved = ::mmap(reinterpret_cast<void *>(address), size, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
R_UNLESS(reserved != MAP_FAILED, os::ResultBusy());
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
libraries/libstratosphere/source/os/os_memory_attribute.cpp
Normal file
29
libraries/libstratosphere/source/os/os_memory_attribute.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/os_memory_attribute_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
void SetMemoryAttribute(uintptr_t address, size_t size, MemoryAttribute attr) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(util::IsAligned(address, MemoryPageSize));
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryPageSize));
|
||||||
|
|
||||||
|
return impl::SetMemoryAttributeImpl(address, size, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,17 +14,47 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/os_memory_heap_manager.hpp"
|
||||||
|
|
||||||
namespace ams::os {
|
namespace ams::os {
|
||||||
|
|
||||||
|
Result SetMemoryHeapSize(size_t size) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryHeapUnitSize));
|
||||||
|
|
||||||
|
/* Set the heap size. */
|
||||||
|
R_RETURN(impl::GetMemoryHeapManager().SetHeapSize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t GetMemoryHeapAddress() {
|
||||||
|
return impl::GetMemoryHeapManager().GetHeapAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetMemoryHeapSize() {
|
||||||
|
return impl::GetMemoryHeapManager().GetHeapSize();
|
||||||
|
}
|
||||||
|
|
||||||
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size) {
|
Result AllocateMemoryBlock(uintptr_t *out_address, size_t size) {
|
||||||
AMS_UNUSED(out_address, size);
|
/* Check pre-conditions. */
|
||||||
AMS_ABORT("Not implemented yet");
|
AMS_ASSERT(size > 0);
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||||
|
|
||||||
|
/* Allocate from heap. */
|
||||||
|
R_RETURN(impl::GetMemoryHeapManager().AllocateFromHeap(out_address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeMemoryBlock(uintptr_t address, size_t size) {
|
void FreeMemoryBlock(uintptr_t address, size_t size) {
|
||||||
AMS_UNUSED(address, size);
|
/* Get memory heap manager. */
|
||||||
AMS_ABORT("Not implemented yet");
|
auto &manager = impl::GetMemoryHeapManager();
|
||||||
|
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(util::IsAligned(address, MemoryBlockUnitSize));
|
||||||
|
AMS_ASSERT(size > 0);
|
||||||
|
AMS_ASSERT(util::IsAligned(size, MemoryBlockUnitSize));
|
||||||
|
AMS_ABORT_UNLESS(manager.IsRegionInMemoryHeap(address, size));
|
||||||
|
|
||||||
|
/* Release the memory block. */
|
||||||
|
manager.ReleaseToHeap(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue