Merge pull request #1805 from lioncash/resource
svc: Implement svcCreateResourceLimit, svcGetResourceLimitCurrentValue(), svcGetResourceLimitLimitValue(), and svcSetResourceLimitLimitValue()
This commit is contained in:
commit
852a462df3
|
@ -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:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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"},
|
{0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
|
||||||
{0x31, nullptr, "GetResourceLimitCurrentValue"},
|
{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"},
|
{0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"},
|
||||||
{0x7E, nullptr, "SetResourceLimitLimitValue"},
|
{0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
|
||||||
{0x7F, nullptr, "CallSecureMonitor"},
|
{0x7F, nullptr, "CallSecureMonitor"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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(¶m).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;
|
||||||
|
|
Reference in New Issue