Merge pull request #1805 from lioncash/resource

svc: Implement svcCreateResourceLimit, svcGetResourceLimitCurrentValue(), svcGetResourceLimitLimitValue(), and svcSetResourceLimitLimitValue()
This commit is contained in:
bunnei 2018-11-26 22:59:51 -05:00 committed by GitHub
commit 852a462df3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 5 deletions

View file

@ -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:
/** /**

View file

@ -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"},
}; };

View file

@ -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;