Core/ResourceLimits: Implemented the basic structure of ResourceLimits.

Implemented svcs GetResourceLimit, GetResourceLimitCurrentValues and GetResourceLimitLimitValues.

Note that the resource limits do not currently keep track of used objects, since we have no way to distinguish between an object created by the application, and an object created by some HLE module once we're inside Kernel::T::Create.
This commit is contained in:
Subv 2015-05-12 15:25:15 -05:00
parent bb68933894
commit d3634d4bf4
12 changed files with 341 additions and 14 deletions

View file

@ -30,6 +30,7 @@ set(SRCS
hle/kernel/kernel.cpp
hle/kernel/mutex.cpp
hle/kernel/process.cpp
hle/kernel/resource_limit.cpp
hle/kernel/semaphore.cpp
hle/kernel/session.cpp
hle/kernel/shared_memory.cpp
@ -141,6 +142,7 @@ set(HEADERS
hle/kernel/kernel.h
hle/kernel/mutex.h
hle/kernel/process.h
hle/kernel/resource_limit.h
hle/kernel/semaphore.h
hle/kernel/session.h
hle/kernel/shared_memory.h

View file

@ -102,8 +102,8 @@ template<ResultCode func(u32)> void Wrap() {
FuncReturn(func(PARAM(0)).raw);
}
template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),
template<ResultCode func(s64*, u32, u32*, s32)> void Wrap(){
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)),
(s32)PARAM(3)).raw);
}

View file

