mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-29 22:15:17 -04:00
kern: implement dynamic slab init + ini relocation
This commit is contained in:
parent
d9e6771e63
commit
cb6af379d8
20 changed files with 851 additions and 22 deletions
|
@ -17,6 +17,12 @@
|
|||
|
||||
namespace ams::kern::arm64 {
|
||||
|
||||
/* Instantiate static members in specific translation unit. */
|
||||
KSpinLock KInterruptManager::s_lock;
|
||||
std::array<KInterruptManager::KGlobalInterruptEntry, KInterruptController::NumGlobalInterrupts> KInterruptManager::s_global_interrupts;
|
||||
KInterruptController::GlobalState KInterruptManager::s_global_state;
|
||||
bool KInterruptManager::s_global_state_saved;
|
||||
|
||||
void KInterruptManager::Initialize(s32 core_id) {
|
||||
this->interrupt_controller.Initialize(core_id);
|
||||
}
|
||||
|
|
|
@ -233,6 +233,10 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
u32 KSystemControl::GetInitialProcessBinaryPool() {
|
||||
return KMemoryManager::Pool_Application;
|
||||
}
|
||||
|
||||
/* Randomness. */
|
||||
void KSystemControl::GenerateRandomBytes(void *dst, size_t size) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38);
|
||||
|
|
74
libraries/libmesosphere/source/kern_initial_process.cpp
Normal file
74
libraries/libmesosphere/source/kern_initial_process.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
KVirtualAddress GetInitialProcessBinaryAddress() {
|
||||
return KMemoryLayout::GetPageTableHeapRegion().GetEndAddress() - InitialProcessBinarySizeMax;
|
||||
}
|
||||
|
||||
void LoadInitialProcessBinaryHeader(InitialProcessBinaryHeader *header) {
|
||||
if (header->magic != InitialProcessBinaryMagic) {
|
||||
*header = *GetPointer<InitialProcessBinaryHeader>(GetInitialProcessBinaryAddress());
|
||||
}
|
||||
|
||||
MESOSPHERE_ABORT_UNLESS(header->magic == InitialProcessBinaryMagic);
|
||||
MESOSPHERE_ABORT_UNLESS(header->num_processes <= init::GetSlabResourceCounts().num_KProcess);
|
||||
}
|
||||
|
||||
KVirtualAddress g_initial_process_binary_address;
|
||||
InitialProcessBinaryHeader g_initial_process_binary_header;
|
||||
u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
||||
u64 g_initial_process_id_max = std::numeric_limits<u64>::min();
|
||||
|
||||
}
|
||||
|
||||
u64 GetInitialProcessIdMin() {
|
||||
return g_initial_process_id_min;
|
||||
}
|
||||
|
||||
u64 GetInitialProcessIdMax() {
|
||||
return g_initial_process_id_max;
|
||||
}
|
||||
|
||||
void CopyInitialProcessBinaryToKernelMemory() {
|
||||
LoadInitialProcessBinaryHeader(&g_initial_process_binary_header);
|
||||
|
||||
if (g_initial_process_binary_header.num_processes > 0) {
|
||||
/* Reserve pages for the initial process binary from the system resource limit. */
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||
const size_t num_pages = total_size / PageSize;
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
||||
|
||||
/* Allocate memory for the image. */
|
||||
const KMemoryManager::Pool pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetInitialProcessBinaryPool());
|
||||
const auto allocate_option = KMemoryManager::EncodeOption(pool, KMemoryManager::Direction_FromFront);
|
||||
KVirtualAddress allocated_memory = mm.AllocateContinuous(num_pages, 1, allocate_option);
|
||||
MESOSPHERE_ABORT_UNLESS(allocated_memory != Null<KVirtualAddress>);
|
||||
mm.Open(allocated_memory, num_pages);
|
||||
|
||||
/* Relocate the image. */
|
||||
std::memmove(GetVoidPointer(allocated_memory), GetVoidPointer(GetInitialProcessBinaryAddress()), g_initial_process_binary_header.size);
|
||||
std::memset(GetVoidPointer(GetInitialProcessBinaryAddress()), 0, g_initial_process_binary_header.size);
|
||||
g_initial_process_binary_address = allocated_memory;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
101
libraries/libmesosphere/source/kern_k_page_group.cpp
Normal file
101
libraries/libmesosphere/source/kern_k_page_group.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KPageGroup::Initialize(KBlockInfoManager *m) {
|
||||
this->manager = m;
|
||||
}
|
||||
|
||||
void KPageGroup::Finalize() {
|
||||
auto it = this->block_list.begin();
|
||||
while (it != this->block_list.end()) {
|
||||
KBlockInfo *info = std::addressof(*it);
|
||||
it = this->block_list.erase(it);
|
||||
this->manager->Free(info);
|
||||
}
|
||||
}
|
||||
|
||||
size_t KPageGroup::GetNumPages() const {
|
||||
size_t num_pages = 0;
|
||||
|
||||
for (const auto &it : *this) {
|
||||
num_pages += it.GetNumPages();
|
||||
}
|
||||
|
||||
return num_pages;
|
||||
}
|
||||
|
||||
Result KPageGroup::AddBlock(KVirtualAddress addr, size_t num_pages) {
|
||||
/* Succeed immediately if we're adding no pages. */
|
||||
R_UNLESS(num_pages != 0, ResultSuccess());
|
||||
|
||||
/* Check for overflow. */
|
||||
MESOSPHERE_ASSERT(addr < addr + num_pages * PageSize);
|
||||
|
||||
/* Try to just append to the last block. */
|
||||
if (!this->block_list.empty()) {
|
||||
auto it = --(this->block_list.end());
|
||||
R_UNLESS(!it->TryConcatenate(addr, num_pages), ResultSuccess());
|
||||
}
|
||||
|
||||
/* Allocate a new block. */
|
||||
KBlockInfo *new_block = this->manager->Allocate();
|
||||
R_UNLESS(new_block != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Initialize the block. */
|
||||
new_block->Initialize(addr, num_pages);
|
||||
this->block_list.push_back(*new_block);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void KPageGroup::Open() const {
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
|
||||
for (const auto &it : *this) {
|
||||
mm.Open(it.GetAddress(), it.GetNumPages());
|
||||
}
|
||||
}
|
||||
|
||||
void KPageGroup::Close() const {
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
|
||||
for (const auto &it : *this) {
|
||||
mm.Close(it.GetAddress(), it.GetNumPages());
|
||||
}
|
||||
}
|
||||
|
||||
bool KPageGroup::IsEquivalentTo(const KPageGroup &rhs) const {
|
||||
auto lit = this->block_list.cbegin();
|
||||
auto rit = rhs.block_list.cbegin();
|
||||
auto lend = this->block_list.cend();
|
||||
auto rend = rhs.block_list.cend();
|
||||
|
||||
while (lit != lend && rit != rend) {
|
||||
if (*lit != *rit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++lit;
|
||||
++rit;
|
||||
}
|
||||
|
||||
return lit == lend && rit == rend;
|
||||
}
|
||||
|
||||
}
|
|
@ -55,8 +55,8 @@ namespace ams::kern {
|
|||
const size_t needed_size = this->blocks[index].GetSize();
|
||||
|
||||
for (s32 i = index; i < static_cast<s32>(this->num_blocks); i++) {
|
||||
if (const KVirtualAddress addr = this->blocks[index].PopBlock(); addr != Null<KVirtualAddress>) {
|
||||
if (const size_t allocated_size = this->blocks[index].GetSize(); allocated_size > needed_size) {
|
||||
if (const KVirtualAddress addr = this->blocks[i].PopBlock(); addr != Null<KVirtualAddress>) {
|
||||
if (const size_t allocated_size = this->blocks[i].GetSize(); allocated_size > needed_size) {
|
||||
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
|
||||
}
|
||||
return addr;
|
||||
|
|
|
@ -18,11 +18,15 @@
|
|||
namespace ams::kern {
|
||||
|
||||
/* Declare kernel data members in kernel TU. */
|
||||
Kernel::State Kernel::s_state = Kernel::State::Invalid;
|
||||
KThread Kernel::s_main_threads[cpu::NumCores];
|
||||
KThread Kernel::s_idle_threads[cpu::NumCores];
|
||||
KResourceLimit Kernel::s_system_resource_limit;
|
||||
KMemoryManager Kernel::s_memory_manager;
|
||||
Kernel::State Kernel::s_state = Kernel::State::Invalid;
|
||||
KThread Kernel::s_main_threads[cpu::NumCores];
|
||||
KThread Kernel::s_idle_threads[cpu::NumCores];
|
||||
KResourceLimit Kernel::s_system_resource_limit;
|
||||
KMemoryManager Kernel::s_memory_manager;
|
||||
KPageTableManager Kernel::s_page_table_manager;
|
||||
KMemoryBlockSlabManager Kernel::s_app_memory_block_manager;
|
||||
KMemoryBlockSlabManager Kernel::s_sys_memory_block_manager;
|
||||
KBlockInfoManager Kernel::s_block_info_manager;
|
||||
|
||||
void Kernel::InitializeCoreLocalRegion(s32 core_id) {
|
||||
/* Construct the core local region object in place. */
|
||||
|
@ -68,10 +72,32 @@ namespace ams::kern {
|
|||
SetCurrentThread(main_thread);
|
||||
SetCurrentProcess(nullptr);
|
||||
|
||||
/* TODO: Initialize the interrupt manager. */
|
||||
/* Initialize the interrupt manager, hardware timer, and scheduler */
|
||||
GetInterruptManager().Initialize(core_id);
|
||||
GetHardwareTimer().Initialize(core_id);
|
||||
GetScheduler().Initialize(idle_thread);
|
||||
}
|
||||
|
||||
void Kernel::InitializeResourceManagers(KVirtualAddress address, size_t size) {
|
||||
/* Ensure that the buffer is suitable for our use. */
|
||||
const size_t app_size = ApplicationMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
const size_t sys_size = SystemMemoryBlockSlabHeapSize * sizeof(KMemoryBlock);
|
||||
const size_t info_size = BlockInfoSlabHeapSize * sizeof(KBlockInfo);
|
||||
const size_t fixed_size = util::AlignUp(app_size + sys_size + info_size, PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(fixed_size < size);
|
||||
|
||||
size_t pt_size = size - fixed_size;
|
||||
const size_t rc_size = util::AlignUp(KPageTableManager::CalculateReferenceCountSize(pt_size), PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(rc_size < pt_size);
|
||||
pt_size -= rc_size;
|
||||
|
||||
/* Initialize the slabheaps. */
|
||||
s_app_memory_block_manager.Initialize(address + pt_size, app_size);
|
||||
s_sys_memory_block_manager.Initialize(address + pt_size + app_size, sys_size);
|
||||
s_block_info_manager.Initialize(address + pt_size + app_size + sys_size, info_size);
|
||||
s_page_table_manager.Initialize(address, pt_size, GetPointer<KPageTableManager::RefCount>(address + pt_size + fixed_size));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,10 +45,17 @@ namespace ams::kern {
|
|||
init::InitializeKPageBufferSlabHeap();
|
||||
}
|
||||
|
||||
/* Note: this is not actually done here, it's done later in main after more stuff is setup. */
|
||||
/* However, for testing (and to manifest this code in the produced binary, this is here for now. */
|
||||
/* TODO: Do this better. */
|
||||
/* Copy the Initial Process Binary to safe memory. */
|
||||
CopyInitialProcessBinaryToKernelMemory();
|
||||
|
||||
/* Initialize the KObject Slab Heaps. */
|
||||
init::InitializeSlabHeaps();
|
||||
|
||||
/* Initialize the Dynamic Slab Heaps. */
|
||||
{
|
||||
const auto &pt_heap_region = KMemoryLayout::GetPageTableHeapRegion();
|
||||
Kernel::InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Implement more of Main() */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue