aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Subv <subv2112@gmail.com>2015-05-12 15:25:15 -0500
committerGravatar Subv <subv2112@gmail.com>2015-05-14 22:50:13 -0500
commitd3634d4bf4b1cbd8cc4fe6f22178054803b41e23 (patch)
tree2fa606ebac3e2e77e65e1196878a5f5345acfacf
parentbb689338943791c735c7c6adb186256457e064b4 (diff)
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.
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/function_wrappers.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp3
-rw-r--r--src/core/hle/kernel/kernel.h3
-rw-r--r--src/core/hle/kernel/process.cpp1
-rw-r--r--src/core/hle/kernel/process.h4
-rw-r--r--src/core/hle/kernel/resource_limit.cpp157
-rw-r--r--src/core/hle/kernel/resource_limit.h119
-rw-r--r--src/core/hle/svc.cpp49
-rw-r--r--src/core/loader/3dsx.cpp4
-rw-r--r--src/core/loader/elf.cpp4
-rw-r--r--src/core/loader/ncch.cpp5
12 files changed, 341 insertions, 14 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e8d8c96d..5caaee47 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -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
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index eb52c8fb..0e5ae29a 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -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);
}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b5c98b24..726e4d2f 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -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;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7c106d37..28748c8f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -46,7 +46,8 @@ enum class HandleType : u32 {
Process = 8,
AddressArbiter = 9,
Semaphore = 10,
- Timer = 11
+ Timer = 11,
+ ResourceLimit = 12,
};
enum {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0cdfa58d..b5c87e88 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -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"
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 90881054..7b8a6861 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -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;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
new file mode 100644
index 00000000..94b3e329
--- /dev/null
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -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
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
new file mode 100644
index 00000000..201ec0db
--- /dev/null
+++ b/src/core/hle/kernel/resource_limit.h
@@ -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
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 9bf88625..654ee2bf 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -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_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_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->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"},
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 84b13ee5..ad5e929c 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -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"
@@ -233,6 +234,9 @@ ResultStatus AppLoader_THREEDSX::Load() {
Kernel::g_current_process = Kernel::Process::Create(filename, 0);
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);
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index a951bc80..f00753a7 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -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
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 36e341fd..08993c4f 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -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));