diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index bec065543..59dc11c22 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -14,7 +14,7 @@ namespace Kernel { class KernelCore; -enum class ResourceType { +enum class ResourceType : u32 { PhysicalMemory, Threads, Events, @@ -25,6 +25,10 @@ enum class ResourceType { ResourceTypeCount }; +constexpr bool IsValidResourceType(ResourceType type) { + return type < ResourceType::ResourceTypeCount; +} + class ResourceLimit final : public Object { public: /** diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f287f7c97..1f19d5576 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -105,6 +105,38 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add return RESULT_SUCCESS; } + +enum class ResourceLimitValueType { + CurrentValue, + LimitValue, +}; + +ResultVal RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type, + ResourceLimitValueType value_type) { + const auto type = static_cast(resource_type); + if (!IsValidResourceType(type)) { + LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); + return ERR_INVALID_ENUM_VALUE; + } + + const auto& kernel = Core::System::GetInstance().Kernel(); + const auto* const current_process = kernel.CurrentProcess(); + ASSERT(current_process != nullptr); + + const auto resource_limit_object = + current_process->GetHandleTable().Get(resource_limit); + if (!resource_limit_object) { + LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", + resource_limit); + return ERR_INVALID_HANDLE; + } + + if (value_type == ResourceLimitValueType::CurrentValue) { + return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); + } + + return MakeResult(resource_limit_object->GetMaxResourceValue(type)); +} } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. @@ -1346,6 +1378,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { return RESULT_SUCCESS; } +static ResultCode CreateResourceLimit(Handle* out_handle) { + LOG_DEBUG(Kernel_SVC, "called"); + + auto& kernel = Core::System::GetInstance().Kernel(); + auto resource_limit = ResourceLimit::Create(kernel); + + auto* const current_process = kernel.CurrentProcess(); + ASSERT(current_process != nullptr); + + const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); + if (handle.Failed()) { + return handle.Code(); + } + + *out_handle = *handle; + return RESULT_SUCCESS; +} + +static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit, + u32 resource_type) { + LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); + + const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type, + ResourceLimitValueType::LimitValue); + if (limit_value.Failed()) { + return limit_value.Code(); + } + + *out_value = static_cast(*limit_value); + return RESULT_SUCCESS; +} + +static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit, + u32 resource_type) { + LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); + + const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type, + ResourceLimitValueType::CurrentValue); + if (current_value.Failed()) { + return current_value.Code(); + } + + *out_value = static_cast(*current_value); + return RESULT_SUCCESS; +} + +static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) { + LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, + resource_type, value); + + const auto type = static_cast(resource_type); + if (!IsValidResourceType(type)) { + LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); + return ERR_INVALID_ENUM_VALUE; + } + + auto& kernel = Core::System::GetInstance().Kernel(); + auto* const current_process = kernel.CurrentProcess(); + ASSERT(current_process != nullptr); + + auto resource_limit_object = + current_process->GetHandleTable().Get(resource_limit); + if (!resource_limit_object) { + LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", + resource_limit); + return ERR_INVALID_HANDLE; + } + + const auto set_result = resource_limit_object->SetLimitValue(type, static_cast(value)); + if (set_result.IsError()) { + LOG_ERROR( + Kernel_SVC, + "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", + resource_limit_object->GetMaxResourceValue(type), resource_type, + resource_limit_object->GetCurrentResourceValue(type)); + return set_result; + } + + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -1405,8 +1518,8 @@ static const FunctionDef SVC_Table[] = { {0x2D, nullptr, "UnmapPhysicalMemory"}, {0x2E, nullptr, "GetFutureThreadInfo"}, {0x2F, nullptr, "GetLastThreadInfo"}, - {0x30, nullptr, "GetResourceLimitLimitValue"}, - {0x31, nullptr, "GetResourceLimitCurrentValue"}, + {0x30, SvcWrap, "GetResourceLimitLimitValue"}, + {0x31, SvcWrap, "GetResourceLimitCurrentValue"}, {0x32, SvcWrap, "SetThreadActivity"}, {0x33, SvcWrap, "GetThreadContext"}, {0x34, SvcWrap, "WaitForAddress"}, @@ -1482,8 +1595,8 @@ static const FunctionDef SVC_Table[] = { {0x7A, nullptr, "StartProcess"}, {0x7B, nullptr, "TerminateProcess"}, {0x7C, SvcWrap, "GetProcessInfo"}, - {0x7D, nullptr, "CreateResourceLimit"}, - {0x7E, nullptr, "SetResourceLimitLimitValue"}, + {0x7D, SvcWrap, "CreateResourceLimit"}, + {0x7E, SvcWrap, "SetResourceLimitLimitValue"}, {0x7F, nullptr, "CallSecureMonitor"}, }; diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 233a99fb0..fa1116624 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -43,6 +43,14 @@ void SvcWrap() { FuncReturn(func(static_cast(Param(0)), static_cast(Param(1))).raw); } +template +void SvcWrap() { + u32 param = 0; + const u32 retval = func(¶m).raw; + Core::CurrentArmInterface().SetReg(1, param); + FuncReturn(retval); +} + template void SvcWrap() { u32 param_1 = 0;