Bläddra i källkod

Merge pull request #1805 from lioncash/resource

svc: Implement svcCreateResourceLimit, svcGetResourceLimitCurrentValue(), svcGetResourceLimitLimitValue(), and svcSetResourceLimitLimitValue()
bunnei 7 år sedan
förälder
incheckning
852a462df3
3 ändrade filer med 130 tillägg och 5 borttagningar
  1. 5 1
      src/core/hle/kernel/resource_limit.h
  2. 117 4
      src/core/hle/kernel/svc.cpp
  3. 8 0
      src/core/hle/kernel/svc_wrap.h

+ 5 - 1
src/core/hle/kernel/resource_limit.h

@@ -14,7 +14,7 @@ namespace Kernel {
 
 
 class KernelCore;
 class KernelCore;
 
 
-enum class ResourceType {
+enum class ResourceType : u32 {
     PhysicalMemory,
     PhysicalMemory,
     Threads,
     Threads,
     Events,
     Events,
@@ -25,6 +25,10 @@ enum class ResourceType {
     ResourceTypeCount
     ResourceTypeCount
 };
 };
 
 
+constexpr bool IsValidResourceType(ResourceType type) {
+    return type < ResourceType::ResourceTypeCount;
+}
+
 class ResourceLimit final : public Object {
 class ResourceLimit final : public Object {
 public:
 public:
     /**
     /**

+ 117 - 4
src/core/hle/kernel/svc.cpp

@@ -105,6 +105,38 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
 
 
     return RESULT_SUCCESS;
     return RESULT_SUCCESS;
 }
 }
+
+enum class ResourceLimitValueType {
+    CurrentValue,
+    LimitValue,
+};
+
+ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type,
+                                          ResourceLimitValueType value_type) {
+    const auto type = static_cast<ResourceType>(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<ResourceLimit>(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
 } // Anonymous namespace
 
 
 /// Set the process heap to a given Size. It can both extend and shrink the heap.
 /// 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;
     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<u64>(*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<u64>(*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<ResourceType>(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<ResourceLimit>(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<s64>(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 {
 namespace {
 struct FunctionDef {
 struct FunctionDef {
     using Func = void();
     using Func = void();
@@ -1405,8 +1518,8 @@ static const FunctionDef SVC_Table[] = {
     {0x2D, nullptr, "UnmapPhysicalMemory"},
     {0x2D, nullptr, "UnmapPhysicalMemory"},
     {0x2E, nullptr, "GetFutureThreadInfo"},
     {0x2E, nullptr, "GetFutureThreadInfo"},
     {0x2F, nullptr, "GetLastThreadInfo"},
     {0x2F, nullptr, "GetLastThreadInfo"},
-    {0x30, nullptr, "GetResourceLimitLimitValue"},
-    {0x31, nullptr, "GetResourceLimitCurrentValue"},
+    {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
+    {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
     {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
     {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
     {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
     {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
     {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
     {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
@@ -1482,8 +1595,8 @@ static const FunctionDef SVC_Table[] = {
     {0x7A, nullptr, "StartProcess"},
     {0x7A, nullptr, "StartProcess"},
     {0x7B, nullptr, "TerminateProcess"},
     {0x7B, nullptr, "TerminateProcess"},
     {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
     {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
-    {0x7D, nullptr, "CreateResourceLimit"},
-    {0x7E, nullptr, "SetResourceLimitLimitValue"},
+    {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"},
+    {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
     {0x7F, nullptr, "CallSecureMonitor"},
     {0x7F, nullptr, "CallSecureMonitor"},
 };
 };
 
 

+ 8 - 0
src/core/hle/kernel/svc_wrap.h

@@ -43,6 +43,14 @@ void SvcWrap() {
     FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
     FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
 }
 }
 
 
+template <ResultCode func(u32*)>
+void SvcWrap() {
+    u32 param = 0;
+    const u32 retval = func(&param).raw;
+    Core::CurrentArmInterface().SetReg(1, param);
+    FuncReturn(retval);
+}
+
 template <ResultCode func(u32*, u32)>
 template <ResultCode func(u32*, u32)>
 void SvcWrap() {
 void SvcWrap() {
     u32 param_1 = 0;
     u32 param_1 = 0;