// Copyright 2015 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include #include #include "common/archives.h" #include "common/assert.h" #include "common/settings.h" #include "core/hle/kernel/resource_limit.h" SERIALIZE_EXPORT_IMPL(Kernel::ResourceLimit) SERIALIZE_EXPORT_IMPL(Kernel::ResourceLimitList) namespace Kernel { ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {} ResourceLimit::~ResourceLimit() = default; std::shared_ptr ResourceLimit::Create(KernelSystem& kernel, std::string name) { auto resource_limit = std::make_shared(kernel); resource_limit->m_name = std::move(name); return resource_limit; } s32 ResourceLimit::GetCurrentValue(ResourceLimitType type) const { const auto index = static_cast(type); return m_current_values[index]; } s32 ResourceLimit::GetLimitValue(ResourceLimitType type) const { const auto index = static_cast(type); return m_limit_values[index]; } void ResourceLimit::SetLimitValue(ResourceLimitType type, s32 value) { const auto index = static_cast(type); m_limit_values[index] = value; } bool ResourceLimit::Reserve(ResourceLimitType type, s32 amount) { const auto index = static_cast(type); const s32 limit = m_limit_values[index]; const s32 new_value = m_current_values[index] + amount; if (new_value > limit) { LOG_ERROR(Kernel, "New value {} exceeds limit {} for resource type {}", new_value, limit, type); return false; } m_current_values[index] = new_value; return true; } bool ResourceLimit::Release(ResourceLimitType type, s32 amount) { const auto index = static_cast(type); const s32 value = m_current_values[index]; if (amount > value) { LOG_ERROR(Kernel, "Amount {} exceeds current value {} for resource type {}", amount, value, type); return false; } m_current_values[index] = value - amount; return true; } template void ResourceLimit::serialize(Archive& ar, const unsigned int) { ar& boost::serialization::base_object(*this); ar& m_name; ar& m_limit_values; ar& m_current_values; } SERIALIZE_IMPL(ResourceLimit) ResourceLimitList::ResourceLimitList(KernelSystem& kernel) { // PM makes APPMEMALLOC always match app RESLIMIT_COMMIT. // See: https://github.com/LumaTeam/Luma3DS/blob/e2778a45/sysmodules/pm/source/reslimit.c#L275 const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); const auto& appmemalloc = kernel.GetMemoryRegion(MemoryRegion::APPLICATION); // Create the Application resource limit auto resource_limit = ResourceLimit::Create(kernel, "Applications"); resource_limit->SetLimitValue(ResourceLimitType::Priority, 0x18); resource_limit->SetLimitValue(ResourceLimitType::Commit, appmemalloc->size); resource_limit->SetLimitValue(ResourceLimitType::Thread, 0x20); resource_limit->SetLimitValue(ResourceLimitType::Event, 0x20); resource_limit->SetLimitValue(ResourceLimitType::Mutex, 0x20); resource_limit->SetLimitValue(ResourceLimitType::Semaphore, 0x8); resource_limit->SetLimitValue(ResourceLimitType::Timer, 0x8); resource_limit->SetLimitValue(ResourceLimitType::SharedMemory, 0x10); resource_limit->SetLimitValue(ResourceLimitType::AddressArbiter, 0x2); resource_limit->SetLimitValue(ResourceLimitType::CpuTime, 0x0); resource_limits[static_cast(ResourceLimitCategory::Application)] = resource_limit; // Create the SysApplet resource limit resource_limit = ResourceLimit::Create(kernel, "System Applets"); resource_limit->SetLimitValue(ResourceLimitType::Priority, 0x4); resource_limit->SetLimitValue(ResourceLimitType::Commit, is_new_3ds ? 0x5E06000 : 0x2606000); resource_limit->SetLimitValue(ResourceLimitType::Thread, is_new_3ds ? 0x1D : 0xE); resource_limit->SetLimitValue(ResourceLimitType::Event, is_new_3ds ? 0xB : 0x8); resource_limit->SetLimitValue(ResourceLimitType::Mutex, 0x8); resource_limit->SetLimitValue(ResourceLimitType::Semaphore, 0x4); resource_limit->SetLimitValue(ResourceLimitType::Timer, 0x4); resource_limit->SetLimitValue(ResourceLimitType::SharedMemory, 0x8); resource_limit->SetLimitValue(ResourceLimitType::AddressArbiter, 0x3); resource_limit->SetLimitValue(ResourceLimitType::CpuTime, 0x2710); resource_limits[static_cast(ResourceLimitCategory::SysApplet)] = resource_limit; // Create the LibApplet resource limit resource_limit = ResourceLimit::Create(kernel, "Library Applets"); resource_limit->SetLimitValue(ResourceLimitType::Priority, 0x4); resource_limit->SetLimitValue(ResourceLimitType::Commit, 0x602000); resource_limit->SetLimitValue(ResourceLimitType::Thread, 0xE); resource_limit->SetLimitValue(ResourceLimitType::Event, 0x8); resource_limit->SetLimitValue(ResourceLimitType::Mutex, 0x8); resource_limit->SetLimitValue(ResourceLimitType::Semaphore, 0x4); resource_limit->SetLimitValue(ResourceLimitType::Timer, 0x4); resource_limit->SetLimitValue(ResourceLimitType::SharedMemory, 0x8); resource_limit->SetLimitValue(ResourceLimitType::AddressArbiter, 0x1); resource_limit->SetLimitValue(ResourceLimitType::CpuTime, 0x2710); resource_limits[static_cast(ResourceLimitCategory::LibApplet)] = resource_limit; // Create the Other resource limit resource_limit = ResourceLimit::Create(kernel, "Others"); resource_limit->SetLimitValue(ResourceLimitType::Priority, 0x4); resource_limit->SetLimitValue(ResourceLimitType::Commit, is_new_3ds ? 0x2182000 : 0x1682000); resource_limit->SetLimitValue(ResourceLimitType::Thread, is_new_3ds ? 0xE1 : 0xCA); resource_limit->SetLimitValue(ResourceLimitType::Event, is_new_3ds ? 0x108 : 0xF8); resource_limit->SetLimitValue(ResourceLimitType::Mutex, is_new_3ds ? 0x25 : 0x23); resource_limit->SetLimitValue(ResourceLimitType::Semaphore, is_new_3ds ? 0x43 : 0x40); resource_limit->SetLimitValue(ResourceLimitType::Timer, is_new_3ds ? 0x2C : 0x2B); resource_limit->SetLimitValue(ResourceLimitType::SharedMemory, is_new_3ds ? 0x1F : 0x1E); resource_limit->SetLimitValue(ResourceLimitType::AddressArbiter, is_new_3ds ? 0x2D : 0x2B); resource_limit->SetLimitValue(ResourceLimitType::CpuTime, 0x3E8); resource_limits[static_cast(ResourceLimitCategory::Other)] = resource_limit; } ResourceLimitList::~ResourceLimitList() = default; std::shared_ptr ResourceLimitList::GetForCategory(ResourceLimitCategory category) { switch (category) { case ResourceLimitCategory::Application: case ResourceLimitCategory::SysApplet: case ResourceLimitCategory::LibApplet: case ResourceLimitCategory::Other: return resource_limits[static_cast(category)]; default: UNREACHABLE_MSG("Unknown resource limit category"); } } template void ResourceLimitList::serialize(Archive& ar, const unsigned int) { ar& resource_limits; } SERIALIZE_IMPL(ResourceLimitList) } // namespace Kernel