mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
kern: add minimum alignment support to KMemoryManager
This commit is contained in:
parent
ff38a32a9b
commit
912b84c4e3
7 changed files with 58 additions and 16 deletions
|
@ -24,4 +24,8 @@ namespace ams::kern {
|
||||||
constexpr inline size_t MainMemorySize = 4_GB;
|
constexpr inline size_t MainMemorySize = 4_GB;
|
||||||
constexpr inline size_t MainMemorySizeMax = 8_GB;
|
constexpr inline size_t MainMemorySizeMax = 8_GB;
|
||||||
|
|
||||||
|
constexpr inline u32 MinimumMemoryManagerAlignmentShifts[] = {
|
||||||
|
0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ namespace ams::kern {
|
||||||
size_t m_num_managers;
|
size_t m_num_managers;
|
||||||
u64 m_optimized_process_ids[Pool_Count];
|
u64 m_optimized_process_ids[Pool_Count];
|
||||||
bool m_has_optimized_process[Pool_Count];
|
bool m_has_optimized_process[Pool_Count];
|
||||||
|
s32 m_min_heap_indexes[Pool_Count];
|
||||||
private:
|
private:
|
||||||
Impl &GetManager(KPhysicalAddress address) {
|
Impl &GetManager(KPhysicalAddress address) {
|
||||||
return m_managers[KMemoryLayout::GetPhysicalLinearRegion(address).GetAttributes()];
|
return m_managers[KMemoryLayout::GetPhysicalLinearRegion(address).GetAttributes()];
|
||||||
|
@ -188,12 +189,12 @@ namespace ams::kern {
|
||||||
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index);
|
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index);
|
||||||
public:
|
public:
|
||||||
KMemoryManager()
|
KMemoryManager()
|
||||||
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process()
|
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process(), m_min_heap_indexes()
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
NOINLINE void Initialize(KVirtualAddress management_region, size_t management_region_size);
|
NOINLINE void Initialize(KVirtualAddress management_region, size_t management_region_size, const u32 *min_align_shifts);
|
||||||
|
|
||||||
NOINLINE Result InitializeOptimizedMemory(u64 process_id, Pool pool);
|
NOINLINE Result InitializeOptimizedMemory(u64 process_id, Pool pool);
|
||||||
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
||||||
|
@ -299,6 +300,10 @@ namespace ams::kern {
|
||||||
manager->DumpFreeList();
|
manager->DumpFreeList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetMinimumAlignment(Pool pool) {
|
||||||
|
return KPageHeap::GetBlockSize(m_min_heap_indexes[pool]);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
static size_t CalculateManagementOverheadSize(size_t region_size) {
|
static size_t CalculateManagementOverheadSize(size_t region_size) {
|
||||||
return Impl::CalculateManagementOverheadSize(region_size);
|
return Impl::CalculateManagementOverheadSize(region_size);
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size) {
|
void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size, const u32 *min_align_shifts) {
|
||||||
/* Clear the management region to zero. */
|
/* Clear the management region to zero. */
|
||||||
const KVirtualAddress management_region_end = management_region + management_region_size;
|
const KVirtualAddress management_region_end = management_region + management_region_size;
|
||||||
std::memset(GetVoidPointer(management_region), 0, management_region_size);
|
std::memset(GetVoidPointer(management_region), 0, management_region_size);
|
||||||
|
@ -154,6 +154,17 @@ namespace ams::kern {
|
||||||
for (size_t i = 0; i < m_num_managers; ++i) {
|
for (size_t i = 0; i < m_num_managers; ++i) {
|
||||||
m_managers[i].SetInitialUsedHeapSize(reserved_sizes[i]);
|
m_managers[i].SetInitialUsedHeapSize(reserved_sizes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine the min heap size for all pools. */
|
||||||
|
for (size_t i = 0; i < Pool_Count; ++i) {
|
||||||
|
/* Determine the min alignment for the pool in pages. */
|
||||||
|
const size_t min_align_pages = 1 << min_align_shifts[i];
|
||||||
|
|
||||||
|
/* Determine a heap index. */
|
||||||
|
if (const auto heap_index = KPageHeap::GetAlignedBlockIndex(min_align_pages, min_align_pages); heap_index >= 0) {
|
||||||
|
m_min_heap_indexes[i] = heap_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KMemoryManager::InitializeOptimizedMemory(u64 process_id, Pool pool) {
|
Result KMemoryManager::InitializeOptimizedMemory(u64 process_id, Pool pool) {
|
||||||
|
@ -192,8 +203,19 @@ namespace ams::kern {
|
||||||
return Null<KPhysicalAddress>;
|
return Null<KPhysicalAddress>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lock the pool that we're allocating from. */
|
/* Determine the pool and direction we're allocating from. */
|
||||||
const auto [pool, dir] = DecodeOption(option);
|
const auto [pool, dir] = DecodeOption(option);
|
||||||
|
|
||||||
|
/* Check that we're allocating a correctly aligned number of pages. */
|
||||||
|
const size_t min_align_pages = KPageHeap::GetBlockNumPages(m_min_heap_indexes[pool]);
|
||||||
|
if (!util::IsAligned(num_pages, min_align_pages)) {
|
||||||
|
return Null<KPhysicalAddress>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update our alignment. */
|
||||||
|
align_pages = std::max(align_pages, min_align_pages);
|
||||||
|
|
||||||
|
/* Lock the pool that we're allocating from. */
|
||||||
KScopedLightLock lk(m_pool_locks[pool]);
|
KScopedLightLock lk(m_pool_locks[pool]);
|
||||||
|
|
||||||
/* Choose a heap based on our page size request. */
|
/* Choose a heap based on our page size request. */
|
||||||
|
@ -226,6 +248,13 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index) {
|
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index) {
|
||||||
|
/* Check that we're allocating a correctly aligned number of pages. */
|
||||||
|
const size_t min_align_pages = KPageHeap::GetBlockNumPages(m_min_heap_indexes[pool]);
|
||||||
|
R_UNLESS(util::IsAligned(num_pages, min_align_pages), svc::ResultInvalidSize());
|
||||||
|
|
||||||
|
/* Adjust our min heap index to the pool minimum if needed. */
|
||||||
|
min_heap_index = std::max(min_heap_index, m_min_heap_indexes[pool]);
|
||||||
|
|
||||||
/* Choose a heap based on our page size request. */
|
/* Choose a heap based on our page size request. */
|
||||||
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
||||||
R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory());
|
R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory());
|
||||||
|
|
|
@ -924,7 +924,6 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ABORT_UNLESS(m_main_thread_stack_size == 0);
|
MESOSPHERE_ABORT_UNLESS(m_main_thread_stack_size == 0);
|
||||||
|
|
||||||
/* Ensure that we're allocating a valid stack. */
|
/* Ensure that we're allocating a valid stack. */
|
||||||
stack_size = util::AlignUp(stack_size, PageSize);
|
|
||||||
R_UNLESS(stack_size + m_code_size <= m_max_process_memory, svc::ResultOutOfMemory());
|
R_UNLESS(stack_size + m_code_size <= m_max_process_memory, svc::ResultOutOfMemory());
|
||||||
R_UNLESS(stack_size + m_code_size >= m_code_size, svc::ResultOutOfMemory());
|
R_UNLESS(stack_size + m_code_size >= m_code_size, svc::ResultOutOfMemory());
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,9 @@ namespace ams::kern {
|
||||||
{
|
{
|
||||||
const auto &management_region = KMemoryLayout::GetPoolManagementRegion();
|
const auto &management_region = KMemoryLayout::GetPoolManagementRegion();
|
||||||
MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0);
|
MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0);
|
||||||
|
static_assert(util::size(MinimumMemoryManagerAlignmentShifts) == KMemoryManager::Pool_Count);
|
||||||
|
|
||||||
Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize());
|
Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize(), MinimumMemoryManagerAlignmentShifts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the Initial Process Binary to safe memory. */
|
/* Copy the Initial Process Binary to safe memory. */
|
||||||
|
|
|
@ -48,10 +48,11 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
Result MapPhysicalMemory(uintptr_t address, size_t size) {
|
Result MapPhysicalMemory(uintptr_t address, size_t size) {
|
||||||
/* Validate address / size. */
|
/* Validate address / size. */
|
||||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
const size_t min_alignment = Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool());
|
||||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
R_UNLESS(util::IsAligned(address, min_alignment), svc::ResultInvalidAddress());
|
||||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
R_UNLESS(util::IsAligned(size, min_alignment), svc::ResultInvalidSize());
|
||||||
R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Verify that the process has system resource. */
|
/* Verify that the process has system resource. */
|
||||||
auto &process = GetCurrentProcess();
|
auto &process = GetCurrentProcess();
|
||||||
|
@ -69,10 +70,11 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
Result UnmapPhysicalMemory(uintptr_t address, size_t size) {
|
Result UnmapPhysicalMemory(uintptr_t address, size_t size) {
|
||||||
/* Validate address / size. */
|
/* Validate address / size. */
|
||||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
const size_t min_alignment = Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool());
|
||||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
R_UNLESS(util::IsAligned(address, min_alignment), svc::ResultInvalidAddress());
|
||||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
R_UNLESS(util::IsAligned(size, min_alignment), svc::ResultInvalidSize());
|
||||||
R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Verify that the process has system resource. */
|
/* Verify that the process has system resource. */
|
||||||
auto &process = GetCurrentProcess();
|
auto &process = GetCurrentProcess();
|
||||||
|
|
|
@ -296,7 +296,9 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
Result StartProcess(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) {
|
Result StartProcess(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) {
|
||||||
/* Validate stack size. */
|
/* Validate stack size. */
|
||||||
R_UNLESS(main_thread_stack_size == static_cast<size_t>(main_thread_stack_size), svc::ResultOutOfMemory());
|
const uint64_t aligned_stack_size = util::AlignUp(main_thread_stack_size, Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool()));
|
||||||
|
R_UNLESS(aligned_stack_size >= main_thread_stack_size, svc::ResultOutOfMemory());
|
||||||
|
R_UNLESS(aligned_stack_size == static_cast<size_t>(aligned_stack_size), svc::ResultOutOfMemory());
|
||||||
|
|
||||||
/* Get the target process. */
|
/* Get the target process. */
|
||||||
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
|
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
|
||||||
|
@ -314,7 +316,7 @@ namespace ams::kern::svc {
|
||||||
process->SetIdealCoreId(core_id);
|
process->SetIdealCoreId(core_id);
|
||||||
|
|
||||||
/* Run the process. */
|
/* Run the process. */
|
||||||
R_RETURN(process->Run(priority, static_cast<size_t>(main_thread_stack_size)));
|
R_RETURN(process->Run(priority, static_cast<size_t>(aligned_stack_size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result TerminateProcess(ams::svc::Handle process_handle) {
|
Result TerminateProcess(ams::svc::Handle process_handle) {
|
||||||
|
|
Loading…
Reference in a new issue