diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 2e9d63c30..49255dfd1 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -9,6 +9,12 @@ namespace Kernel { namespace ErrCodes { enum { + OutOfSharedMems = 11, + OutOfThreads = 12, + OutOfMutexes = 13, + OutOfSemaphores = 14, + OutOfEvents = 15, + OutOfTimers = 16, OutOfHandles = 19, SessionClosedByRemote = 26, PortNameTooLong = 30, @@ -16,6 +22,7 @@ enum { NoPendingSessions = 35, WrongPermission = 46, InvalidBufferDescriptor = 48, + OutOfAddressArbiters = 51, MaxConnectionsReached = 52, CommandTooLarge = 54, }; diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 07672adf1..a1fd8876c 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -8,12 +8,11 @@ #include #include #include "core/hle/kernel/object.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/wait_object.h" namespace Kernel { -class ResourceLimit; - class Event final : public WaitObject { public: explicit Event(KernelSystem& kernel); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5bd40d20a..db0caf59c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -137,6 +137,10 @@ const SharedPage::Handler& KernelSystem::GetSharedPageHandler() const { return *shared_page_handler; } +ConfigMem::Handler& KernelSystem::GetConfigMemHandler() { + return *config_mem_handler; +} + IPCDebugger::Recorder& KernelSystem::GetIPCRecorder() { return *ipc_recorder; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4f508df7e..e9f77be6c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -295,6 +295,8 @@ public: SharedPage::Handler& GetSharedPageHandler(); const SharedPage::Handler& GetSharedPageHandler() const; + ConfigMem::Handler& GetConfigMemHandler(); + IPCDebugger::Recorder& GetIPCRecorder(); const IPCDebugger::Recorder& GetIPCRecorder() const; diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 4440dac79..5094b3c4f 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -12,6 +12,7 @@ #include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" @@ -19,8 +20,6 @@ namespace Kernel { class Thread; -class ResourceLimit; - class Mutex final : public WaitObject { public: explicit Mutex(KernelSystem& kernel); diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 89c20f465..8b57f22c4 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -38,8 +38,8 @@ void ResourceLimit::SetLimitValue(ResourceLimitType type, s32 value) { bool ResourceLimit::Reserve(ResourceLimitType type, s32 amount) { const auto index = static_cast(type); - const u32 limit = m_limit_values[index]; - const u32 new_value = m_current_values[index] + amount; + 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); @@ -51,7 +51,7 @@ bool ResourceLimit::Reserve(ResourceLimitType type, s32 amount) { bool ResourceLimit::Release(ResourceLimitType type, s32 amount) { const auto index = static_cast(type); - const u32 value = m_current_values[index]; + const s32 value = m_current_values[index]; if (amount > value) { LOG_ERROR(Kernel, "Amount {} exceeds current value {} for resource type {}", amount, value, type); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 53d3028fc..a9a1a618f 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -16,6 +16,7 @@ #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" @@ -390,6 +391,8 @@ private: VAddr names, u32 name_count); ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limit_handle, VAddr names, u32 name_count); + ResultCode SetResourceLimitLimitValues(Handle res_limit, VAddr names, VAddr resource_list, + u32 name_count); ResultCode CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top, u32 priority, s32 processor_id); void ExitThread(); @@ -1074,7 +1077,8 @@ ResultCode SVC::CreateAddressArbiter(Handle* out_handle) { const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::AddressArbiter, 1)) { - return ResultCode{0xC8601833}; + return ResultCode(ErrCodes::OutOfAddressArbiters, ErrorModule::OS, + ErrorSummary::OutOfResource, ErrorLevel::Status); } // Create address arbiter. @@ -1197,14 +1201,48 @@ ResultCode SVC::GetResourceLimitLimitValues(VAddr values, Handle resource_limit_ } for (u32 i = 0; i < name_count; ++i) { - const u32 name = memory.Read32(names + i * sizeof(u32)); - const s64 value = resource_limit->GetLimitValue(static_cast(name)); + const auto name = static_cast(memory.Read32(names + i * sizeof(u32))); + if (name >= ResourceLimitType::Max) { + return ERR_INVALID_ENUM_VALUE; + } + const s64 value = resource_limit->GetLimitValue(name); memory.Write64(values + i * sizeof(u64), value); } return RESULT_SUCCESS; } +ResultCode SVC::SetResourceLimitLimitValues(Handle res_limit, VAddr names, VAddr resource_list, + u32 name_count) { + LOG_TRACE(Kernel_SVC, "called resource_limit={:08X}, names={:08X}, name_count={}", res_limit, + names, name_count); + + const auto resource_limit = + kernel.GetCurrentProcess()->handle_table.Get(res_limit); + if (!resource_limit) { + return ERR_INVALID_HANDLE; + } + + for (u32 i = 0; i < name_count; ++i) { + const auto name = static_cast(memory.Read32(names + i * sizeof(u32))); + if (name >= ResourceLimitType::Max) { + return ERR_INVALID_ENUM_VALUE; + } + const s64 value = memory.Read64(resource_list + i * sizeof(u64)); + const s32 value_high = value >> 32; + if (value_high < 0) { + return ERR_OUT_OF_RANGE_KERNEL; + } + if (name == ResourceLimitType::Commit && value_high != 0) { + auto& config_mem = kernel.GetConfigMemHandler().GetConfigMem(); + config_mem.app_mem_alloc = value_high; + } + resource_limit->SetLimitValue(name, static_cast(value)); + } + + return RESULT_SUCCESS; +} + /// Creates a new thread ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr stack_top, u32 priority, s32 processor_id) { @@ -1250,9 +1288,9 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr } // Update thread count in resource limit. - const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::Thread, 1)) { - return ResultCode{0xC860180C}; + return ResultCode(ErrCodes::OutOfThreads, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // Create thread. @@ -1331,7 +1369,8 @@ ResultCode SVC::CreateMutex(Handle* out_handle, u32 initial_locked) { const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::Mutex, 1)) { - return ResultCode{0xC860180D}; + return ResultCode(ErrCodes::OutOfMutexes, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // Create mutex. @@ -1405,7 +1444,8 @@ ResultCode SVC::CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_c const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::Semaphore, 1)) { - return ResultCode{0xC860180E}; + return ResultCode(ErrCodes::OutOfSemaphores, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // Create semaphore @@ -1501,7 +1541,8 @@ ResultCode SVC::CreateEvent(Handle* out_handle, u32 reset_type) { const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::Event, 1)) { - return ResultCode{0xC860180F}; + return ResultCode(ErrCodes::OutOfEvents, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // Create event. @@ -1553,7 +1594,8 @@ ResultCode SVC::CreateTimer(Handle* out_handle, u32 reset_type) { const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::Timer, 1)) { - return ResultCode{0xC8601810}; + return ResultCode(ErrCodes::OutOfTimers, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // Create timer. @@ -1711,7 +1753,8 @@ ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my const auto current_process = kernel.GetCurrentProcess(); const auto& resource_limit = current_process->resource_limit; if (!resource_limit->Reserve(ResourceLimitType::SharedMemory, 1)) { - return ResultCode{0xC860180B}; + return ResultCode(ErrCodes::OutOfSharedMems, ErrorModule::OS, ErrorSummary::OutOfResource, + ErrorLevel::Status); } // When trying to create a memory block with address = 0, @@ -2282,7 +2325,7 @@ const std::array SVC::SVC_Table{{ {0x76, &SVC::Wrap<&SVC::TerminateProcess>, "TerminateProcess"}, {0x77, nullptr, "SetProcessResourceLimits"}, {0x78, nullptr, "CreateResourceLimit"}, - {0x79, nullptr, "SetResourceLimitValues"}, + {0x79, &SVC::Wrap<&SVC::SetResourceLimitLimitValues>, "SetResourceLimitLimitValues"}, {0x7A, nullptr, "AddCodeSegment"}, {0x7B, nullptr, "Backdoor"}, {0x7C, &SVC::Wrap<&SVC::KernelSetState>, "KernelSetState"}, diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 6d84ae1a2..41ce6ef1a 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -30,7 +30,6 @@ Timer::~Timer() { std::shared_ptr KernelSystem::CreateTimer(ResetType reset_type, std::string name) { auto timer = std::make_shared(*this); - timer->resource_limit = resource_limit; timer->reset_type = reset_type; timer->signaled = false; timer->name = std::move(name); diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp index 84c989642..8c148aa21 100644 --- a/src/core/hle/service/ac/ac.cpp +++ b/src/core/hle/service/ac/ac.cpp @@ -12,6 +12,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/result.h" #include "core/hle/service/ac/ac.h" #include "core/hle/service/ac/ac_i.h" diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index eb78a2aa3..9f115086c 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -19,7 +19,6 @@ #include "core/file_sys/file_backend.h" #include "core/global.h" #include "core/hle/kernel/mutex.h" -#include "core/hle/kernel/resource_limit.h" #include "core/hle/result.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h index e4000e851..fd4ee7ebb 100644 --- a/src/core/hle/service/boss/boss.h +++ b/src/core/hle/service/boss/boss.h @@ -8,6 +8,7 @@ #include #include "core/global.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/service/service.h" namespace Core { diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 22fed1931..5bbe85944 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -166,7 +166,7 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr& process) const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); if (is_new_3ds && n3ds_mode == Kernel::New3dsMemoryMode::Legacy && category == Kernel::ResourceLimitCategory::Application) { - s32 new_limit = 0; + u64 new_limit = 0; switch (o3ds_mode) { case Kernel::MemoryMode::Prod: new_limit = 64_MiB; @@ -180,7 +180,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr& process) default: break; } - process->resource_limit->SetLimitValue(Kernel::ResourceLimitType::Commit, new_limit); + process->resource_limit->SetLimitValue(Kernel::ResourceLimitType::Commit, + static_cast(new_limit)); } // Set the default CPU core for this process