Merge pull request #761 from Subv/resource_limits

Core/ResourceLimits: Implemented the basic structure of ResourceLimits.
master
bunnei 2015-05-15 09:42:36 +07:00
commit ef8d0e9823
12 changed files with 341 additions and 14 deletions

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

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

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

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

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

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

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

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

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

@ -9,6 +9,7 @@
#include "core/file_sys/archive_romfs.h" #include "core/file_sys/archive_romfs.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/archive.h"
#include "core/loader/elf.h" #include "core/loader/elf.h"
#include "core/loader/ncch.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->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings; 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); Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR);
Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);

@ -11,6 +11,7 @@
#include "common/symbols.h" #include "common/symbols.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/elf.h" #include "core/loader/elf.h"
#include "core/memory.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->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings; 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]); ElfReader elf_reader(&buffer[0]);
elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
// TODO: Fill application title // TODO: Fill application title

@ -11,6 +11,7 @@
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/ncch.h" #include "core/loader/ncch.h"
#include "core/memory.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]); u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); 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 // Copy data while converting endianess
std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps; 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)); std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));