summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h4
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h57
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp152
-rw-r--r--src/core/hle/kernel/k_resource_limit.h81
-rw-r--r--src/core/hle/kernel/k_thread.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp26
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp10
-rw-r--r--src/core/hle/kernel/process.cpp24
-rw-r--r--src/core/hle/kernel/process.h6
-rw-r--r--src/core/hle/kernel/resource_limit.cpp73
-rw-r--r--src/core/hle/kernel/resource_limit.h106
-rw-r--r--src/core/hle/kernel/svc.cpp25
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp10
-rw-r--r--src/core/hle/service/hid/hid.cpp13
-rw-r--r--src/core/hle/service/nifm/nifm.cpp165
-rw-r--r--src/core/settings.cpp3
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp2
20 files changed, 535 insertions, 240 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 397cc028f..0ee02c81d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -160,9 +160,12 @@ add_library(core STATIC
160 hle/kernel/k_affinity_mask.h 160 hle/kernel/k_affinity_mask.h
161 hle/kernel/k_condition_variable.cpp 161 hle/kernel/k_condition_variable.cpp
162 hle/kernel/k_condition_variable.h 162 hle/kernel/k_condition_variable.h
163 hle/kernel/k_light_condition_variable.h
163 hle/kernel/k_light_lock.cpp 164 hle/kernel/k_light_lock.cpp
164 hle/kernel/k_light_lock.h 165 hle/kernel/k_light_lock.h
165 hle/kernel/k_priority_queue.h 166 hle/kernel/k_priority_queue.h
167 hle/kernel/k_resource_limit.cpp
168 hle/kernel/k_resource_limit.h
166 hle/kernel/k_scheduler.cpp 169 hle/kernel/k_scheduler.cpp
167 hle/kernel/k_scheduler.h 170 hle/kernel/k_scheduler.h
168 hle/kernel/k_scheduler_lock.h 171 hle/kernel/k_scheduler_lock.h
@@ -203,8 +206,6 @@ add_library(core STATIC
203 hle/kernel/process_capability.h 206 hle/kernel/process_capability.h
204 hle/kernel/readable_event.cpp 207 hle/kernel/readable_event.cpp
205 hle/kernel/readable_event.h 208 hle/kernel/readable_event.h
206 hle/kernel/resource_limit.cpp
207 hle/kernel/resource_limit.h
208 hle/kernel/server_port.cpp 209 hle/kernel/server_port.cpp
209 hle/kernel/server_port.h 210 hle/kernel/server_port.h
210 hle/kernel/server_session.cpp 211 hle/kernel/server_session.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index c650a4dfb..ec4407b6e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -71,8 +71,9 @@ public:
71 } 71 }
72 72
73 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 73 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
74 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 74 LOG_CRITICAL(Core_ARM,
75 exception, pc, MemoryReadCode(pc)); 75 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
76 exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
76 UNIMPLEMENTED(); 77 UNIMPLEMENTED();
77 } 78 }
78 79
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 35e9ced48..f6c4d4db9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -50,6 +50,10 @@ public:
50 u64 GetTPIDR_EL0() const override; 50 u64 GetTPIDR_EL0() const override;
51 void ChangeProcessorID(std::size_t new_core_id) override; 51 void ChangeProcessorID(std::size_t new_core_id) override;
52 52
53 bool IsInThumbMode() const {
54 return (GetPSTATE() & 0x20) != 0;
55 }
56
53 void SaveContext(ThreadContext32& ctx) override; 57 void SaveContext(ThreadContext32& ctx) override;
54 void SaveContext(ThreadContext64& ctx) override {} 58 void SaveContext(ThreadContext64& ctx) override {}
55 void LoadContext(const ThreadContext32& ctx) override; 59 void LoadContext(const ThreadContext32& ctx) override;
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
new file mode 100644
index 000000000..362d0db28
--- /dev/null
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -0,0 +1,57 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/common_types.h"
11#include "core/hle/kernel/k_scheduler.h"
12#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
13#include "core/hle/kernel/k_thread_queue.h"
14#include "core/hle/kernel/time_manager.h"
15
16namespace Kernel {
17class KernelCore;
18
19class KLightConditionVariable {
20public:
21 explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {}
22
23 void Wait(KLightLock* lock, s64 timeout = -1) {
24 WaitImpl(lock, timeout);
25 lock->Lock();
26 }
27
28 void Broadcast() {
29 KScopedSchedulerLock lk{kernel};
30 while (thread_queue.WakeupFrontThread() != nullptr) {
31 // We want to signal all threads, and so should continue waking up until there's nothing
32 // to wake.
33 }
34 }
35
36private:
37 void WaitImpl(KLightLock* lock, s64 timeout) {
38 KThread* owner = GetCurrentThreadPointer(kernel);
39
40 // Sleep the thread.
41 {
42 KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
43 lock->Unlock();
44
45 if (!thread_queue.SleepThread(owner)) {
46 lk.CancelSleep();
47 return;
48 }
49 }
50
51 // Cancel the task that the sleep setup.
52 kernel.TimeManager().UnscheduleTimeEvent(owner);
53 }
54 KThreadQueue thread_queue;
55 KernelCore& kernel;
56};
57} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
new file mode 100644
index 000000000..ab2ab683f
--- /dev/null
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -0,0 +1,152 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#include "common/assert.h"
9#include "core/core.h"
10#include "core/core_timing.h"
11#include "core/core_timing_util.h"
12#include "core/hle/kernel/k_resource_limit.h"
13#include "core/hle/kernel/svc_results.h"
14
15namespace Kernel {
16constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
17
18KResourceLimit::KResourceLimit(KernelCore& kernel, Core::System& system)
19 : Object{kernel}, lock{kernel}, cond_var{kernel}, kernel{kernel}, system(system) {}
20KResourceLimit::~KResourceLimit() = default;
21
22s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
23 const auto index = static_cast<std::size_t>(which);
24 s64 value{};
25 {
26 KScopedLightLock lk{lock};
27 value = limit_values[index];
28 ASSERT(value >= 0);
29 ASSERT(current_values[index] <= limit_values[index]);
30 ASSERT(current_hints[index] <= current_values[index]);
31 }
32 return value;
33}
34
35s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
36 const auto index = static_cast<std::size_t>(which);
37 s64 value{};
38 {
39 KScopedLightLock lk{lock};
40 value = current_values[index];
41 ASSERT(value >= 0);
42 ASSERT(current_values[index] <= limit_values[index]);
43 ASSERT(current_hints[index] <= current_values[index]);
44 }
45 return value;
46}
47
48s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
49 const auto index = static_cast<std::size_t>(which);
50 s64 value{};
51 {
52 KScopedLightLock lk{lock};
53 value = peak_values[index];
54 ASSERT(value >= 0);
55 ASSERT(current_values[index] <= limit_values[index]);
56 ASSERT(current_hints[index] <= current_values[index]);
57 }
58 return value;
59}
60
61s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
62 const auto index = static_cast<std::size_t>(which);
63 s64 value{};
64 {
65 KScopedLightLock lk(lock);
66 ASSERT(current_values[index] >= 0);
67 ASSERT(current_values[index] <= limit_values[index]);
68 ASSERT(current_hints[index] <= current_values[index]);
69 value = limit_values[index] - current_values[index];
70 }
71
72 return value;
73}
74
75ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
76 const auto index = static_cast<std::size_t>(which);
77 KScopedLightLock lk(lock);
78 R_UNLESS(current_values[index] <= value, Svc::ResultInvalidState);
79
80 limit_values[index] = value;
81
82 return RESULT_SUCCESS;
83}
84
85bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
86 return Reserve(which, value, system.CoreTiming().GetGlobalTimeNs().count() + DefaultTimeout);
87}
88
89bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
90 ASSERT(value >= 0);
91 const auto index = static_cast<std::size_t>(which);
92 KScopedLightLock lk(lock);
93
94 ASSERT(current_hints[index] <= current_values[index]);
95 if (current_hints[index] >= limit_values[index]) {
96 return false;
97 }
98
99 // Loop until we reserve or run out of time.
100 while (true) {
101 ASSERT(current_values[index] <= limit_values[index]);
102 ASSERT(current_hints[index] <= current_values[index]);
103
104 // If we would overflow, don't allow to succeed.
105 if (current_values[index] + value <= current_values[index]) {
106 break;
107 }
108
109 if (current_values[index] + value <= limit_values[index]) {
110 current_values[index] += value;
111 current_hints[index] += value;
112 peak_values[index] = std::max(peak_values[index], current_values[index]);
113 return true;
114 }
115
116 if (current_hints[index] + value <= limit_values[index] &&
117 (timeout < 0 || system.CoreTiming().GetGlobalTimeNs().count() < timeout)) {
118 waiter_count++;
119 cond_var.Wait(&lock, timeout);
120 waiter_count--;
121 } else {
122 break;
123 }
124 }
125
126 return false;
127}
128
129void KResourceLimit::Release(LimitableResource which, s64 value) {
130 Release(which, value, value);
131}
132
133void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
134 ASSERT(value >= 0);
135 ASSERT(hint >= 0);
136
137 const auto index = static_cast<std::size_t>(which);
138 KScopedLightLock lk(lock);
139 ASSERT(current_values[index] <= limit_values[index]);
140 ASSERT(current_hints[index] <= current_values[index]);
141 ASSERT(value <= current_values[index]);
142 ASSERT(hint <= current_hints[index]);
143
144 current_values[index] -= value;
145 current_hints[index] -= hint;
146
147 if (waiter_count != 0) {
148 cond_var.Broadcast();
149 }
150}
151
152} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
new file mode 100644
index 000000000..58ae456f1
--- /dev/null
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -0,0 +1,81 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include <array>
11#include "common/common_types.h"
12#include "core/hle/kernel/k_light_condition_variable.h"
13#include "core/hle/kernel/k_light_lock.h"
14#include "core/hle/kernel/object.h"
15
16union ResultCode;
17
18namespace Core {
19class System;
20}
21
22namespace Kernel {
23class KernelCore;
24enum class LimitableResource : u32 {
25 PhysicalMemory = 0,
26 Threads = 1,
27 Events = 2,
28 TransferMemory = 3,
29 Sessions = 4,
30
31 Count,
32};
33
34constexpr bool IsValidResourceType(LimitableResource type) {
35 return type < LimitableResource::Count;
36}
37
38class KResourceLimit final : public Object {
39public:
40 explicit KResourceLimit(KernelCore& kernel, Core::System& system);
41 ~KResourceLimit();
42
43 s64 GetLimitValue(LimitableResource which) const;
44 s64 GetCurrentValue(LimitableResource which) const;
45 s64 GetPeakValue(LimitableResource which) const;
46 s64 GetFreeValue(LimitableResource which) const;
47
48 ResultCode SetLimitValue(LimitableResource which, s64 value);
49
50 bool Reserve(LimitableResource which, s64 value);
51 bool Reserve(LimitableResource which, s64 value, s64 timeout);
52 void Release(LimitableResource which, s64 value);
53 void Release(LimitableResource which, s64 value, s64 hint);
54
55 std::string GetTypeName() const override {
56 return "KResourceLimit";
57 }
58 std::string GetName() const override {
59 return GetTypeName();
60 }
61
62 static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
63 HandleType GetHandleType() const override {
64 return HANDLE_TYPE;
65 }
66
67 virtual void Finalize() override {}
68
69private:
70 using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
71 ResourceArray limit_values{};
72 ResourceArray current_values{};
73 ResourceArray current_hints{};
74 ResourceArray peak_values{};
75 mutable KLightLock lock;
76 s32 waiter_count{};
77 KLightConditionVariable cond_var;
78 KernelCore& kernel;
79 Core::System& system;
80};
81} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index aa100e139..b59259c4f 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -21,6 +21,7 @@
21#include "core/hle/kernel/errors.h" 21#include "core/hle/kernel/errors.h"
22#include "core/hle/kernel/handle_table.h" 22#include "core/hle/kernel/handle_table.h"
23#include "core/hle/kernel/k_condition_variable.h" 23#include "core/hle/kernel/k_condition_variable.h"
24#include "core/hle/kernel/k_resource_limit.h"
24#include "core/hle/kernel/k_scheduler.h" 25#include "core/hle/kernel/k_scheduler.h"
25#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 26#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
26#include "core/hle/kernel/k_thread.h" 27#include "core/hle/kernel/k_thread.h"
@@ -29,7 +30,6 @@
29#include "core/hle/kernel/memory/memory_layout.h" 30#include "core/hle/kernel/memory/memory_layout.h"
30#include "core/hle/kernel/object.h" 31#include "core/hle/kernel/object.h"
31#include "core/hle/kernel/process.h" 32#include "core/hle/kernel/process.h"
32#include "core/hle/kernel/resource_limit.h"
33#include "core/hle/kernel/svc_results.h" 33#include "core/hle/kernel/svc_results.h"
34#include "core/hle/kernel/time_manager.h" 34#include "core/hle/kernel/time_manager.h"
35#include "core/hle/result.h" 35#include "core/hle/result.h"
@@ -247,7 +247,7 @@ void KThread::Finalize() {
247 // Decrement the parent process's thread count. 247 // Decrement the parent process's thread count.
248 if (parent != nullptr) { 248 if (parent != nullptr) {
249 parent->DecrementThreadCount(); 249 parent->DecrementThreadCount();
250 parent->GetResourceLimit()->Release(ResourceType::Threads, 1); 250 parent->GetResourceLimit()->Release(LimitableResource::Threads, 1);
251 } 251 }
252} 252}
253 253
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index df309d523..b20c2d13a 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -28,6 +28,7 @@
28#include "core/hle/kernel/client_port.h" 28#include "core/hle/kernel/client_port.h"
29#include "core/hle/kernel/errors.h" 29#include "core/hle/kernel/errors.h"
30#include "core/hle/kernel/handle_table.h" 30#include "core/hle/kernel/handle_table.h"
31#include "core/hle/kernel/k_resource_limit.h"
31#include "core/hle/kernel/k_scheduler.h" 32#include "core/hle/kernel/k_scheduler.h"
32#include "core/hle/kernel/k_thread.h" 33#include "core/hle/kernel/k_thread.h"
33#include "core/hle/kernel/kernel.h" 34#include "core/hle/kernel/kernel.h"
@@ -36,7 +37,6 @@
36#include "core/hle/kernel/memory/slab_heap.h" 37#include "core/hle/kernel/memory/slab_heap.h"
37#include "core/hle/kernel/physical_core.h" 38#include "core/hle/kernel/physical_core.h"
38#include "core/hle/kernel/process.h" 39#include "core/hle/kernel/process.h"
39#include "core/hle/kernel/resource_limit.h"
40#include "core/hle/kernel/service_thread.h" 40#include "core/hle/kernel/service_thread.h"
41#include "core/hle/kernel/shared_memory.h" 41#include "core/hle/kernel/shared_memory.h"
42#include "core/hle/kernel/time_manager.h" 42#include "core/hle/kernel/time_manager.h"
@@ -66,7 +66,7 @@ struct KernelCore::Impl {
66 is_phantom_mode_for_singlecore = false; 66 is_phantom_mode_for_singlecore = false;
67 67
68 InitializePhysicalCores(); 68 InitializePhysicalCores();
69 InitializeSystemResourceLimit(kernel); 69 InitializeSystemResourceLimit(kernel, system);
70 InitializeMemoryLayout(); 70 InitializeMemoryLayout();
71 InitializePreemption(kernel); 71 InitializePreemption(kernel);
72 InitializeSchedulers(); 72 InitializeSchedulers();
@@ -131,19 +131,19 @@ struct KernelCore::Impl {
131 } 131 }
132 132
133 // Creates the default system resource limit 133 // Creates the default system resource limit
134 void InitializeSystemResourceLimit(KernelCore& kernel) { 134 void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
135 system_resource_limit = ResourceLimit::Create(kernel); 135 system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
136 136
137 // If setting the default system values fails, then something seriously wrong has occurred. 137 // If setting the default system values fails, then something seriously wrong has occurred.
138 ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x100000000) 138 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
139 .IsSuccess()); 139 .IsSuccess());
140 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess()); 140 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
141 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess()); 141 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
142 ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess()); 142 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
143 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); 143 .IsSuccess());
144 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess());
144 145
145 if (!system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0) || 146 if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) {
146 !system_resource_limit->Reserve(ResourceType::PhysicalMemory, 0x60000)) {
147 UNREACHABLE(); 147 UNREACHABLE();
148 } 148 }
149 } 149 }
@@ -320,7 +320,7 @@ struct KernelCore::Impl {
320 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; 320 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
321 Kernel::TimeManager time_manager; 321 Kernel::TimeManager time_manager;
322 322
323 std::shared_ptr<ResourceLimit> system_resource_limit; 323 std::shared_ptr<KResourceLimit> system_resource_limit;
324 324
325 std::shared_ptr<Core::Timing::EventType> preemption_event; 325 std::shared_ptr<Core::Timing::EventType> preemption_event;
326 326
@@ -390,7 +390,7 @@ void KernelCore::Shutdown() {
390 impl->Shutdown(); 390 impl->Shutdown();
391} 391}
392 392
393std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { 393std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
394 return impl->system_resource_limit; 394 return impl->system_resource_limit;
395} 395}
396 396
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index e7c77727b..806a0d986 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -38,7 +38,7 @@ class GlobalSchedulerContext;
38class HandleTable; 38class HandleTable;
39class PhysicalCore; 39class PhysicalCore;
40class Process; 40class Process;
41class ResourceLimit; 41class KResourceLimit;
42class KScheduler; 42class KScheduler;
43class SharedMemory; 43class SharedMemory;
44class ServiceThread; 44class ServiceThread;
@@ -85,7 +85,7 @@ public:
85 void Shutdown(); 85 void Shutdown();
86 86
87 /// Retrieves a shared pointer to the system resource limit instance. 87 /// Retrieves a shared pointer to the system resource limit instance.
88 std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; 88 std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
89 89
90 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. 90 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
91 std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; 91 std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index 080886554..7de91c768 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -7,6 +7,7 @@
7#include "common/scope_exit.h" 7#include "common/scope_exit.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/errors.h" 9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/k_resource_limit.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory/address_space_info.h" 12#include "core/hle/kernel/memory/address_space_info.h"
12#include "core/hle/kernel/memory/memory_block.h" 13#include "core/hle/kernel/memory/memory_block.h"
@@ -15,7 +16,6 @@
15#include "core/hle/kernel/memory/page_table.h" 16#include "core/hle/kernel/memory/page_table.h"
16#include "core/hle/kernel/memory/system_control.h" 17#include "core/hle/kernel/memory/system_control.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/resource_limit.h"
19#include "core/memory.h" 19#include "core/memory.h"
20 20
21namespace Kernel::Memory { 21namespace Kernel::Memory {
@@ -414,7 +414,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
414 const std::size_t remaining_pages{remaining_size / PageSize}; 414 const std::size_t remaining_pages{remaining_size / PageSize};
415 415
416 if (process->GetResourceLimit() && 416 if (process->GetResourceLimit() &&
417 !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, remaining_size)) { 417 !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) {
418 return ERR_RESOURCE_LIMIT_EXCEEDED; 418 return ERR_RESOURCE_LIMIT_EXCEEDED;
419 } 419 }
420 420
@@ -422,7 +422,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
422 { 422 {
423 auto block_guard = detail::ScopeExit([&] { 423 auto block_guard = detail::ScopeExit([&] {
424 system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); 424 system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool);
425 process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, remaining_size); 425 process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size);
426 }); 426 });
427 427
428 CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, 428 CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages,
@@ -474,7 +474,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
474 CASCADE_CODE(UnmapMemory(addr, size)); 474 CASCADE_CODE(UnmapMemory(addr, size));
475 475
476 auto process{system.Kernel().CurrentProcess()}; 476 auto process{system.Kernel().CurrentProcess()};
477 process->GetResourceLimit()->Release(ResourceType::PhysicalMemory, mapped_size); 477 process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
478 physical_memory_usage -= mapped_size; 478 physical_memory_usage -= mapped_size;
479 479
480 return RESULT_SUCCESS; 480 return RESULT_SUCCESS;
@@ -783,7 +783,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
783 783
784 auto process{system.Kernel().CurrentProcess()}; 784 auto process{system.Kernel().CurrentProcess()};
785 if (process->GetResourceLimit() && delta != 0 && 785 if (process->GetResourceLimit() && delta != 0 &&
786 !process->GetResourceLimit()->Reserve(ResourceType::PhysicalMemory, delta)) { 786 !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) {
787 return ERR_RESOURCE_LIMIT_EXCEEDED; 787 return ERR_RESOURCE_LIMIT_EXCEEDED;
788 } 788 }
789 789
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0edbfc4cc..afdb27c54 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -15,6 +15,7 @@
15#include "core/file_sys/program_metadata.h" 15#include "core/file_sys/program_metadata.h"
16#include "core/hle/kernel/code_set.h" 16#include "core/hle/kernel/code_set.h"
17#include "core/hle/kernel/errors.h" 17#include "core/hle/kernel/errors.h"
18#include "core/hle/kernel/k_resource_limit.h"
18#include "core/hle/kernel/k_scheduler.h" 19#include "core/hle/kernel/k_scheduler.h"
19#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
20#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
@@ -22,7 +23,6 @@
22#include "core/hle/kernel/memory/page_table.h" 23#include "core/hle/kernel/memory/page_table.h"
23#include "core/hle/kernel/memory/slab_heap.h" 24#include "core/hle/kernel/memory/slab_heap.h"
24#include "core/hle/kernel/process.h" 25#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/resource_limit.h"
26#include "core/hle/lock.h" 26#include "core/hle/lock.h"
27#include "core/memory.h" 27#include "core/memory.h"
28#include "core/settings.h" 28#include "core/settings.h"
@@ -116,7 +116,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
116 116
117 std::shared_ptr<Process> process = std::make_shared<Process>(system); 117 std::shared_ptr<Process> process = std::make_shared<Process>(system);
118 process->name = std::move(name); 118 process->name = std::move(name);
119 process->resource_limit = ResourceLimit::Create(kernel); 119 process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
120 process->status = ProcessStatus::Created; 120 process->status = ProcessStatus::Created;
121 process->program_id = 0; 121 process->program_id = 0;
122 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() 122 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -132,7 +132,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
132 return process; 132 return process;
133} 133}
134 134
135std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { 135std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
136 return resource_limit; 136 return resource_limit;
137} 137}
138 138
@@ -154,7 +154,7 @@ void Process::DecrementThreadCount() {
154} 154}
155 155
156u64 Process::GetTotalPhysicalMemoryAvailable() const { 156u64 Process::GetTotalPhysicalMemoryAvailable() const {
157 const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) + 157 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
158 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + 158 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
159 main_thread_stack_size}; 159 main_thread_stack_size};
160 160
@@ -308,13 +308,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
308 308
309 // Set initial resource limits 309 // Set initial resource limits
310 resource_limit->SetLimitValue( 310 resource_limit->SetLimitValue(
311 ResourceType::PhysicalMemory, 311 LimitableResource::PhysicalMemory,
312 kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); 312 kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
313 resource_limit->SetLimitValue(ResourceType::Threads, 608); 313 resource_limit->SetLimitValue(LimitableResource::Threads, 608);
314 resource_limit->SetLimitValue(ResourceType::Events, 700); 314 resource_limit->SetLimitValue(LimitableResource::Events, 700);
315 resource_limit->SetLimitValue(ResourceType::TransferMemory, 128); 315 resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
316 resource_limit->SetLimitValue(ResourceType::Sessions, 894); 316 resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
317 ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size)); 317 ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size));
318 318
319 // Create TLS region 319 // Create TLS region
320 tls_region_address = CreateTLSRegion(); 320 tls_region_address = CreateTLSRegion();
@@ -331,8 +331,8 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
331 ChangeStatus(ProcessStatus::Running); 331 ChangeStatus(ProcessStatus::Running);
332 332
333 SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); 333 SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
334 resource_limit->Reserve(ResourceType::Threads, 1); 334 resource_limit->Reserve(LimitableResource::Threads, 1);
335 resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size); 335 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
336} 336}
337 337
338void Process::PrepareForTermination() { 338void Process::PrepareForTermination() {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 26e647743..c8af76ce8 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -29,7 +29,7 @@ class ProgramMetadata;
29namespace Kernel { 29namespace Kernel {
30 30
31class KernelCore; 31class KernelCore;
32class ResourceLimit; 32class KResourceLimit;
33class KThread; 33class KThread;
34class TLSPage; 34class TLSPage;
35 35
@@ -170,7 +170,7 @@ public:
170 } 170 }
171 171
172 /// Gets the resource limit descriptor for this process 172 /// Gets the resource limit descriptor for this process
173 std::shared_ptr<ResourceLimit> GetResourceLimit() const; 173 std::shared_ptr<KResourceLimit> GetResourceLimit() const;
174 174
175 /// Gets the ideal CPU core ID for this process 175 /// Gets the ideal CPU core ID for this process
176 u8 GetIdealCoreId() const { 176 u8 GetIdealCoreId() const {
@@ -402,7 +402,7 @@ private:
402 u32 system_resource_size = 0; 402 u32 system_resource_size = 0;
403 403
404 /// Resource limit descriptor for this process 404 /// Resource limit descriptor for this process
405 std::shared_ptr<ResourceLimit> resource_limit; 405 std::shared_ptr<KResourceLimit> resource_limit;
406 406
407 /// The ideal CPU core for this process, threads are scheduled on this core by default. 407 /// The ideal CPU core for this process, threads are scheduled on this core by default.
408 u8 ideal_core = 0; 408 u8 ideal_core = 0;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
deleted file mode 100644
index 7bf50339d..000000000
--- a/src/core/hle/kernel/resource_limit.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/errors.h"
6#include "core/hle/kernel/resource_limit.h"
7#include "core/hle/result.h"
8
9namespace Kernel {
10namespace {
11constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
12 return static_cast<std::size_t>(type);
13}
14} // Anonymous namespace
15
16ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
17ResourceLimit::~ResourceLimit() = default;
18
19bool ResourceLimit::Reserve(ResourceType resource, s64 amount) {
20 return Reserve(resource, amount, 10000000000);
21}
22
23bool ResourceLimit::Reserve(ResourceType resource, s64 amount, u64 timeout) {
24 const std::size_t index{ResourceTypeToIndex(resource)};
25
26 s64 new_value = current[index] + amount;
27 if (new_value > limit[index] && available[index] + amount <= limit[index]) {
28 // TODO(bunnei): This is wrong for multicore, we should wait the calling thread for timeout
29 new_value = current[index] + amount;
30 }
31
32 if (new_value <= limit[index]) {
33 current[index] = new_value;
34 return true;
35 }
36 return false;
37}
38
39void ResourceLimit::Release(ResourceType resource, u64 amount) {
40 Release(resource, amount, amount);
41}
42
43void ResourceLimit::Release(ResourceType resource, u64 used_amount, u64 available_amount) {
44 const std::size_t index{ResourceTypeToIndex(resource)};
45
46 current[index] -= used_amount;
47 available[index] -= available_amount;
48}
49
50std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) {
51 return std::make_shared<ResourceLimit>(kernel);
52}
53
54s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
55 return limit.at(ResourceTypeToIndex(resource)) - current.at(ResourceTypeToIndex(resource));
56}
57
58s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
59 return limit.at(ResourceTypeToIndex(resource));
60}
61
62ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
63 const std::size_t index{ResourceTypeToIndex(resource)};
64 if (current[index] <= value) {
65 limit[index] = value;
66 return RESULT_SUCCESS;
67 } else {
68 LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource,
69 value, index);
70 return ERR_INVALID_STATE;
71 }
72}
73} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
deleted file mode 100644
index 464d4f2a6..000000000
--- a/src/core/hle/kernel/resource_limit.h
+++ /dev/null
@@ -1,106 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <memory>
9
10#include "common/common_types.h"
11#include "core/hle/kernel/object.h"
12
13union ResultCode;
14
15namespace Kernel {
16
17class KernelCore;
18
19enum class ResourceType : u32 {
20 PhysicalMemory,
21 Threads,
22 Events,
23 TransferMemory,
24 Sessions,
25
26 // Used as a count, not an actual type.
27 ResourceTypeCount
28};
29
30constexpr bool IsValidResourceType(ResourceType type) {
31 return type < ResourceType::ResourceTypeCount;
32}
33
34class ResourceLimit final : public Object {
35public:
36 explicit ResourceLimit(KernelCore& kernel);
37 ~ResourceLimit() override;
38
39 /// Creates a resource limit object.
40 static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel);
41
42 std::string GetTypeName() const override {
43 return "ResourceLimit";
44 }
45 std::string GetName() const override {
46 return GetTypeName();
47 }
48
49 static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
50 HandleType GetHandleType() const override {
51 return HANDLE_TYPE;
52 }
53
54 bool Reserve(ResourceType resource, s64 amount);
55 bool Reserve(ResourceType resource, s64 amount, u64 timeout);
56 void Release(ResourceType resource, u64 amount);
57 void Release(ResourceType resource, u64 used_amount, u64 available_amount);
58
59 /**
60 * Gets the current value for the specified resource.
61 * @param resource Requested resource type
62 * @returns The current value of the resource type
63 */
64 s64 GetCurrentResourceValue(ResourceType resource) const;
65
66 /**
67 * Gets the max value for the specified resource.
68 * @param resource Requested resource type
69 * @returns The max value of the resource type
70 */
71 s64 GetMaxResourceValue(ResourceType resource) const;
72
73 /**
74 * Sets the limit value for a given resource type.
75 *
76 * @param resource The resource type to apply the limit to.
77 * @param value The limit to apply to the given resource type.
78 *
79 * @return A result code indicating if setting the limit value
80 * was successful or not.
81 *
82 * @note The supplied limit value *must* be greater than or equal to
83 * the current resource value for the given resource type,
84 * otherwise ERR_INVALID_STATE will be returned.
85 */
86 ResultCode SetLimitValue(ResourceType resource, s64 value);
87
88 void Finalize() override {}
89
90private:
91 // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
92 // functions
93 //
94 // Currently we have no way of distinguishing if a Create was called by the running application,
95 // or by a service module. Approach this once we have separated the service modules into their
96 // own processes
97
98 using ResourceArray =
99 std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
100
101 ResourceArray limit{};
102 ResourceArray current{};
103 ResourceArray available{};
104};
105
106} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 7fd514e9d..74eb90100 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -26,6 +26,7 @@
26#include "core/hle/kernel/handle_table.h" 26#include "core/hle/kernel/handle_table.h"
27#include "core/hle/kernel/k_address_arbiter.h" 27#include "core/hle/kernel/k_address_arbiter.h"
28#include "core/hle/kernel/k_condition_variable.h" 28#include "core/hle/kernel/k_condition_variable.h"
29#include "core/hle/kernel/k_resource_limit.h"
29#include "core/hle/kernel/k_scheduler.h" 30#include "core/hle/kernel/k_scheduler.h"
30#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 31#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
31#include "core/hle/kernel/k_synchronization_object.h" 32#include "core/hle/kernel/k_synchronization_object.h"
@@ -37,7 +38,6 @@
37#include "core/hle/kernel/physical_core.h" 38#include "core/hle/kernel/physical_core.h"
38#include "core/hle/kernel/process.h" 39#include "core/hle/kernel/process.h"
39#include "core/hle/kernel/readable_event.h" 40#include "core/hle/kernel/readable_event.h"
40#include "core/hle/kernel/resource_limit.h"
41#include "core/hle/kernel/shared_memory.h" 41#include "core/hle/kernel/shared_memory.h"
42#include "core/hle/kernel/svc.h" 42#include "core/hle/kernel/svc.h"
43#include "core/hle/kernel/svc_results.h" 43#include "core/hle/kernel/svc_results.h"
@@ -141,7 +141,7 @@ enum class ResourceLimitValueType {
141ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, 141ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
142 u32 resource_type, ResourceLimitValueType value_type) { 142 u32 resource_type, ResourceLimitValueType value_type) {
143 std::lock_guard lock{HLE::g_hle_lock}; 143 std::lock_guard lock{HLE::g_hle_lock};
144 const auto type = static_cast<ResourceType>(resource_type); 144 const auto type = static_cast<LimitableResource>(resource_type);
145 if (!IsValidResourceType(type)) { 145 if (!IsValidResourceType(type)) {
146 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); 146 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
147 return ERR_INVALID_ENUM_VALUE; 147 return ERR_INVALID_ENUM_VALUE;
@@ -151,7 +151,7 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
151 ASSERT(current_process != nullptr); 151 ASSERT(current_process != nullptr);
152 152
153 const auto resource_limit_object = 153 const auto resource_limit_object =
154 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); 154 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
155 if (!resource_limit_object) { 155 if (!resource_limit_object) {
156 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", 156 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
157 resource_limit); 157 resource_limit);
@@ -159,10 +159,10 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
159 } 159 }
160 160
161 if (value_type == ResourceLimitValueType::CurrentValue) { 161 if (value_type == ResourceLimitValueType::CurrentValue) {
162 return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); 162 return MakeResult(resource_limit_object->GetCurrentValue(type));
163 } 163 }
164 164
165 return MakeResult(resource_limit_object->GetMaxResourceValue(type)); 165 return MakeResult(resource_limit_object->GetLimitValue(type));
166} 166}
167} // Anonymous namespace 167} // Anonymous namespace
168 168
@@ -312,7 +312,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
312 return ERR_NOT_FOUND; 312 return ERR_NOT_FOUND;
313 } 313 }
314 314
315 ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Sessions, 1)); 315 ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1));
316 316
317 auto client_port = it->second; 317 auto client_port = it->second;
318 318
@@ -1450,7 +1450,8 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1450 Svc::ResultInvalidPriority); 1450 Svc::ResultInvalidPriority);
1451 R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); 1451 R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
1452 1452
1453 ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1)); 1453 ASSERT(process.GetResourceLimit()->Reserve(
1454 LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
1454 1455
1455 std::shared_ptr<KThread> thread; 1456 std::shared_ptr<KThread> thread;
1456 { 1457 {
@@ -1972,7 +1973,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle)
1972 LOG_DEBUG(Kernel_SVC, "called"); 1973 LOG_DEBUG(Kernel_SVC, "called");
1973 1974
1974 auto& kernel = system.Kernel(); 1975 auto& kernel = system.Kernel();
1975 auto resource_limit = ResourceLimit::Create(kernel); 1976 auto resource_limit = std::make_shared<KResourceLimit>(kernel, system);
1976 1977
1977 auto* const current_process = kernel.CurrentProcess(); 1978 auto* const current_process = kernel.CurrentProcess();
1978 ASSERT(current_process != nullptr); 1979 ASSERT(current_process != nullptr);
@@ -2019,7 +2020,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
2019 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, 2020 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
2020 resource_type, value); 2021 resource_type, value);
2021 2022
2022 const auto type = static_cast<ResourceType>(resource_type); 2023 const auto type = static_cast<LimitableResource>(resource_type);
2023 if (!IsValidResourceType(type)) { 2024 if (!IsValidResourceType(type)) {
2024 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); 2025 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
2025 return ERR_INVALID_ENUM_VALUE; 2026 return ERR_INVALID_ENUM_VALUE;
@@ -2029,7 +2030,7 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
2029 ASSERT(current_process != nullptr); 2030 ASSERT(current_process != nullptr);
2030 2031
2031 auto resource_limit_object = 2032 auto resource_limit_object =
2032 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); 2033 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
2033 if (!resource_limit_object) { 2034 if (!resource_limit_object) {
2034 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", 2035 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
2035 resource_limit); 2036 resource_limit);
@@ -2041,8 +2042,8 @@ static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resour
2041 LOG_ERROR( 2042 LOG_ERROR(
2042 Kernel_SVC, 2043 Kernel_SVC,
2043 "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", 2044 "Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
2044 resource_limit_object->GetMaxResourceValue(type), resource_type, 2045 resource_limit_object->GetLimitValue(type), resource_type,
2045 resource_limit_object->GetCurrentResourceValue(type)); 2046 resource_limit_object->GetCurrentValue(type));
2046 return set_result; 2047 return set_result;
2047 } 2048 }
2048 2049
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index d9865d56f..50b2c58e2 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -41,12 +41,18 @@ constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/
41ProfileManager::ProfileManager() { 41ProfileManager::ProfileManager() {
42 ParseUserSaveFile(); 42 ParseUserSaveFile();
43 43
44 if (user_count == 0) 44 // Create an user if none are present
45 if (user_count == 0) {
45 CreateNewUser(UUID::Generate(), "yuzu"); 46 CreateNewUser(UUID::Generate(), "yuzu");
47 }
46 48
47 auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1); 49 auto current = std::clamp<int>(Settings::values.current_user, 0, MAX_USERS - 1);
48 if (UserExistsIndex(current)) 50
51 // If user index don't exist. Load the first user and change the active user
52 if (!UserExistsIndex(current)) {
49 current = 0; 53 current = 0;
54 Settings::values.current_user = 0;
55 }
50 56
51 OpenUser(*GetUser(current)); 57 OpenUser(*GetUser(current));
52} 58}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 5efc1237e..4cee4838c 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -126,14 +126,23 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
126 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 126 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
127 } 127 }
128 128
129 // If ns_late is higher than the update rate ignore the delay
130 if (ns_late > motion_update_ns) {
131 ns_late = {};
132 }
133
129 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); 134 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
130} 135}
131 136
132void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 137void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
133 auto& core_timing = system.CoreTiming(); 138 auto& core_timing = system.CoreTiming();
134 139
135 for (const auto& controller : controllers) { 140 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(
136 controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 141 core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
142
143 // If ns_late is higher than the update rate ignore the delay
144 if (ns_late > motion_update_ns) {
145 ns_late = {};
137 } 146 }
138 147
139 core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event); 148 core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index ef5176bea..8372e170c 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -21,6 +21,93 @@ enum class RequestState : u32 {
21 Connected = 3, 21 Connected = 3,
22}; 22};
23 23
24struct IpAddressSetting {
25 bool is_automatic{};
26 Network::IPv4Address current_address{};
27 Network::IPv4Address subnet_mask{};
28 Network::IPv4Address gateway{};
29};
30static_assert(sizeof(IpAddressSetting) == 0xD, "IpAddressSetting has incorrect size.");
31
32struct DnsSetting {
33 bool is_automatic{};
34 Network::IPv4Address primary_dns{};
35 Network::IPv4Address secondary_dns{};
36};
37static_assert(sizeof(DnsSetting) == 0x9, "DnsSetting has incorrect size.");
38
39struct ProxySetting {
40 bool enabled{};
41 INSERT_PADDING_BYTES(1);
42 u16 port{};
43 std::array<char, 0x64> proxy_server{};
44 bool automatic_auth_enabled{};
45 std::array<char, 0x20> user{};
46 std::array<char, 0x20> password{};
47 INSERT_PADDING_BYTES(1);
48};
49static_assert(sizeof(ProxySetting) == 0xAA, "ProxySetting has incorrect size.");
50
51struct IpSettingData {
52 IpAddressSetting ip_address_setting{};
53 DnsSetting dns_setting{};
54 ProxySetting proxy_setting{};
55 u16 mtu{};
56};
57static_assert(sizeof(IpSettingData) == 0xC2, "IpSettingData has incorrect size.");
58
59struct SfWirelessSettingData {
60 u8 ssid_length{};
61 std::array<char, 0x20> ssid{};
62 u8 unknown_1{};
63 u8 unknown_2{};
64 u8 unknown_3{};
65 std::array<char, 0x41> passphrase{};
66};
67static_assert(sizeof(SfWirelessSettingData) == 0x65, "SfWirelessSettingData has incorrect size.");
68
69struct NifmWirelessSettingData {
70 u8 ssid_length{};
71 std::array<char, 0x21> ssid{};
72 u8 unknown_1{};
73 INSERT_PADDING_BYTES(1);
74 u32 unknown_2{};
75 u32 unknown_3{};
76 std::array<char, 0x41> passphrase{};
77 INSERT_PADDING_BYTES(3);
78};
79static_assert(sizeof(NifmWirelessSettingData) == 0x70,
80 "NifmWirelessSettingData has incorrect size.");
81
82#pragma pack(push, 1)
83struct SfNetworkProfileData {
84 IpSettingData ip_setting_data{};
85 u128 uuid{};
86 std::array<char, 0x40> network_name{};
87 u8 unknown_1{};
88 u8 unknown_2{};
89 u8 unknown_3{};
90 u8 unknown_4{};
91 SfWirelessSettingData wireless_setting_data{};
92 INSERT_PADDING_BYTES(1);
93};
94static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size.");
95
96struct NifmNetworkProfileData {
97 u128 uuid{};
98 std::array<char, 0x40> network_name{};
99 u32 unknown_1{};
100 u32 unknown_2{};
101 u8 unknown_3{};
102 u8 unknown_4{};
103 INSERT_PADDING_BYTES(2);
104 NifmWirelessSettingData wireless_setting_data{};
105 IpSettingData ip_setting_data{};
106};
107static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
108 "NifmNetworkProfileData has incorrect size.");
109#pragma pack(pop)
110
24class IScanRequest final : public ServiceFramework<IScanRequest> { 111class IScanRequest final : public ServiceFramework<IScanRequest> {
25public: 112public:
26 explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { 113 explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} {
@@ -128,7 +215,11 @@ private:
128 void GetAppletInfo(Kernel::HLERequestContext& ctx) { 215 void GetAppletInfo(Kernel::HLERequestContext& ctx) {
129 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 216 LOG_WARNING(Service_NIFM, "(STUBBED) called");
130 217
131 IPC::ResponseBuilder rb{ctx, 8}; 218 std::vector<u8> out_buffer(ctx.GetWriteBufferSize());
219
220 ctx.WriteBuffer(out_buffer);
221
222 IPC::ResponseBuilder rb{ctx, 5};
132 rb.Push(RESULT_SUCCESS); 223 rb.Push(RESULT_SUCCESS);
133 rb.Push<u32>(0); 224 rb.Push<u32>(0);
134 rb.Push<u32>(0); 225 rb.Push<u32>(0);
@@ -179,6 +270,46 @@ private:
179 rb.Push(RESULT_SUCCESS); 270 rb.Push(RESULT_SUCCESS);
180 rb.PushIpcInterface<IRequest>(system); 271 rb.PushIpcInterface<IRequest>(system);
181 } 272 }
273 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
274 LOG_WARNING(Service_NIFM, "(STUBBED) called");
275
276 const SfNetworkProfileData network_profile_data{
277 .ip_setting_data{
278 .ip_address_setting{
279 .is_automatic{true},
280 .current_address{192, 168, 1, 100},
281 .subnet_mask{255, 255, 255, 0},
282 .gateway{192, 168, 1, 1},
283 },
284 .dns_setting{
285 .is_automatic{true},
286 .primary_dns{1, 1, 1, 1},
287 .secondary_dns{1, 0, 0, 1},
288 },
289 .proxy_setting{
290 .enabled{false},
291 .port{},
292 .proxy_server{},
293 .automatic_auth_enabled{},
294 .user{},
295 .password{},
296 },
297 .mtu{1500},
298 },
299 .uuid{0xdeadbeef, 0xdeadbeef},
300 .network_name{"yuzu Network"},
301 .wireless_setting_data{
302 .ssid_length{12},
303 .ssid{"yuzu Network"},
304 .passphrase{"yuzupassword"},
305 },
306 };
307
308 ctx.WriteBuffer(network_profile_data);
309
310 IPC::ResponseBuilder rb{ctx, 2};
311 rb.Push(RESULT_SUCCESS);
312 }
182 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 313 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
183 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 314 LOG_WARNING(Service_NIFM, "(STUBBED) called");
184 315
@@ -210,6 +341,34 @@ private:
210 rb.PushIpcInterface<INetworkProfile>(system); 341 rb.PushIpcInterface<INetworkProfile>(system);
211 rb.PushRaw<u128>(uuid); 342 rb.PushRaw<u128>(uuid);
212 } 343 }
344 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
345 LOG_WARNING(Service_NIFM, "(STUBBED) called");
346
347 struct IpConfigInfo {
348 IpAddressSetting ip_address_setting;
349 DnsSetting dns_setting;
350 };
351 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
352 "IpConfigInfo has incorrect size.");
353
354 const IpConfigInfo ip_config_info{
355 .ip_address_setting{
356 .is_automatic{true},
357 .current_address{192, 168, 1, 100},
358 .subnet_mask{255, 255, 255, 0},
359 .gateway{192, 168, 1, 1},
360 },
361 .dns_setting{
362 .is_automatic{true},
363 .primary_dns{1, 1, 1, 1},
364 .secondary_dns{1, 0, 0, 1},
365 },
366 };
367
368 IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)};
369 rb.Push(RESULT_SUCCESS);
370 rb.PushRaw<IpConfigInfo>(ip_config_info);
371 }
213 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 372 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
214 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 373 LOG_WARNING(Service_NIFM, "(STUBBED) called");
215 374
@@ -248,7 +407,7 @@ IGeneralService::IGeneralService(Core::System& system_)
248 {1, &IGeneralService::GetClientId, "GetClientId"}, 407 {1, &IGeneralService::GetClientId, "GetClientId"},
249 {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, 408 {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
250 {4, &IGeneralService::CreateRequest, "CreateRequest"}, 409 {4, &IGeneralService::CreateRequest, "CreateRequest"},
251 {5, nullptr, "GetCurrentNetworkProfile"}, 410 {5, &IGeneralService::GetCurrentNetworkProfile, "GetCurrentNetworkProfile"},
252 {6, nullptr, "EnumerateNetworkInterfaces"}, 411 {6, nullptr, "EnumerateNetworkInterfaces"},
253 {7, nullptr, "EnumerateNetworkProfiles"}, 412 {7, nullptr, "EnumerateNetworkProfiles"},
254 {8, nullptr, "GetNetworkProfile"}, 413 {8, nullptr, "GetNetworkProfile"},
@@ -258,7 +417,7 @@ IGeneralService::IGeneralService(Core::System& system_)
258 {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"}, 417 {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
259 {13, nullptr, "GetCurrentAccessPointOld"}, 418 {13, nullptr, "GetCurrentAccessPointOld"},
260 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, 419 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
261 {15, nullptr, "GetCurrentIpConfigInfo"}, 420 {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"},
262 {16, nullptr, "SetWirelessCommunicationEnabled"}, 421 {16, nullptr, "SetWirelessCommunicationEnabled"},
263 {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"}, 422 {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
264 {18, nullptr, "GetInternetConnectionStatus"}, 423 {18, nullptr, "GetInternetConnectionStatus"},
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 39306509a..2ae5196e0 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -70,6 +70,9 @@ void LogSettings() {
70 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); 70 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
71 log_setting("Audio_OutputDevice", values.audio_device_id); 71 log_setting("Audio_OutputDevice", values.audio_device_id);
72 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); 72 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
73 log_setting("DataStorage_CacheDir", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir));
74 log_setting("DataStorage_ConfigDir", Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir));
75 log_setting("DataStorage_LoadDir", Common::FS::GetUserPath(Common::FS::UserPath::LoadDir));
73 log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); 76 log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
74 log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); 77 log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
75 log_setting("Debugging_ProgramArgs", values.program_args); 78 log_setting("Debugging_ProgramArgs", values.program_args);
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index d102a43af..51647a028 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -116,8 +116,8 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent)
116 scene = new QGraphicsScene; 116 scene = new QGraphicsScene;
117 ui->current_user_icon->setScene(scene); 117 ui->current_user_icon->setScene(scene);
118 118
119 SetConfiguration();
120 RetranslateUI(); 119 RetranslateUI();
120 SetConfiguration();
121} 121}
122 122
123ConfigureProfileManager::~ConfigureProfileManager() = default; 123ConfigureProfileManager::~ConfigureProfileManager() = default;