summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp236
1 files changed, 173 insertions, 63 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 09c36ee09..b77723503 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -28,10 +28,12 @@
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_page_buffer.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
@@ -47,6 +49,11 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
namespace Kernel {
struct KernelCore::Impl {
+ static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000;
+ static constexpr size_t SystemMemoryBlockSlabHeapSize = 10000;
+ static constexpr size_t BlockInfoSlabHeapSize = 4000;
+ static constexpr size_t ReservedDynamicPageCount = 64;
+
explicit Impl(Core::System& system_, KernelCore& kernel_)
: time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"},
service_thread_barrier{2}, system{system_} {}
@@ -71,7 +78,6 @@ struct KernelCore::Impl {
// Initialize kernel memory and resources.
InitializeSystemResourceLimit(kernel, system.CoreTiming());
InitializeMemoryLayout();
- Init::InitializeKPageBufferSlabHeap(system);
InitializeShutdownThreads();
InitializePhysicalCores();
InitializePreemption(kernel);
@@ -81,12 +87,13 @@ struct KernelCore::Impl {
const auto& pt_heap_region = memory_layout->GetPageTableHeapRegion();
ASSERT(pt_heap_region.GetEndAddress() != 0);
- InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize());
+ InitializeResourceManagers(kernel, pt_heap_region.GetAddress(),
+ pt_heap_region.GetSize());
}
- RegisterHostThread();
+ RegisterHostThread(nullptr);
- default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
+ default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
}
void InitializeCores() {
@@ -222,18 +229,22 @@ struct KernelCore::Impl {
const auto kernel_size{sizes.second};
// If setting the default system values fails, then something seriously wrong has occurred.
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
+ ASSERT(
+ system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, total_size)
+ .IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800)
+ .IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 900)
+ .IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200)
.IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 1133)
.IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
- system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
+ system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, kernel_size);
// Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{4_MiB};
- ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
+ ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax,
secure_applet_memory_size));
}
@@ -253,16 +264,82 @@ struct KernelCore::Impl {
system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
}
- void InitializeResourceManagers(VAddr address, size_t size) {
- dynamic_page_manager = std::make_unique<KDynamicPageManager>();
- memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
+ void InitializeResourceManagers(KernelCore& kernel, VAddr address, size_t size) {
+ // Ensure that the buffer is suitable for our use.
+ ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(size, PageSize));
+
+ // Ensure that we have space for our reference counts.
+ const size_t rc_size =
+ Common::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(size), PageSize);
+ ASSERT(rc_size < size);
+ size -= rc_size;
+
+ // Initialize the resource managers' shared page manager.
+ resource_manager_page_manager = std::make_unique<KDynamicPageManager>();
+ resource_manager_page_manager->Initialize(
+ address, size, std::max<size_t>(PageSize, KPageBufferSlabHeap::BufferSize));
+
+ // Initialize the KPageBuffer slab heap.
+ page_buffer_slab_heap.Initialize(system);
+
+ // Initialize the fixed-size slabheaps.
+ app_memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
+ sys_memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
+ block_info_heap = std::make_unique<KBlockInfoSlabHeap>();
+ app_memory_block_heap->Initialize(resource_manager_page_manager.get(),
+ ApplicationMemoryBlockSlabHeapSize);
+ sys_memory_block_heap->Initialize(resource_manager_page_manager.get(),
+ SystemMemoryBlockSlabHeapSize);
+ block_info_heap->Initialize(resource_manager_page_manager.get(), BlockInfoSlabHeapSize);
+
+ // Reserve all but a fixed number of remaining pages for the page table heap.
+ const size_t num_pt_pages = resource_manager_page_manager->GetCount() -
+ resource_manager_page_manager->GetUsed() -
+ ReservedDynamicPageCount;
+ page_table_heap = std::make_unique<KPageTableSlabHeap>();
+
+ // TODO(bunnei): Pass in address once we support kernel virtual memory allocations.
+ page_table_heap->Initialize(
+ resource_manager_page_manager.get(), num_pt_pages,
+ /*GetPointer<KPageTableManager::RefCount>(address + size)*/ nullptr);
+
+ // Setup the slab managers.
+ KDynamicPageManager* const app_dynamic_page_manager = nullptr;
+ KDynamicPageManager* const sys_dynamic_page_manager =
+ /*KTargetSystem::IsDynamicResourceLimitsEnabled()*/ true
+ ? resource_manager_page_manager.get()
+ : nullptr;
app_memory_block_manager = std::make_unique<KMemoryBlockSlabManager>();
-
- dynamic_page_manager->Initialize(address, size);
- static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000;
- memory_block_heap->Initialize(dynamic_page_manager.get(),
- ApplicationMemoryBlockSlabHeapSize);
- app_memory_block_manager->Initialize(nullptr, memory_block_heap.get());
+ sys_memory_block_manager = std::make_unique<KMemoryBlockSlabManager>();
+ app_block_info_manager = std::make_unique<KBlockInfoManager>();
+ sys_block_info_manager = std::make_unique<KBlockInfoManager>();
+ app_page_table_manager = std::make_unique<KPageTableManager>();
+ sys_page_table_manager = std::make_unique<KPageTableManager>();
+
+ app_memory_block_manager->Initialize(app_dynamic_page_manager, app_memory_block_heap.get());
+ sys_memory_block_manager->Initialize(sys_dynamic_page_manager, sys_memory_block_heap.get());
+
+ app_block_info_manager->Initialize(app_dynamic_page_manager, block_info_heap.get());
+ sys_block_info_manager->Initialize(sys_dynamic_page_manager, block_info_heap.get());
+
+ app_page_table_manager->Initialize(app_dynamic_page_manager, page_table_heap.get());
+ sys_page_table_manager->Initialize(sys_dynamic_page_manager, page_table_heap.get());
+
+ // Check that we have the correct number of dynamic pages available.
+ ASSERT(resource_manager_page_manager->GetCount() -
+ resource_manager_page_manager->GetUsed() ==
+ ReservedDynamicPageCount);
+
+ // Create the system page table managers.
+ app_system_resource = std::make_unique<KSystemResource>(kernel);
+ sys_system_resource = std::make_unique<KSystemResource>(kernel);
+
+ // Set the managers for the system resources.
+ app_system_resource->SetManagers(*app_memory_block_manager, *app_block_info_manager,
+ *app_page_table_manager);
+ sys_system_resource->SetManagers(*sys_memory_block_manager, *sys_block_info_manager,
+ *sys_page_table_manager);
}
void InitializeShutdownThreads() {
@@ -300,15 +377,18 @@ struct KernelCore::Impl {
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
- KThread* GetHostDummyThread() {
+ KThread* GetHostDummyThread(KThread* existing_thread) {
auto initialize = [this](KThread* thread) {
- ASSERT(KThread::InitializeDummyThread(thread).IsSuccess());
+ ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
return thread;
};
- thread_local auto raw_thread = KThread(system.Kernel());
- thread_local auto thread = initialize(&raw_thread);
+ thread_local KThread raw_thread{system.Kernel()};
+ thread_local KThread* thread = nullptr;
+ if (thread == nullptr) {
+ thread = (existing_thread == nullptr) ? initialize(&raw_thread) : existing_thread;
+ }
return thread;
}
@@ -323,9 +403,9 @@ struct KernelCore::Impl {
}
/// Registers a new host thread by allocating a host thread ID for it
- void RegisterHostThread() {
+ void RegisterHostThread(KThread* existing_thread) {
[[maybe_unused]] const auto this_id = GetHostThreadId();
- [[maybe_unused]] const auto dummy_thread = GetHostDummyThread();
+ [[maybe_unused]] const auto dummy_thread = GetHostDummyThread(existing_thread);
}
[[nodiscard]] u32 GetCurrentHostThreadID() {
@@ -356,7 +436,7 @@ struct KernelCore::Impl {
KThread* GetCurrentEmuThread() {
const auto thread_id = GetCurrentHostThreadID();
if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
- return GetHostDummyThread();
+ return GetHostDummyThread(nullptr);
}
return current_thread;
@@ -446,6 +526,9 @@ struct KernelCore::Impl {
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
+ // Determine if we'll use extra thread resources.
+ const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
+
// Setup the stack region.
constexpr size_t StackRegionSize = 14_MiB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
@@ -456,7 +539,8 @@ struct KernelCore::Impl {
stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
// Determine the size of the resource region.
- const size_t resource_region_size = memory_layout->GetResourceRegionSizeForInit();
+ const size_t resource_region_size =
+ memory_layout->GetResourceRegionSizeForInit(use_extra_resources);
// Determine the size of the slab region.
const size_t slab_region_size =
@@ -702,33 +786,31 @@ struct KernelCore::Impl {
search->second(system.ServiceManager(), server_port);
}
- std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
- const std::string& name) {
- auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name);
+ Kernel::ServiceThread& CreateServiceThread(KernelCore& kernel, const std::string& name) {
+ auto* ptr = new ServiceThread(kernel, name);
service_threads_manager.QueueWork(
- [this, service_thread]() { service_threads.emplace(service_thread); });
+ [this, ptr]() { service_threads.emplace(ptr, std::unique_ptr<ServiceThread>(ptr)); });
- return service_thread;
+ return *ptr;
}
- void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
- if (auto strong_ptr = service_thread.lock()) {
- if (strong_ptr == default_service_thread.lock()) {
- // Nothing to do here, the service is using default_service_thread, which will be
- // released on shutdown.
- return;
- }
+ void ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
+ auto* ptr = &service_thread;
- service_threads_manager.QueueWork(
- [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
+ if (ptr == default_service_thread) {
+ // Nothing to do here, the service is using default_service_thread, which will be
+ // released on shutdown.
+ return;
}
+
+ service_threads_manager.QueueWork([this, ptr]() { service_threads.erase(ptr); });
}
void ClearServiceThreads() {
service_threads_manager.QueueWork([this] {
service_threads.clear();
- default_service_thread.reset();
+ default_service_thread = nullptr;
service_thread_barrier.Sync();
});
service_thread_barrier.Sync();
@@ -751,6 +833,8 @@ struct KernelCore::Impl {
Init::KSlabResourceCounts slab_resource_counts{};
KResourceLimit* system_resource_limit{};
+ KPageBufferSlabHeap page_buffer_slab_heap;
+
std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
@@ -776,10 +860,20 @@ struct KernelCore::Impl {
// Kernel memory management
std::unique_ptr<KMemoryManager> memory_manager;
- // Dynamic slab managers
- std::unique_ptr<KDynamicPageManager> dynamic_page_manager;
- std::unique_ptr<KMemoryBlockSlabHeap> memory_block_heap;
+ // Resource managers
+ std::unique_ptr<KDynamicPageManager> resource_manager_page_manager;
+ std::unique_ptr<KPageTableSlabHeap> page_table_heap;
+ std::unique_ptr<KMemoryBlockSlabHeap> app_memory_block_heap;
+ std::unique_ptr<KMemoryBlockSlabHeap> sys_memory_block_heap;
+ std::unique_ptr<KBlockInfoSlabHeap> block_info_heap;
+ std::unique_ptr<KPageTableManager> app_page_table_manager;
+ std::unique_ptr<KPageTableManager> sys_page_table_manager;
std::unique_ptr<KMemoryBlockSlabManager> app_memory_block_manager;
+ std::unique_ptr<KMemoryBlockSlabManager> sys_memory_block_manager;
+ std::unique_ptr<KBlockInfoManager> app_block_info_manager;
+ std::unique_ptr<KBlockInfoManager> sys_block_info_manager;
+ std::unique_ptr<KSystemResource> app_system_resource;
+ std::unique_ptr<KSystemResource> sys_system_resource;
// Shared memory for services
Kernel::KSharedMemory* hid_shared_mem{};
@@ -792,8 +886,8 @@ struct KernelCore::Impl {
std::unique_ptr<KMemoryLayout> memory_layout;
// Threads used for services
- std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
- std::weak_ptr<ServiceThread> default_service_thread;
+ std::unordered_map<ServiceThread*, std::unique_ptr<ServiceThread>> service_threads;
+ ServiceThread* default_service_thread{};
Common::ThreadWorker service_threads_manager;
Common::Barrier service_thread_barrier;
@@ -1033,8 +1127,12 @@ void KernelCore::RegisterCoreThread(std::size_t core_id) {
impl->RegisterCoreThread(core_id);
}
-void KernelCore::RegisterHostThread() {
- impl->RegisterHostThread();
+void KernelCore::RegisterHostThread(KThread* existing_thread) {
+ impl->RegisterHostThread(existing_thread);
+
+ if (existing_thread != nullptr) {
+ ASSERT(GetCurrentEmuThread() == existing_thread);
+ }
}
u32 KernelCore::GetCurrentHostThreadID() const {
@@ -1057,12 +1155,12 @@ const KMemoryManager& KernelCore::MemoryManager() const {
return *impl->memory_manager;
}
-KMemoryBlockSlabManager& KernelCore::GetApplicationMemoryBlockManager() {
- return *impl->app_memory_block_manager;
+KSystemResource& KernelCore::GetSystemSystemResource() {
+ return *impl->sys_system_resource;
}
-const KMemoryBlockSlabManager& KernelCore::GetApplicationMemoryBlockManager() const {
- return *impl->app_memory_block_manager;
+const KSystemResource& KernelCore::GetSystemSystemResource() const {
+ return *impl->sys_system_resource;
}
Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
@@ -1109,16 +1207,28 @@ void KernelCore::Suspend(bool suspended) {
const bool should_suspend{exception_exited || suspended};
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
- for (auto* process : GetProcessList()) {
- process->SetActivity(activity);
+ std::vector<KScopedAutoObject<KThread>> process_threads;
+ {
+ KScopedSchedulerLock sl{*this};
+
+ if (auto* process = CurrentProcess(); process != nullptr) {
+ process->SetActivity(activity);
+
+ if (!should_suspend) {
+ // Runnable now; no need to wait.
+ return;
+ }
- if (should_suspend) {
- // Wait for execution to stop
for (auto* thread : process->GetThreadList()) {
- thread->WaitUntilSuspended();
+ process_threads.emplace_back(thread);
}
}
}
+
+ // Wait for execution to stop.
+ for (auto& thread : process_threads) {
+ thread->WaitUntilSuspended();
+ }
}
void KernelCore::ShutdownCores() {
@@ -1150,15 +1260,15 @@ void KernelCore::ExitSVCProfile() {
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);
}
-std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
+Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) {
return impl->CreateServiceThread(*this, name);
}
-std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
- return impl->default_service_thread;
+Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const {
+ return *impl->default_service_thread;
}
-void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
+void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
impl->ReleaseServiceThread(service_thread);
}