@ -10,6 +10,7 @@
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@ -134,6 +135,7 @@ void HandleTable::Clear() {
/// Initialize the kernel
void Init() {
Kernel::ResourceLimitsInit();
Kernel::ThreadingInit();
Kernel::TimersInit();
@ -147,6 +149,7 @@ void Init() {
void Shutdown() {
Kernel::ThreadingShutdown();
Kernel::TimersShutdown();
Kernel::ResourceLimitsShutdown();
g_handle_table.Clear(); // Free all kernel objects
g_current_process = nullptr;
}

View file

@ -46,7 +46,8 @@ enum class HandleType : u32 {
Process = 8,
AddressArbiter = 9,
Semaphore = 10,
Timer = 11
Timer = 11,
ResourceLimit = 12,
};
enum {

View file

@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h"
#include "core/memory.h"

View file

@ -45,6 +45,8 @@ union ProcessFlags {
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
};
class ResourceLimit;
class Process final : public Object {
public:
static SharedPtr<Process> Create(std::string name, u64 program_id);
@ -61,6 +63,8 @@ public:
std::string name;
/// Title ID corresponding to the process
u64 program_id;
/// Resource limit descriptor for this process
SharedPtr<ResourceLimit> resource_limit;
/// The process may only call SVCs which have the corresponding bit set.
std::bitset<0x80> svc_access_mask;

View file

@ -0,0 +1,157 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/logging/log.h"
#include "core/mem_map.h"
#include "core/hle/kernel/resource_limit.h"
namespace Kernel {
static SharedPtr<ResourceLimit> resource_limits[4];
ResourceLimit::ResourceLimit() {}
ResourceLimit::~ResourceLimit() {}
SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit);
resource_limit->name = std::move(name);
return resource_limit;
}
SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) {
switch (category)
{
case ResourceLimitCategory::APPLICATION:
case ResourceLimitCategory::SYS_APPLET:
case ResourceLimitCategory::LIB_APPLET:
case ResourceLimitCategory::OTHER:
return resource_limits[static_cast<u8>(category)];
default:
LOG_CRITICAL(Kernel, "Unknown resource limit category");
UNREACHABLE();
}
}
s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
switch (resource) {
case COMMIT:
return current_commit;
case THREAD:
return current_threads;
case EVENT:
return current_events;
case MUTEX:
return current_mutexes;
case SEMAPHORE:
return current_semaphores;
case TIMER:
return current_timers;
case SHARED_MEMORY:
return current_shared_mems;
case ADDRESS_ARBITER:
return current_address_arbiters;
case CPU_TIME:
return current_cpu_time;
default:
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
UNIMPLEMENTED();
return 0;
}
}
s32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
switch (resource) {
case COMMIT:
return max_commit;
case THREAD:
return max_threads;
case EVENT:
return max_events;
case MUTEX:
return max_mutexes;
case SEMAPHORE:
return max_semaphores;
case TIMER:
return max_timers;
case SHARED_MEMORY:
return max_shared_mems;
case ADDRESS_ARBITER:
return max_address_arbiters;
case CPU_TIME:
return max_cpu_time;
default:
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
UNIMPLEMENTED();
return 0;
}
}
void ResourceLimitsInit() {
// Create the four resource limits that the system uses
// Create the APPLICATION resource limit
SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create("Applications");
resource_limit->max_priority = 0x18;
resource_limit->max_commit = 0x4000000;
resource_limit->max_threads = 0x20;
resource_limit->max_events = 0x20;
resource_limit->max_mutexes = 0x20;
resource_limit->max_semaphores = 0x8;
resource_limit->max_timers = 0x8;
resource_limit->max_shared_mems = 0x10;
resource_limit->max_address_arbiters = 0x2;
resource_limit->max_cpu_time = 0x1E;
resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
// Create the SYS_APPLET resource limit
resource_limit = ResourceLimit::Create("System Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x5E00000;
resource_limit->max_threads = 0x1D;
resource_limit->max_events = 0xB;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x3;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
// Create the LIB_APPLET resource limit
resource_limit = ResourceLimit::Create("Library Applets");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x600000;
resource_limit->max_threads = 0xE;
resource_limit->max_events = 0x8;
resource_limit->max_mutexes = 0x8;
resource_limit->max_semaphores = 0x4;
resource_limit->max_timers = 0x4;
resource_limit->max_shared_mems = 0x8;
resource_limit->max_address_arbiters = 0x1;
resource_limit->max_cpu_time = 0x2710;
resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
// Create the OTHER resource limit
resource_limit = ResourceLimit::Create("Others");
resource_limit->max_priority = 0x4;
resource_limit->max_commit = 0x2180000;
resource_limit->max_threads = 0xE1;
resource_limit->max_events = 0x108;
resource_limit->max_mutexes = 0x25;
resource_limit->max_semaphores = 0x43;
resource_limit->max_timers = 0x2C;
resource_limit->max_shared_mems = 0x1F;
resource_limit->max_address_arbiters = 0x2D;
resource_limit->max_cpu_time = 0x3E8;
resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
}
void ResourceLimitsShutdown() {
}
} // namespace

View file

@ -0,0 +1,119 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
namespace Kernel {
enum class ResourceLimitCategory : u8 {
APPLICATION = 0,
SYS_APPLET = 1,
LIB_APPLET = 2,
OTHER = 3
};
enum ResourceTypes {
PRIORITY = 0,
COMMIT = 1,
THREAD = 2,
EVENT = 3,
MUTEX = 4,
SEMAPHORE = 5,
TIMER = 6,
SHARED_MEMORY = 7,
ADDRESS_ARBITER = 8,
CPU_TIME = 9,
};
class ResourceLimit final : public Object {
public:
/**
* Creates a resource limit object.
*/
static SharedPtr<ResourceLimit> Create(std::string name = "Unknown");
/**
* Retrieves the resource limit associated with the specified resource limit category.
* @param category The resource limit category
* @returns The resource limit associated with the category
*/
static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category);
std::string GetTypeName() const override { return "ResourceLimit"; }
std::string GetName() const override { return name; }
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
/**
* Gets the current value for the specified resource.
* @param resource Requested resource type
* @returns The current value of the resource type
*/
s32 GetCurrentResourceValue(u32 resource) const;
/**
* Gets the max value for the specified resource.
* @param resource Requested resource type
* @returns The max value of the resource type
*/
s32 GetMaxResourceValue(u32 resource) const;
/// Name of resource limit object.
std::string name;
/// Max thread priority that a process in this category can create
s32 max_priority = 0;
/// Max memory that processes in this category can use
s32 max_commit = 0;
///< Max number of objects that can be collectively created by the processes in this category
s32 max_threads = 0;
s32 max_events = 0;
s32 max_mutexes = 0;
s32 max_semaphores = 0;
s32 max_timers = 0;
s32 max_shared_mems = 0;
s32 max_address_arbiters = 0;
/// Max CPU time that the processes in this category can utilize
s32 max_cpu_time = 0;
// TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
// APPLICATION resource limits should not be affected by the objects created by service modules.
// Currently we have no way of distinguishing if a Create was called by the running application,
// or by a service module. Approach this once we have separated the service modules into their own processes
/// Current memory that the processes in this category are using
s32 current_commit = 0;
///< Current number of objects among all processes in this category
s32 current_threads = 0;
s32 current_events = 0;
s32 current_mutexes = 0;
s32 current_semaphores = 0;
s32 current_timers = 0;
s32 current_shared_mems = 0;
s32 current_address_arbiters = 0;
/// Current CPU time that the processes in this category are utilizing
s32 current_cpu_time = 0;
private:
ResourceLimit();
~ResourceLimit() override;
};
/// Initializes the resource limits
void ResourceLimitsInit();
// Destroys the resource limits
void ResourceLimitsShutdown();
} // namespace

