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_fence.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_native_handle.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 {
|
||||
|
||||
constexpr inline size_t MemoryPageSize = 0x1000;
|
||||
|
||||
constexpr inline size_t MemoryBlockUnitSize = 0x200000;
|
||||
|
||||
enum MemoryPermission {
|
||||
MemoryPermission_None = (0 << 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
|
||||
#include <vapours.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 {
|
||||
|
||||
Result SetMemoryHeapSize(size_t size);
|
||||
|
||||
uintptr_t GetMemoryHeapAddress();
|
||||
size_t GetMemoryHeapSize();
|
||||
|
||||
Result AllocateMemoryBlock(uintptr_t *out_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_tls_manager_types.hpp"
|
||||
#include "os_giant_lock_types.hpp"
|
||||
#include "os_memory_heap_manager_types.hpp"
|
||||
#include "os_vamm_manager_types.hpp"
|
||||
|
||||
namespace ams::os::impl {
|
||||
|
@ -34,7 +35,7 @@ namespace ams::os::impl {
|
|||
ThreadManager m_thread_manager{};
|
||||
//TlsManager m_tls_manager{};
|
||||
TickManager m_tick_manager{};
|
||||
/* TODO */
|
||||
MemoryHeapManager m_memory_heap_manager;
|
||||
VammManager m_vamm_manager;
|
||||
GiantLock m_giant_lock{};
|
||||
public:
|
||||
|
@ -46,6 +47,7 @@ namespace ams::os::impl {
|
|||
constexpr ALWAYS_INLINE StackGuardManager &GetStackGuardManager() { return m_stack_guard_manager; }
|
||||
//constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_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 GiantLock &GetGiantLock() { return m_giant_lock; }
|
||||
};
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace ams::os::impl {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace ams::os::impl {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
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/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "impl/os_memory_heap_manager.hpp"
|
||||
|
||||
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) {
|
||||
AMS_UNUSED(out_address, size);
|
||||
AMS_ABORT("Not implemented yet");
|
||||
/* Check pre-conditions. */
|
||||
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) {
|
||||
AMS_UNUSED(address, size);
|
||||
AMS_ABORT("Not implemented yet");
|
||||
/* Get memory heap manager. */
|
||||
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