View file

@ -17,6 +17,7 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
@ -301,21 +302,47 @@ static void OutputDebugString(const char* string) {
}
/// Get resource limit
static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) {
// With regards to proceess values:
// 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
// the current KThread.
*resource_limit = 0xDEADBEEF;
LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
if (process == nullptr)
return ERR_INVALID_HANDLE;
CASCADE_RESULT(*resource_limit, Kernel::g_handle_table.Create(process->resource_limit));
return RESULT_SUCCESS;
}
/// Get resource limit current values
static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names,
s32 name_count) {
LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%p, name_count=%d",
resource_limit, names, name_count);
values[0] = 0; // Normmatt: Set used memory to 0 for now
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
if (resource_limit == nullptr)
return ERR_INVALID_HANDLE;
for (unsigned int i = 0; i < name_count; ++i)
values[i] = resource_limit->GetCurrentResourceValue(names[i]);
return RESULT_SUCCESS;
}
/// Get resource limit max values
static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
s32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle);
if (resource_limit == nullptr)
return ERR_INVALID_HANDLE;
for (unsigned int i = 0; i < name_count; ++i)
values[i] = resource_limit->GetMaxResourceValue(names[i]);
return RESULT_SUCCESS;
}
@ -707,7 +734,7 @@ static const FunctionDef SVC_Table[] = {
{0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"},
{0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
{0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
{0x39, nullptr, "GetResourceLimitLimitValues"},
{0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"},
{0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
{0x3B, nullptr, "GetThreadContext"},
{0x3C, nullptr, "Break"},

View file

@ -9,6 +9,7 @@
#include "core/file_sys/archive_romfs.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/fs/archive.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
@ -234,6 +235,9 @@ ResultStatus AppLoader_THREEDSX::Load() {
Kernel::g_current_process->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings;
// Attach the default resource limit (APPLICATION) to the process
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR);
Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);

View file

@ -11,6 +11,7 @@
#include "common/symbols.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/elf.h"
#include "core/memory.h"
@ -354,6 +355,9 @@ ResultStatus AppLoader_ELF::Load() {
Kernel::g_current_process->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings;
// Attach the default resource limit (APPLICATION) to the process
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
ElfReader elf_reader(&buffer[0]);
elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
// TODO: Fill application title

View file

@ -11,6 +11,7 @@
#include "common/swap.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/ncch.h"
#include "core/memory.h"
@ -126,6 +127,10 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
Kernel::g_current_process = Kernel::Process::Create(process_name, program_id);
// Attach a resource limit to the process based on the resource limit category
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(
static_cast<Kernel::ResourceLimitCategory>(exheader_header.arm11_system_local_caps.resource_limit_category));
// Copy data while converting endianess
std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps;
std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));