summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/core/hle/ipc_helpers.h2
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp3
-rw-r--r--src/core/hle/kernel/k_client_port.cpp2
-rw-r--r--src/core/hle/kernel/k_event.cpp2
-rw-r--r--src/core/hle/kernel/k_memory_block.h12
-rw-r--r--src/core/hle/kernel/k_page_table.cpp14
-rw-r--r--src/core/hle/kernel/k_process.cpp14
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp11
-rw-r--r--src/core/hle/kernel/k_resource_limit.h11
-rw-r--r--src/core/hle/kernel/k_session.cpp2
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp6
-rw-r--r--src/core/hle/kernel/k_thread.cpp8
-rw-r--r--src/core/hle/kernel/k_thread.h2
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp67
-rw-r--r--src/core/hle/kernel/kernel.h2
-rw-r--r--src/core/hle/kernel/service_thread.cpp26
-rw-r--r--src/core/hle/kernel/svc.cpp117
-rw-r--r--src/core/hle/kernel/svc_types.h470
-rw-r--r--src/core/hle/service/kernel_helpers.cpp2
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp4
-rw-r--r--src/yuzu/bootmanager.cpp337
-rw-r--r--src/yuzu/main.cpp46
-rw-r--r--src/yuzu/main.h7
25 files changed, 772 insertions, 398 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 0a560ebb7..8173462cb 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -151,6 +151,7 @@ void UpdateRescalingInfo() {
151 ASSERT(false); 151 ASSERT(false);
152 info.up_scale = 1; 152 info.up_scale = 1;
153 info.down_shift = 0; 153 info.down_shift = 0;
154 break;
154 } 155 }
155 info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift); 156 info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift);
156 info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale; 157 info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale;
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 3bb111748..a86bec252 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -149,7 +149,7 @@ public:
149 context->AddDomainObject(std::move(iface)); 149 context->AddDomainObject(std::move(iface));
150 } else { 150 } else {
151 kernel.CurrentProcess()->GetResourceLimit()->Reserve( 151 kernel.CurrentProcess()->GetResourceLimit()->Reserve(
152 Kernel::LimitableResource::Sessions, 1); 152 Kernel::LimitableResource::SessionCountMax, 1);
153 153
154 auto* session = Kernel::KSession::Create(kernel); 154 auto* session = Kernel::KSession::Create(kernel);
155 session->Initialize(nullptr, iface->GetServiceName()); 155 session->Initialize(nullptr, iface->GetServiceName());
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index aa2dddcc6..bda098511 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -265,7 +265,8 @@ void KPageBufferSlabHeap::Initialize(Core::System& system) {
265 const size_t slab_size = num_pages * PageSize; 265 const size_t slab_size = num_pages * PageSize;
266 266
267 // Reserve memory from the system resource limit. 267 // Reserve memory from the system resource limit.
268 ASSERT(kernel.GetSystemResourceLimit()->Reserve(LimitableResource::PhysicalMemory, slab_size)); 268 ASSERT(
269 kernel.GetSystemResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, slab_size));
269 270
270 // Allocate memory for the slab. 271 // Allocate memory for the slab.
271 constexpr auto AllocateOption = KMemoryManager::EncodeOption( 272 constexpr auto AllocateOption = KMemoryManager::EncodeOption(
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index eaa2e094c..2ec623a58 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -61,7 +61,7 @@ bool KClientPort::IsSignaled() const {
61Result KClientPort::CreateSession(KClientSession** out) { 61Result KClientPort::CreateSession(KClientSession** out) {
62 // Reserve a new session from the resource limit. 62 // Reserve a new session from the resource limit.
63 KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), 63 KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
64 LimitableResource::Sessions); 64 LimitableResource::SessionCountMax);
65 R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); 65 R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
66 66
67 // Update the session counts. 67 // Update the session counts.
diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp
index 78ca59463..27f70e5c5 100644
--- a/src/core/hle/kernel/k_event.cpp
+++ b/src/core/hle/kernel/k_event.cpp
@@ -50,7 +50,7 @@ Result KEvent::Clear() {
50void KEvent::PostDestroy(uintptr_t arg) { 50void KEvent::PostDestroy(uintptr_t arg) {
51 // Release the event count resource the owner process holds. 51 // Release the event count resource the owner process holds.
52 KProcess* owner = reinterpret_cast<KProcess*>(arg); 52 KProcess* owner = reinterpret_cast<KProcess*>(arg);
53 owner->GetResourceLimit()->Release(LimitableResource::Events, 1); 53 owner->GetResourceLimit()->Release(LimitableResource::EventCountMax, 1);
54 owner->Close(); 54 owner->Close();
55} 55}
56 56
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index 6f845d675..3b6e7baff 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -216,13 +216,15 @@ struct KMemoryInfo {
216 216
217 constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { 217 constexpr Svc::MemoryInfo GetSvcMemoryInfo() const {
218 return { 218 return {
219 .addr = m_address, 219 .base_address = m_address,
220 .size = m_size, 220 .size = m_size,
221 .state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask), 221 .state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask),
222 .attr = static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask), 222 .attribute =
223 .perm = static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask), 223 static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask),
224 .ipc_refcount = m_ipc_lock_count, 224 .permission =
225 .device_refcount = m_device_use_count, 225 static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask),
226 .ipc_count = m_ipc_lock_count,
227 .device_count = m_device_use_count,
226 .padding = {}, 228 .padding = {},
227 }; 229 };
228 } 230 }
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index fab55a057..5387bf5fe 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -920,8 +920,8 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
920 920
921 // Reserve space for any partial pages we allocate. 921 // Reserve space for any partial pages we allocate.
922 const size_t unmapped_size = aligned_src_size - mapping_src_size; 922 const size_t unmapped_size = aligned_src_size - mapping_src_size;
923 KScopedResourceReservation memory_reservation(m_resource_limit, 923 KScopedResourceReservation memory_reservation(
924 LimitableResource::PhysicalMemory, unmapped_size); 924 m_resource_limit, LimitableResource::PhysicalMemoryMax, unmapped_size);
925 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); 925 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
926 926
927 // Ensure that we manage page references correctly. 927 // Ensure that we manage page references correctly.
@@ -1227,7 +1227,7 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState
1227 const VAddr mapping_start = Common::AlignUp((address), PageSize); 1227 const VAddr mapping_start = Common::AlignUp((address), PageSize);
1228 const VAddr mapping_end = Common::AlignDown((address) + size, PageSize); 1228 const VAddr mapping_end = Common::AlignDown((address) + size, PageSize);
1229 const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0; 1229 const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0;
1230 m_resource_limit->Release(LimitableResource::PhysicalMemory, aligned_size - mapping_size); 1230 m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, aligned_size - mapping_size);
1231 1231
1232 R_SUCCEED(); 1232 R_SUCCEED();
1233} 1233}
@@ -1568,7 +1568,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
1568 { 1568 {
1569 // Reserve the memory from the process resource limit. 1569 // Reserve the memory from the process resource limit.
1570 KScopedResourceReservation memory_reservation( 1570 KScopedResourceReservation memory_reservation(
1571 m_resource_limit, LimitableResource::PhysicalMemory, size - mapped_size); 1571 m_resource_limit, LimitableResource::PhysicalMemoryMax, size - mapped_size);
1572 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); 1572 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
1573 1573
1574 // Allocate pages for the new memory. 1574 // Allocate pages for the new memory.
@@ -1908,7 +1908,7 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
1908 1908
1909 // Release the memory resource. 1909 // Release the memory resource.
1910 m_mapped_physical_memory_size -= mapped_size; 1910 m_mapped_physical_memory_size -= mapped_size;
1911 m_resource_limit->Release(LimitableResource::PhysicalMemory, mapped_size); 1911 m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, mapped_size);
1912 1912
1913 // Update memory blocks. 1913 // Update memory blocks.
1914 m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, 1914 m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize,
@@ -2492,7 +2492,7 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
2492 OperationType::Unmap)); 2492 OperationType::Unmap));
2493 2493
2494 // Release the memory from the resource limit. 2494 // Release the memory from the resource limit.
2495 m_resource_limit->Release(LimitableResource::PhysicalMemory, num_pages * PageSize); 2495 m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, num_pages * PageSize);
2496 2496
2497 // Apply the memory block update. 2497 // Apply the memory block update.
2498 m_memory_block_manager.Update(std::addressof(allocator), m_heap_region_start + size, 2498 m_memory_block_manager.Update(std::addressof(allocator), m_heap_region_start + size,
@@ -2522,7 +2522,7 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
2522 2522
2523 // Reserve memory for the heap extension. 2523 // Reserve memory for the heap extension.
2524 KScopedResourceReservation memory_reservation( 2524 KScopedResourceReservation memory_reservation(
2525 m_resource_limit, LimitableResource::PhysicalMemory, allocation_size); 2525 m_resource_limit, LimitableResource::PhysicalMemoryMax, allocation_size);
2526 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); 2526 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
2527 2527
2528 // Allocate pages for the heap extension. 2528 // Allocate pages for the heap extension.
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 4ddeea73b..55a9c5fae 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -38,7 +38,7 @@ namespace {
38 */ 38 */
39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) { 39void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
40 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); 40 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
41 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); 41 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
42 42
43 KThread* thread = KThread::Create(system.Kernel()); 43 KThread* thread = KThread::Create(system.Kernel());
44 SCOPE_EXIT({ thread->Close(); }); 44 SCOPE_EXIT({ thread->Close(); });
@@ -124,7 +124,7 @@ void KProcess::DecrementRunningThreadCount() {
124} 124}
125 125
126u64 KProcess::GetTotalPhysicalMemoryAvailable() { 126u64 KProcess::GetTotalPhysicalMemoryAvailable() {
127 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + 127 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
128 page_table.GetNormalMemorySize() + GetSystemResourceSize() + image_size + 128 page_table.GetNormalMemorySize() + GetSystemResourceSize() + image_size +
129 main_thread_stack_size}; 129 main_thread_stack_size};
130 if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); 130 if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
@@ -349,8 +349,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
349 // We currently do not support process-specific system resource 349 // We currently do not support process-specific system resource
350 UNIMPLEMENTED_IF(system_resource_size != 0); 350 UNIMPLEMENTED_IF(system_resource_size != 0);
351 351
352 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, 352 KScopedResourceReservation memory_reservation(
353 code_size + system_resource_size); 353 resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size);
354 if (!memory_reservation.Succeeded()) { 354 if (!memory_reservation.Succeeded()) {
355 LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", 355 LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
356 code_size + system_resource_size); 356 code_size + system_resource_size);
@@ -406,8 +406,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
406 406
407void KProcess::Run(s32 main_thread_priority, u64 stack_size) { 407void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
408 AllocateMainThreadStack(stack_size); 408 AllocateMainThreadStack(stack_size);
409 resource_limit->Reserve(LimitableResource::Threads, 1); 409 resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
410 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); 410 resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
411 411
412 const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)}; 412 const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
413 ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError()); 413 ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
@@ -442,7 +442,7 @@ void KProcess::PrepareForTermination() {
442 plr_address = 0; 442 plr_address = 0;
443 443
444 if (resource_limit) { 444 if (resource_limit) {
445 resource_limit->Release(LimitableResource::PhysicalMemory, 445 resource_limit->Release(LimitableResource::PhysicalMemoryMax,
446 main_thread_stack_size + image_size); 446 main_thread_stack_size + image_size);
447 } 447 }
448 448
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index 010dcf99e..b9d22b414 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -159,12 +159,13 @@ KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical
159 // TODO(bunnei): These values are the system defaults, the limits for service processes are 159 // TODO(bunnei): These values are the system defaults, the limits for service processes are
160 // lower. These should use the correct limit values. 160 // lower. These should use the correct limit values.
161 161
162 ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, physical_memory_size) 162 ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, physical_memory_size)
163 .IsSuccess()); 163 .IsSuccess());
164 ASSERT(resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); 164 ASSERT(resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800).IsSuccess());
165 ASSERT(resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess()); 165 ASSERT(resource_limit->SetLimitValue(LimitableResource::EventCountMax, 900).IsSuccess());
166 ASSERT(resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200).IsSuccess()); 166 ASSERT(
167 ASSERT(resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess()); 167 resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200).IsSuccess());
168 ASSERT(resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 1133).IsSuccess());
168 169
169 return resource_limit; 170 return resource_limit;
170} 171}
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 65c98c979..2573d1b7c 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -16,15 +16,8 @@ class CoreTiming;
16 16
17namespace Kernel { 17namespace Kernel {
18class KernelCore; 18class KernelCore;
19enum class LimitableResource : u32 { 19
20 PhysicalMemory = 0, 20using LimitableResource = Svc::LimitableResource;
21 Threads = 1,
22 Events = 2,
23 TransferMemory = 3,
24 Sessions = 4,
25
26 Count,
27};
28 21
29constexpr bool IsValidResourceType(LimitableResource type) { 22constexpr bool IsValidResourceType(LimitableResource type) {
30 return type < LimitableResource::Count; 23 return type < LimitableResource::Count;
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
index 7a6534ac3..b6f6fe9d9 100644
--- a/src/core/hle/kernel/k_session.cpp
+++ b/src/core/hle/kernel/k_session.cpp
@@ -76,7 +76,7 @@ void KSession::OnClientClosed() {
76void KSession::PostDestroy(uintptr_t arg) { 76void KSession::PostDestroy(uintptr_t arg) {
77 // Release the session count resource the owner process holds. 77 // Release the session count resource the owner process holds.
78 KProcess* owner = reinterpret_cast<KProcess*>(arg); 78 KProcess* owner = reinterpret_cast<KProcess*>(arg);
79 owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); 79 owner->GetResourceLimit()->Release(LimitableResource::SessionCountMax, 1);
80 owner->Close(); 80 owner->Close();
81} 81}
82 82
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
index a039cc591..10cd4c43d 100644
--- a/src/core/hle/kernel/k_shared_memory.cpp
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -14,7 +14,7 @@ namespace Kernel {
14KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {} 14KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
15 15
16KSharedMemory::~KSharedMemory() { 16KSharedMemory::~KSharedMemory() {
17 kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); 17 kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, size);
18} 18}
19 19
20Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_, 20Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
@@ -35,7 +35,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
35 KResourceLimit* reslimit = kernel.GetSystemResourceLimit(); 35 KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
36 36
37 // Reserve memory for ourselves. 37 // Reserve memory for ourselves.
38 KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory, 38 KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemoryMax,
39 size_); 39 size_);
40 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); 40 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
41 41
@@ -57,7 +57,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
57 57
58void KSharedMemory::Finalize() { 58void KSharedMemory::Finalize() {
59 // Release the memory reservation. 59 // Release the memory reservation.
60 resource_limit->Release(LimitableResource::PhysicalMemory, size); 60 resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
61 resource_limit->Close(); 61 resource_limit->Close();
62 62
63 // Perform inherited finalization. 63 // Perform inherited finalization.
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index cc88d08f0..21207fe99 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -263,9 +263,9 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_
263 R_SUCCEED(); 263 R_SUCCEED();
264} 264}
265 265
266Result KThread::InitializeDummyThread(KThread* thread) { 266Result KThread::InitializeDummyThread(KThread* thread, KProcess* owner) {
267 // Initialize the thread. 267 // Initialize the thread.
268 R_TRY(thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy)); 268 R_TRY(thread->Initialize({}, {}, {}, DummyThreadPriority, 3, owner, ThreadType::Dummy));
269 269
270 // Initialize emulation parameters. 270 // Initialize emulation parameters.
271 thread->stack_parameters.disable_count = 0; 271 thread->stack_parameters.disable_count = 0;
@@ -303,7 +303,7 @@ void KThread::PostDestroy(uintptr_t arg) {
303 const bool resource_limit_release_hint = (arg & 1); 303 const bool resource_limit_release_hint = (arg & 1);
304 const s64 hint_value = (resource_limit_release_hint ? 0 : 1); 304 const s64 hint_value = (resource_limit_release_hint ? 0 : 1);
305 if (owner != nullptr) { 305 if (owner != nullptr) {
306 owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value); 306 owner->GetResourceLimit()->Release(LimitableResource::ThreadCountMax, 1, hint_value);
307 owner->Close(); 307 owner->Close();
308 } 308 }
309} 309}
@@ -1054,7 +1054,7 @@ void KThread::Exit() {
1054 1054
1055 // Release the thread resource hint, running thread count from parent. 1055 // Release the thread resource hint, running thread count from parent.
1056 if (parent != nullptr) { 1056 if (parent != nullptr) {
1057 parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1); 1057 parent->GetResourceLimit()->Release(Kernel::LimitableResource::ThreadCountMax, 0, 1);
1058 resource_limit_release_hint = true; 1058 resource_limit_release_hint = true;
1059 parent->DecrementRunningThreadCount(); 1059 parent->DecrementRunningThreadCount();
1060 } 1060 }
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 30aa10c9a..f38c92bff 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -415,7 +415,7 @@ public:
415 415
416 static void PostDestroy(uintptr_t arg); 416 static void PostDestroy(uintptr_t arg);
417 417
418 [[nodiscard]] static Result InitializeDummyThread(KThread* thread); 418 [[nodiscard]] static Result InitializeDummyThread(KThread* thread, KProcess* owner);
419 419
420 [[nodiscard]] static Result InitializeMainThread(Core::System& system, KThread* thread, 420 [[nodiscard]] static Result InitializeMainThread(Core::System& system, KThread* thread,
421 s32 virt_core); 421 s32 virt_core);
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index b0320eb73..9f34c2d46 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -37,7 +37,7 @@ void KTransferMemory::Finalize() {
37 37
38void KTransferMemory::PostDestroy(uintptr_t arg) { 38void KTransferMemory::PostDestroy(uintptr_t arg) {
39 KProcess* owner = reinterpret_cast<KProcess*>(arg); 39 KProcess* owner = reinterpret_cast<KProcess*>(arg);
40 owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); 40 owner->GetResourceLimit()->Release(LimitableResource::TransferMemoryCountMax, 1);
41 owner->Close(); 41 owner->Close();
42} 42}
43 43
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index abff14079..b77723503 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -91,7 +91,7 @@ struct KernelCore::Impl {
91 pt_heap_region.GetSize()); 91 pt_heap_region.GetSize());
92 } 92 }
93 93
94 RegisterHostThread(); 94 RegisterHostThread(nullptr);
95 95
96 default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread"); 96 default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
97 } 97 }
@@ -229,18 +229,22 @@ struct KernelCore::Impl {
229 const auto kernel_size{sizes.second}; 229 const auto kernel_size{sizes.second};
230 230
231 // If setting the default system values fails, then something seriously wrong has occurred. 231 // If setting the default system values fails, then something seriously wrong has occurred.
232 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size) 232 ASSERT(
233 system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, total_size)
234 .IsSuccess());
235 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800)
233 .IsSuccess()); 236 .IsSuccess());
234 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); 237 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 900)
235 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
236 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
237 .IsSuccess()); 238 .IsSuccess());
238 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess()); 239 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200)
239 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size); 240 .IsSuccess());
241 ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 1133)
242 .IsSuccess());
243 system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, kernel_size);
240 244
241 // Reserve secure applet memory, introduced in firmware 5.0.0 245 // Reserve secure applet memory, introduced in firmware 5.0.0
242 constexpr u64 secure_applet_memory_size{4_MiB}; 246 constexpr u64 secure_applet_memory_size{4_MiB};
243 ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 247 ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax,
244 secure_applet_memory_size)); 248 secure_applet_memory_size));
245 } 249 }
246 250
@@ -373,15 +377,18 @@ struct KernelCore::Impl {
373 } 377 }
374 378
375 // Gets the dummy KThread for the caller, allocating a new one if this is the first time 379 // Gets the dummy KThread for the caller, allocating a new one if this is the first time
376 KThread* GetHostDummyThread() { 380 KThread* GetHostDummyThread(KThread* existing_thread) {
377 auto initialize = [this](KThread* thread) { 381 auto initialize = [this](KThread* thread) {
378 ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); 382 ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
379 thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); 383 thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
380 return thread; 384 return thread;
381 }; 385 };
382 386
383 thread_local auto raw_thread = KThread(system.Kernel()); 387 thread_local KThread raw_thread{system.Kernel()};
384 thread_local auto thread = initialize(&raw_thread); 388 thread_local KThread* thread = nullptr;
389 if (thread == nullptr) {
390 thread = (existing_thread == nullptr) ? initialize(&raw_thread) : existing_thread;
391 }
385 392
386 return thread; 393 return thread;
387 } 394 }
@@ -396,9 +403,9 @@ struct KernelCore::Impl {
396 } 403 }
397 404
398 /// Registers a new host thread by allocating a host thread ID for it 405 /// Registers a new host thread by allocating a host thread ID for it
399 void RegisterHostThread() { 406 void RegisterHostThread(KThread* existing_thread) {
400 [[maybe_unused]] const auto this_id = GetHostThreadId(); 407 [[maybe_unused]] const auto this_id = GetHostThreadId();
401 [[maybe_unused]] const auto dummy_thread = GetHostDummyThread(); 408 [[maybe_unused]] const auto dummy_thread = GetHostDummyThread(existing_thread);
402 } 409 }
403 410
404 [[nodiscard]] u32 GetCurrentHostThreadID() { 411 [[nodiscard]] u32 GetCurrentHostThreadID() {
@@ -429,7 +436,7 @@ struct KernelCore::Impl {
429 KThread* GetCurrentEmuThread() { 436 KThread* GetCurrentEmuThread() {
430 const auto thread_id = GetCurrentHostThreadID(); 437 const auto thread_id = GetCurrentHostThreadID();
431 if (thread_id >= Core::Hardware::NUM_CPU_CORES) { 438 if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
432 return GetHostDummyThread(); 439 return GetHostDummyThread(nullptr);
433 } 440 }
434 441
435 return current_thread; 442 return current_thread;
@@ -1120,8 +1127,12 @@ void KernelCore::RegisterCoreThread(std::size_t core_id) {
1120 impl->RegisterCoreThread(core_id); 1127 impl->RegisterCoreThread(core_id);
1121} 1128}
1122 1129
1123void KernelCore::RegisterHostThread() { 1130void KernelCore::RegisterHostThread(KThread* existing_thread) {
1124 impl->RegisterHostThread(); 1131 impl->RegisterHostThread(existing_thread);
1132
1133 if (existing_thread != nullptr) {
1134 ASSERT(GetCurrentEmuThread() == existing_thread);
1135 }
1125} 1136}
1126 1137
1127u32 KernelCore::GetCurrentHostThreadID() const { 1138u32 KernelCore::GetCurrentHostThreadID() const {
@@ -1196,16 +1207,28 @@ void KernelCore::Suspend(bool suspended) {
1196 const bool should_suspend{exception_exited || suspended}; 1207 const bool should_suspend{exception_exited || suspended};
1197 const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; 1208 const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
1198 1209
1199 for (auto* process : GetProcessList()) { 1210 std::vector<KScopedAutoObject<KThread>> process_threads;
1200 process->SetActivity(activity); 1211 {
1212 KScopedSchedulerLock sl{*this};
1213
1214 if (auto* process = CurrentProcess(); process != nullptr) {
1215 process->SetActivity(activity);
1216
1217 if (!should_suspend) {
1218 // Runnable now; no need to wait.
1219 return;
1220 }
1201 1221
1202 if (should_suspend) {
1203 // Wait for execution to stop
1204 for (auto* thread : process->GetThreadList()) { 1222 for (auto* thread : process->GetThreadList()) {
1205 thread->WaitUntilSuspended(); 1223 process_threads.emplace_back(thread);
1206 } 1224 }
1207 } 1225 }
1208 } 1226 }
1227
1228 // Wait for execution to stop.
1229 for (auto& thread : process_threads) {
1230 thread->WaitUntilSuspended();
1231 }
1209} 1232}
1210 1233
1211void KernelCore::ShutdownCores() { 1234void KernelCore::ShutdownCores() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 29617d736..2e22fe0f6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -240,7 +240,7 @@ public:
240 void RegisterCoreThread(std::size_t core_id); 240 void RegisterCoreThread(std::size_t core_id);
241 241
242 /// Register the current thread as a non CPU core thread. 242 /// Register the current thread as a non CPU core thread.
243 void RegisterHostThread(); 243 void RegisterHostThread(KThread* existing_thread = nullptr);
244 244
245 /// Gets the virtual memory manager for the kernel. 245 /// Gets the virtual memory manager for the kernel.
246 KMemoryManager& MemoryManager(); 246 KMemoryManager& MemoryManager();
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index c8fe42537..f5c2ab23f 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -36,11 +36,12 @@ public:
36private: 36private:
37 KernelCore& kernel; 37 KernelCore& kernel;
38 38
39 std::jthread m_thread; 39 std::jthread m_host_thread;
40 std::mutex m_session_mutex; 40 std::mutex m_session_mutex;
41 std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions; 41 std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions;
42 KEvent* m_wakeup_event; 42 KEvent* m_wakeup_event;
43 KProcess* m_process; 43 KProcess* m_process;
44 KThread* m_thread;
44 std::atomic<bool> m_shutdown_requested; 45 std::atomic<bool> m_shutdown_requested;
45 const std::string m_service_name; 46 const std::string m_service_name;
46}; 47};
@@ -132,7 +133,7 @@ void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
132void ServiceThread::Impl::LoopProcess() { 133void ServiceThread::Impl::LoopProcess() {
133 Common::SetCurrentThreadName(m_service_name.c_str()); 134 Common::SetCurrentThreadName(m_service_name.c_str());
134 135
135 kernel.RegisterHostThread(); 136 kernel.RegisterHostThread(m_thread);
136 137
137 while (!m_shutdown_requested.load()) { 138 while (!m_shutdown_requested.load()) {
138 WaitAndProcessImpl(); 139 WaitAndProcessImpl();
@@ -160,7 +161,7 @@ ServiceThread::Impl::~Impl() {
160 // Shut down the processing thread. 161 // Shut down the processing thread.
161 m_shutdown_requested.store(true); 162 m_shutdown_requested.store(true);
162 m_wakeup_event->Signal(); 163 m_wakeup_event->Signal();
163 m_thread.join(); 164 m_host_thread.join();
164 165
165 // Lock mutex. 166 // Lock mutex.
166 m_session_mutex.lock(); 167 m_session_mutex.lock();
@@ -177,6 +178,9 @@ ServiceThread::Impl::~Impl() {
177 m_wakeup_event->GetReadableEvent().Close(); 178 m_wakeup_event->GetReadableEvent().Close();
178 m_wakeup_event->Close(); 179 m_wakeup_event->Close();
179 180
181 // Close thread.
182 m_thread->Close();
183
180 // Close process. 184 // Close process.
181 m_process->Close(); 185 m_process->Close();
182} 186}
@@ -189,7 +193,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
189 KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit()); 193 KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
190 194
191 // Reserve a new event from the process resource limit 195 // Reserve a new event from the process resource limit
192 KScopedResourceReservation event_reservation(m_process, LimitableResource::Events); 196 KScopedResourceReservation event_reservation(m_process, LimitableResource::EventCountMax);
193 ASSERT(event_reservation.Succeeded()); 197 ASSERT(event_reservation.Succeeded());
194 198
195 // Initialize event. 199 // Initialize event.
@@ -199,11 +203,19 @@ ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
199 // Commit the event reservation. 203 // Commit the event reservation.
200 event_reservation.Commit(); 204 event_reservation.Commit();
201 205
202 // Register the event. 206 // Reserve a new thread from the process resource limit
203 KEvent::Register(kernel, m_wakeup_event); 207 KScopedResourceReservation thread_reservation(m_process, LimitableResource::ThreadCountMax);
208 ASSERT(thread_reservation.Succeeded());
209
210 // Initialize thread.
211 m_thread = KThread::Create(kernel);
212 ASSERT(KThread::InitializeDummyThread(m_thread, m_process).IsSuccess());
213
214 // Commit the thread reservation.
215 thread_reservation.Commit();
204 216
205 // Start thread. 217 // Start thread.
206 m_thread = std::jthread([this] { LoopProcess(); }); 218 m_host_thread = std::jthread([this] { LoopProcess(); });
207} 219}
208 220
209ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name) 221ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index ecac97a52..9962ad171 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -267,7 +267,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
267 267
268 // Reserve a new session from the process resource limit. 268 // Reserve a new session from the process resource limit.
269 // FIXME: LimitableResource_SessionCountMax 269 // FIXME: LimitableResource_SessionCountMax
270 KScopedResourceReservation session_reservation(&process, LimitableResource::Sessions); 270 KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax);
271 if (session_reservation.Succeeded()) { 271 if (session_reservation.Succeeded()) {
272 session = T::Create(system.Kernel()); 272 session = T::Create(system.Kernel());
273 } else { 273 } else {
@@ -298,7 +298,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
298 298
299 // We successfully allocated a session, so add the object we allocated to the resource 299 // We successfully allocated a session, so add the object we allocated to the resource
300 // limit. 300 // limit.
301 // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::Sessions, 1); 301 // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
302 } 302 }
303 303
304 // Check that we successfully created a session. 304 // Check that we successfully created a session.
@@ -656,27 +656,12 @@ static Result ArbitrateUnlock32(Core::System& system, u32 address) {
656 return ArbitrateUnlock(system, address); 656 return ArbitrateUnlock(system, address);
657} 657}
658 658
659enum class BreakType : u32 {
660 Panic = 0,
661 AssertionFailed = 1,
662 PreNROLoad = 3,
663 PostNROLoad = 4,
664 PreNROUnload = 5,
665 PostNROUnload = 6,
666 CppException = 7,
667};
668
669struct BreakReason {
670 union {
671 u32 raw;
672 BitField<0, 30, BreakType> break_type;
673 BitField<31, 1, u32> signal_debugger;
674 };
675};
676
677/// Break program execution 659/// Break program execution
678static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { 660static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
679 BreakReason break_reason{reason}; 661 BreakReason break_reason =
662 static_cast<BreakReason>(reason & ~static_cast<u32>(BreakReason::NotificationOnlyFlag));
663 bool notification_only = (reason & static_cast<u32>(BreakReason::NotificationOnlyFlag)) != 0;
664
680 bool has_dumped_buffer{}; 665 bool has_dumped_buffer{};
681 std::vector<u8> debug_buffer; 666 std::vector<u8> debug_buffer;
682 667
@@ -705,57 +690,56 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
705 } 690 }
706 has_dumped_buffer = true; 691 has_dumped_buffer = true;
707 }; 692 };
708 switch (break_reason.break_type) { 693 switch (break_reason) {
709 case BreakType::Panic: 694 case BreakReason::Panic:
710 LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}", 695 LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
711 info1, info2); 696 info2);
712 handle_debug_buffer(info1, info2); 697 handle_debug_buffer(info1, info2);
713 break; 698 break;
714 case BreakType::AssertionFailed: 699 case BreakReason::Assert:
715 LOG_CRITICAL(Debug_Emulated, 700 LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
716 "Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
717 info1, info2); 701 info1, info2);
718 handle_debug_buffer(info1, info2); 702 handle_debug_buffer(info1, info2);
719 break; 703 break;
720 case BreakType::PreNROLoad: 704 case BreakReason::User:
721 LOG_WARNING( 705 LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
722 Debug_Emulated, 706 handle_debug_buffer(info1, info2);
723 "Signalling debugger, Attempting to load an NRO at 0x{:016X} with size 0x{:016X}",
724 info1, info2);
725 break; 707 break;
726 case BreakType::PostNROLoad: 708 case BreakReason::PreLoadDll:
727 LOG_WARNING(Debug_Emulated, 709 LOG_INFO(Debug_Emulated,
728 "Signalling debugger, Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1, 710 "Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
729 info2); 711 info2);
730 break; 712 break;
731 case BreakType::PreNROUnload: 713 case BreakReason::PostLoadDll:
732 LOG_WARNING( 714 LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
733 Debug_Emulated, 715 info2);
734 "Signalling debugger, Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}",
735 info1, info2);
736 break; 716 break;
737 case BreakType::PostNROUnload: 717 case BreakReason::PreUnloadDll:
738 LOG_WARNING(Debug_Emulated, 718 LOG_INFO(Debug_Emulated,
739 "Signalling debugger, Unloaded an NRO at 0x{:016X} with size 0x{:016X}", info1, 719 "Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
740 info2); 720 info2);
741 break; 721 break;
742 case BreakType::CppException: 722 case BreakReason::PostUnloadDll:
723 LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
724 info1, info2);
725 break;
726 case BreakReason::CppException:
743 LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered."); 727 LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
744 break; 728 break;
745 default: 729 default:
746 LOG_WARNING( 730 LOG_WARNING(
747 Debug_Emulated, 731 Debug_Emulated,
748 "Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}", 732 "Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
749 static_cast<u32>(break_reason.break_type.Value()), info1, info2); 733 reason, info1, info2);
750 handle_debug_buffer(info1, info2); 734 handle_debug_buffer(info1, info2);
751 break; 735 break;
752 } 736 }
753 737
754 system.GetReporter().SaveSvcBreakReport( 738 system.GetReporter().SaveSvcBreakReport(reason, notification_only, info1, info2,
755 static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger.As<bool>(), 739 has_dumped_buffer ? std::make_optional(debug_buffer)
756 info1, info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); 740 : std::nullopt);
757 741
758 if (!break_reason.signal_debugger) { 742 if (!notification_only) {
759 LOG_CRITICAL( 743 LOG_CRITICAL(
760 Debug_Emulated, 744 Debug_Emulated,
761 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 745 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
@@ -1716,13 +1700,13 @@ static Result QueryProcessMemory(Core::System& system, VAddr memory_info_address
1716 auto& memory{system.Memory()}; 1700 auto& memory{system.Memory()};
1717 const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; 1701 const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
1718 1702
1719 memory.Write64(memory_info_address + 0x00, memory_info.addr); 1703 memory.Write64(memory_info_address + 0x00, memory_info.base_address);
1720 memory.Write64(memory_info_address + 0x08, memory_info.size); 1704 memory.Write64(memory_info_address + 0x08, memory_info.size);
1721 memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff); 1705 memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff);
1722 memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attr)); 1706 memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attribute));
1723 memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.perm)); 1707 memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.permission));
1724 memory.Write32(memory_info_address + 0x1c, memory_info.ipc_refcount); 1708 memory.Write32(memory_info_address + 0x1c, memory_info.ipc_count);
1725 memory.Write32(memory_info_address + 0x20, memory_info.device_refcount); 1709 memory.Write32(memory_info_address + 0x20, memory_info.device_count);
1726 memory.Write32(memory_info_address + 0x24, 0); 1710 memory.Write32(memory_info_address + 0x24, 0);
1727 1711
1728 // Page info appears to be currently unused by the kernel and is always set to zero. 1712 // Page info appears to be currently unused by the kernel and is always set to zero.
@@ -1943,7 +1927,7 @@ static Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry
1943 1927
1944 // Reserve a new thread from the process resource limit (waiting up to 100ms). 1928 // Reserve a new thread from the process resource limit (waiting up to 100ms).
1945 KScopedResourceReservation thread_reservation( 1929 KScopedResourceReservation thread_reservation(
1946 kernel.CurrentProcess(), LimitableResource::Threads, 1, 1930 kernel.CurrentProcess(), LimitableResource::ThreadCountMax, 1,
1947 system.CoreTiming().GetGlobalTimeNs().count() + 100000000); 1931 system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
1948 if (!thread_reservation.Succeeded()) { 1932 if (!thread_reservation.Succeeded()) {
1949 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); 1933 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
@@ -2344,7 +2328,7 @@ static Result CreateTransferMemory(Core::System& system, Handle* out, VAddr addr
2344 2328
2345 // Reserve a new transfer memory from the process resource limit. 2329 // Reserve a new transfer memory from the process resource limit.
2346 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), 2330 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
2347 LimitableResource::TransferMemory); 2331 LimitableResource::TransferMemoryCountMax);
2348 R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); 2332 R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
2349 2333
2350 // Create the transfer memory. 2334 // Create the transfer memory.
@@ -2496,7 +2480,7 @@ static Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_r
2496 2480
2497 // Reserve a new event from the process resource limit 2481 // Reserve a new event from the process resource limit
2498 KScopedResourceReservation event_reservation(kernel.CurrentProcess(), 2482 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2499 LimitableResource::Events); 2483 LimitableResource::EventCountMax);
2500 R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); 2484 R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
2501 2485
2502 // Create a new event. 2486 // Create a new event.
@@ -2539,11 +2523,6 @@ static Result CreateEvent32(Core::System& system, Handle* out_write, Handle* out
2539static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { 2523static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
2540 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); 2524 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
2541 2525
2542 // This function currently only allows retrieving a process' status.
2543 enum class InfoType {
2544 Status,
2545 };
2546
2547 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 2526 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
2548 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); 2527 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
2549 if (process.IsNull()) { 2528 if (process.IsNull()) {
@@ -2552,9 +2531,9 @@ static Result GetProcessInfo(Core::System& system, u64* out, Handle process_hand
2552 return ResultInvalidHandle; 2531 return ResultInvalidHandle;
2553 } 2532 }
2554 2533
2555 const auto info_type = static_cast<InfoType>(type); 2534 const auto info_type = static_cast<ProcessInfoType>(type);
2556 if (info_type != InfoType::Status) { 2535 if (info_type != ProcessInfoType::ProcessState) {
2557 LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type); 2536 LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", type);
2558 return ResultInvalidEnumValue; 2537 return ResultInvalidEnumValue;
2559 } 2538 }
2560 2539
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 9b0305552..33eebcef6 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -8,6 +8,8 @@
8 8
9namespace Kernel::Svc { 9namespace Kernel::Svc {
10 10
11using Handle = u32;
12
11enum class MemoryState : u32 { 13enum class MemoryState : u32 {
12 Free = 0x00, 14 Free = 0x00,
13 Io = 0x01, 15 Io = 0x01,
@@ -55,17 +57,6 @@ enum class MemoryPermission : u32 {
55}; 57};
56DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission); 58DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission);
57 59
58struct MemoryInfo {
59 u64 addr{};
60 u64 size{};
61 MemoryState state{};
62 MemoryAttribute attr{};
63 MemoryPermission perm{};
64 u32 ipc_refcount{};
65 u32 device_refcount{};
66 u32 padding{};
67};
68
69enum class SignalType : u32 { 60enum class SignalType : u32 {
70 Signal = 0, 61 Signal = 0,
71 SignalAndIncrementIfEqual = 1, 62 SignalAndIncrementIfEqual = 1,
@@ -124,7 +115,57 @@ enum class ProcessExitReason : u32 {
124 115
125constexpr inline size_t ThreadLocalRegionSize = 0x200; 116constexpr inline size_t ThreadLocalRegionSize = 0x200;
126 117
127// Debug types. 118struct PageInfo {
119 u32 flags;
120};
121
122// Info Types.
123enum class InfoType : u32 {
124 CoreMask = 0,
125 PriorityMask = 1,
126 AliasRegionAddress = 2,
127 AliasRegionSize = 3,
128 HeapRegionAddress = 4,
129 HeapRegionSize = 5,
130 TotalMemorySize = 6,
131 UsedMemorySize = 7,
132 DebuggerAttached = 8,
133 ResourceLimit = 9,
134 IdleTickCount = 10,
135 RandomEntropy = 11,
136 AslrRegionAddress = 12,
137 AslrRegionSize = 13,
138 StackRegionAddress = 14,
139 StackRegionSize = 15,
140 SystemResourceSizeTotal = 16,
141 SystemResourceSizeUsed = 17,
142 ProgramId = 18,
143 InitialProcessIdRange = 19,
144 UserExceptionContextAddress = 20,
145 TotalNonSystemMemorySize = 21,
146 UsedNonSystemMemorySize = 22,
147 IsApplication = 23,
148 FreeThreadCount = 24,
149 ThreadTickCount = 25,
150 IsSvcPermitted = 26,
151
152 MesosphereMeta = 65000,
153 MesosphereCurrentProcess = 65001,
154};
155
156enum class BreakReason : u32 {
157 Panic = 0,
158 Assert = 1,
159 User = 2,
160 PreLoadDll = 3,
161 PostLoadDll = 4,
162 PreUnloadDll = 5,
163 PostUnloadDll = 6,
164 CppException = 7,
165
166 NotificationOnlyFlag = 0x80000000,
167};
168
128enum class DebugEvent : u32 { 169enum class DebugEvent : u32 {
129 CreateProcess = 0, 170 CreateProcess = 0,
130 CreateThread = 1, 171 CreateThread = 1,
@@ -133,6 +174,14 @@ enum class DebugEvent : u32 {
133 Exception = 4, 174 Exception = 4,
134}; 175};
135 176
177enum class DebugThreadParam : u32 {
178 Priority = 0,
179 State = 1,
180 IdealCore = 2,
181 CurrentCore = 3,
182 AffinityMask = 4,
183};
184
136enum class DebugException : u32 { 185enum class DebugException : u32 {
137 UndefinedInstruction = 0, 186 UndefinedInstruction = 0,
138 InstructionAbort = 1, 187 InstructionAbort = 1,
@@ -146,4 +195,401 @@ enum class DebugException : u32 {
146 MemorySystemError = 9, 195 MemorySystemError = 9,
147}; 196};
148 197
198enum class DebugEventFlag : u32 {
199 Stopped = (1u << 0),
200};
201
202enum class BreakPointType : u32 {
203 HardwareInstruction = 0,
204 HardwareData = 1,
205};
206
207enum class HardwareBreakPointRegisterName : u32 {
208 I0 = 0,
209 I1 = 1,
210 I2 = 2,
211 I3 = 3,
212 I4 = 4,
213 I5 = 5,
214 I6 = 6,
215 I7 = 7,
216 I8 = 8,
217 I9 = 9,
218 I10 = 10,
219 I11 = 11,
220 I12 = 12,
221 I13 = 13,
222 I14 = 14,
223 I15 = 15,
224 D0 = 16,
225 D1 = 17,
226 D2 = 18,
227 D3 = 19,
228 D4 = 20,
229 D5 = 21,
230 D6 = 22,
231 D7 = 23,
232 D8 = 24,
233 D9 = 25,
234 D10 = 26,
235 D11 = 27,
236 D12 = 28,
237 D13 = 29,
238 D14 = 30,
239 D15 = 31,
240};
241
242namespace lp64 {
243struct LastThreadContext {
244 u64 fp;
245 u64 sp;
246 u64 lr;
247 u64 pc;
248};
249
250struct PhysicalMemoryInfo {
251 PAddr physical_address;
252 u64 virtual_address;
253 u64 size;
254};
255
256struct DebugInfoCreateProcess {
257 u64 program_id;
258 u64 process_id;
259 std::array<char, 0xC> name;
260 u32 flags;
261 u64 user_exception_context_address; // 5.0.0+
262};
263
264struct DebugInfoCreateThread {
265 u64 thread_id;
266 u64 tls_address;
267 // Removed in 11.0.0 u64 entrypoint;
268};
269
270struct DebugInfoExitProcess {
271 ProcessExitReason reason;
272};
273
274struct DebugInfoExitThread {
275 ThreadExitReason reason;
276};
277
278struct DebugInfoUndefinedInstructionException {
279 u32 insn;
280};
281
282struct DebugInfoDataAbortException {
283 u64 address;
284};
285
286struct DebugInfoAlignmentFaultException {
287 u64 address;
288};
289
290struct DebugInfoBreakPointException {
291 BreakPointType type;
292 u64 address;
293};
294
295struct DebugInfoUserBreakException {
296 BreakReason break_reason;
297 u64 address;
298 u64 size;
299};
300
301struct DebugInfoDebuggerBreakException {
302 std::array<u64, 4> active_thread_ids;
303};
304
305struct DebugInfoUndefinedSystemCallException {
306 u32 id;
307};
308
309union DebugInfoSpecificException {
310 DebugInfoUndefinedInstructionException undefined_instruction;
311 DebugInfoDataAbortException data_abort;
312 DebugInfoAlignmentFaultException alignment_fault;
313 DebugInfoBreakPointException break_point;
314 DebugInfoUserBreakException user_break;
315 DebugInfoDebuggerBreakException debugger_break;
316 DebugInfoUndefinedSystemCallException undefined_system_call;
317 u64 raw;
318};
319
320struct DebugInfoException {
321 DebugException type;
322 u64 address;
323 DebugInfoSpecificException specific;
324};
325
326union DebugInfo {
327 DebugInfoCreateProcess create_process;
328 DebugInfoCreateThread create_thread;
329 DebugInfoExitProcess exit_process;
330 DebugInfoExitThread exit_thread;
331 DebugInfoException exception;
332};
333
334struct DebugEventInfo {
335 DebugEvent type;
336 u32 flags;
337 u64 thread_id;
338 DebugInfo info;
339};
340static_assert(sizeof(DebugEventInfo) >= 0x40);
341
342struct SecureMonitorArguments {
343 std::array<u64, 8> r;
344};
345static_assert(sizeof(SecureMonitorArguments) == 0x40);
346} // namespace lp64
347
348namespace ilp32 {
349struct LastThreadContext {
350 u32 fp;
351 u32 sp;
352 u32 lr;
353 u32 pc;
354};
355
356struct PhysicalMemoryInfo {
357 PAddr physical_address;
358 u32 virtual_address;
359 u32 size;
360};
361
362struct DebugInfoCreateProcess {
363 u64 program_id;
364 u64 process_id;
365 std::array<char, 0xC> name;
366 u32 flags;
367 u32 user_exception_context_address; // 5.0.0+
368};
369
370struct DebugInfoCreateThread {
371 u64 thread_id;
372 u32 tls_address;
373 // Removed in 11.0.0 u32 entrypoint;
374};
375
376struct DebugInfoExitProcess {
377 ProcessExitReason reason;
378};
379
380struct DebugInfoExitThread {
381 ThreadExitReason reason;
382};
383
384struct DebugInfoUndefinedInstructionException {
385 u32 insn;
386};
387
388struct DebugInfoDataAbortException {
389 u32 address;
390};
391
392struct DebugInfoAlignmentFaultException {
393 u32 address;
394};
395
396struct DebugInfoBreakPointException {
397 BreakPointType type;
398 u32 address;
399};
400
401struct DebugInfoUserBreakException {
402 BreakReason break_reason;
403 u32 address;
404 u32 size;
405};
406
407struct DebugInfoDebuggerBreakException {
408 std::array<u64, 4> active_thread_ids;
409};
410
411struct DebugInfoUndefinedSystemCallException {
412 u32 id;
413};
414
415union DebugInfoSpecificException {
416 DebugInfoUndefinedInstructionException undefined_instruction;
417 DebugInfoDataAbortException data_abort;
418 DebugInfoAlignmentFaultException alignment_fault;
419 DebugInfoBreakPointException break_point;
420 DebugInfoUserBreakException user_break;
421 DebugInfoDebuggerBreakException debugger_break;
422 DebugInfoUndefinedSystemCallException undefined_system_call;
423 u64 raw;
424};
425
426struct DebugInfoException {
427 DebugException type;
428 u32 address;
429 DebugInfoSpecificException specific;
430};
431
432union DebugInfo {
433 DebugInfoCreateProcess create_process;
434 DebugInfoCreateThread create_thread;
435 DebugInfoExitProcess exit_process;
436 DebugInfoExitThread exit_thread;
437 DebugInfoException exception;
438};
439
440struct DebugEventInfo {
441 DebugEvent type;
442 u32 flags;
443 u64 thread_id;
444 DebugInfo info;
445};
446
447struct SecureMonitorArguments {
448 std::array<u32, 8> r;
449};
450static_assert(sizeof(SecureMonitorArguments) == 0x20);
451} // namespace ilp32
452
453struct ThreadContext {
454 std::array<u64, 29> r;
455 u64 fp;
456 u64 lr;
457 u64 sp;
458 u64 pc;
459 u32 pstate;
460 u32 padding;
461 std::array<u128, 32> v;
462 u32 fpcr;
463 u32 fpsr;
464 u64 tpidr;
465};
466static_assert(sizeof(ThreadContext) == 0x320);
467
468struct MemoryInfo {
469 u64 base_address;
470 u64 size;
471 MemoryState state;
472 MemoryAttribute attribute;
473 MemoryPermission permission;
474 u32 ipc_count;
475 u32 device_count;
476 u32 padding;
477};
478
479enum class LimitableResource : u32 {
480 PhysicalMemoryMax = 0,
481 ThreadCountMax = 1,
482 EventCountMax = 2,
483 TransferMemoryCountMax = 3,
484 SessionCountMax = 4,
485 Count,
486};
487
488enum class IoPoolType : u32 {
489 // Not supported.
490 Count = 0,
491};
492
493enum class MemoryMapping : u32 {
494 IoRegister = 0,
495 Uncached = 1,
496 Memory = 2,
497};
498
499enum class KernelDebugType : u32 {
500 Thread = 0,
501 ThreadCallStack = 1,
502 KernelObject = 2,
503 Handle_ = 3,
504 Memory = 4,
505 PageTable = 5,
506 CpuUtilization = 6,
507 Process = 7,
508 SuspendProcess = 8,
509 ResumeProcess = 9,
510 Port = 10,
511};
512
513enum class KernelTraceState : u32 {
514 Disabled = 0,
515 Enabled = 1,
516};
517
518enum class CodeMemoryOperation : u32 {
519 Map = 0,
520 MapToOwner = 1,
521 Unmap = 2,
522 UnmapFromOwner = 3,
523};
524
525enum class InterruptType : u32 {
526 Edge = 0,
527 Level = 1,
528};
529
530enum class DeviceName {
531 Afi = 0,
532 Avpc = 1,
533 Dc = 2,
534 Dcb = 3,
535 Hc = 4,
536 Hda = 5,
537 Isp2 = 6,
538 MsencNvenc = 7,
539 Nv = 8,
540 Nv2 = 9,
541 Ppcs = 10,
542 Sata = 11,
543 Vi = 12,
544 Vic = 13,
545 XusbHost = 14,
546 XusbDev = 15,
547 Tsec = 16,
548 Ppcs1 = 17,
549 Dc1 = 18,
550 Sdmmc1a = 19,
551 Sdmmc2a = 20,
552 Sdmmc3a = 21,
553 Sdmmc4a = 22,
554 Isp2b = 23,
555 Gpu = 24,
556 Gpub = 25,
557 Ppcs2 = 26,
558 Nvdec = 27,
559 Ape = 28,
560 Se = 29,
561 Nvjpg = 30,
562 Hc1 = 31,
563 Se1 = 32,
564 Axiap = 33,
565 Etr = 34,
566 Tsecb = 35,
567 Tsec1 = 36,
568 Tsecb1 = 37,
569 Nvdec1 = 38,
570 Count,
571};
572
573enum class SystemInfoType : u32 {
574 TotalPhysicalMemorySize = 0,
575 UsedPhysicalMemorySize = 1,
576 InitialProcessIdRange = 2,
577};
578
579enum class ProcessInfoType : u32 {
580 ProcessState = 0,
581};
582
583struct CreateProcessParameter {
584 std::array<char, 12> name;
585 u32 version;
586 u64 program_id;
587 u64 code_address;
588 s32 code_num_pages;
589 u32 flags;
590 Handle reslimit;
591 s32 system_resource_num_pages;
592};
593static_assert(sizeof(CreateProcessParameter) == 0x30);
594
149} // namespace Kernel::Svc 595} // namespace Kernel::Svc
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index af133af93..42991928e 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -31,7 +31,7 @@ ServiceContext::~ServiceContext() {
31Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) { 31Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
32 // Reserve a new event from the process resource limit 32 // Reserve a new event from the process resource limit
33 Kernel::KScopedResourceReservation event_reservation(process, 33 Kernel::KScopedResourceReservation event_reservation(process,
34 Kernel::LimitableResource::Events); 34 Kernel::LimitableResource::EventCountMax);
35 if (!event_reservation.Succeeded()) { 35 if (!event_reservation.Succeeded()) {
36 LOG_CRITICAL(Service, "Resource limit reached!"); 36 LOG_CRITICAL(Service, "Resource limit reached!");
37 return {}; 37 return {};
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 69e0fe808..1cf9dd1c4 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -34,8 +34,8 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
34 // once this is a proper process 34 // once this is a proper process
35 35
36 // Reserve a new session from the process resource limit. 36 // Reserve a new session from the process resource limit.
37 Kernel::KScopedResourceReservation session_reservation(&process, 37 Kernel::KScopedResourceReservation session_reservation(
38 Kernel::LimitableResource::Sessions); 38 &process, Kernel::LimitableResource::SessionCountMax);
39 ASSERT(session_reservation.Succeeded()); 39 ASSERT(session_reservation.Succeeded());
40 40
41 // Create the session. 41 // Create the session.
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 6acfb7b06..d88efacd7 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -401,224 +401,127 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
401} 401}
402 402
403int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { 403int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) {
404 switch (qt_key) { 404 static constexpr std::array<std::pair<Qt::Key, Settings::NativeKeyboard::Keys>, 106> key_map = {
405 case Qt::Key_A: 405 std::pair<Qt::Key, Settings::NativeKeyboard::Keys>{Qt::Key_A, Settings::NativeKeyboard::A},
406 return Settings::NativeKeyboard::A; 406 {Qt::Key_A, Settings::NativeKeyboard::A},
407 case Qt::Key_B: 407 {Qt::Key_B, Settings::NativeKeyboard::B},
408 return Settings::NativeKeyboard::B; 408 {Qt::Key_C, Settings::NativeKeyboard::C},
409 case Qt::Key_C: 409 {Qt::Key_D, Settings::NativeKeyboard::D},
410 return Settings::NativeKeyboard::C; 410 {Qt::Key_E, Settings::NativeKeyboard::E},
411 case Qt::Key_D: 411 {Qt::Key_F, Settings::NativeKeyboard::F},
412 return Settings::NativeKeyboard::D; 412 {Qt::Key_G, Settings::NativeKeyboard::G},
413 case Qt::Key_E: 413 {Qt::Key_H, Settings::NativeKeyboard::H},
414 return Settings::NativeKeyboard::E; 414 {Qt::Key_I, Settings::NativeKeyboard::I},
415 case Qt::Key_F: 415 {Qt::Key_J, Settings::NativeKeyboard::J},
416 return Settings::NativeKeyboard::F; 416 {Qt::Key_K, Settings::NativeKeyboard::K},
417 case Qt::Key_G: 417 {Qt::Key_L, Settings::NativeKeyboard::L},
418 return Settings::NativeKeyboard::G; 418 {Qt::Key_M, Settings::NativeKeyboard::M},
419 case Qt::Key_H: 419 {Qt::Key_N, Settings::NativeKeyboard::N},
420 return Settings::NativeKeyboard::H; 420 {Qt::Key_O, Settings::NativeKeyboard::O},
421 case Qt::Key_I: 421 {Qt::Key_P, Settings::NativeKeyboard::P},
422 return Settings::NativeKeyboard::I; 422 {Qt::Key_Q, Settings::NativeKeyboard::Q},
423 case Qt::Key_J: 423 {Qt::Key_R, Settings::NativeKeyboard::R},
424 return Settings::NativeKeyboard::J; 424 {Qt::Key_S, Settings::NativeKeyboard::S},
425 case Qt::Key_K: 425 {Qt::Key_T, Settings::NativeKeyboard::T},
426 return Settings::NativeKeyboard::K; 426 {Qt::Key_U, Settings::NativeKeyboard::U},
427 case Qt::Key_L: 427 {Qt::Key_V, Settings::NativeKeyboard::V},
428 return Settings::NativeKeyboard::L; 428 {Qt::Key_W, Settings::NativeKeyboard::W},
429 case Qt::Key_M: 429 {Qt::Key_X, Settings::NativeKeyboard::X},
430 return Settings::NativeKeyboard::M; 430 {Qt::Key_Y, Settings::NativeKeyboard::Y},
431 case Qt::Key_N: 431 {Qt::Key_Z, Settings::NativeKeyboard::Z},
432 return Settings::NativeKeyboard::N; 432 {Qt::Key_1, Settings::NativeKeyboard::N1},
433 case Qt::Key_O: 433 {Qt::Key_2, Settings::NativeKeyboard::N2},
434 return Settings::NativeKeyboard::O; 434 {Qt::Key_3, Settings::NativeKeyboard::N3},
435 case Qt::Key_P: 435 {Qt::Key_4, Settings::NativeKeyboard::N4},
436 return Settings::NativeKeyboard::P; 436 {Qt::Key_5, Settings::NativeKeyboard::N5},
437 case Qt::Key_Q: 437 {Qt::Key_6, Settings::NativeKeyboard::N6},
438 return Settings::NativeKeyboard::Q; 438 {Qt::Key_7, Settings::NativeKeyboard::N7},
439 case Qt::Key_R: 439 {Qt::Key_8, Settings::NativeKeyboard::N8},
440 return Settings::NativeKeyboard::R; 440 {Qt::Key_9, Settings::NativeKeyboard::N9},
441 case Qt::Key_S: 441 {Qt::Key_0, Settings::NativeKeyboard::N0},
442 return Settings::NativeKeyboard::S; 442 {Qt::Key_Return, Settings::NativeKeyboard::Return},
443 case Qt::Key_T: 443 {Qt::Key_Escape, Settings::NativeKeyboard::Escape},
444 return Settings::NativeKeyboard::T; 444 {Qt::Key_Backspace, Settings::NativeKeyboard::Backspace},
445 case Qt::Key_U: 445 {Qt::Key_Tab, Settings::NativeKeyboard::Tab},
446 return Settings::NativeKeyboard::U; 446 {Qt::Key_Space, Settings::NativeKeyboard::Space},
447 case Qt::Key_V: 447 {Qt::Key_Minus, Settings::NativeKeyboard::Minus},
448 return Settings::NativeKeyboard::V; 448 {Qt::Key_Plus, Settings::NativeKeyboard::Plus},
449 case Qt::Key_W: 449 {Qt::Key_questiondown, Settings::NativeKeyboard::Plus},
450 return Settings::NativeKeyboard::W; 450 {Qt::Key_BracketLeft, Settings::NativeKeyboard::OpenBracket},
451 case Qt::Key_X: 451 {Qt::Key_BraceLeft, Settings::NativeKeyboard::OpenBracket},
452 return Settings::NativeKeyboard::X; 452 {Qt::Key_BracketRight, Settings::NativeKeyboard::CloseBracket},
453 case Qt::Key_Y: 453 {Qt::Key_BraceRight, Settings::NativeKeyboard::CloseBracket},
454 return Settings::NativeKeyboard::Y; 454 {Qt::Key_Bar, Settings::NativeKeyboard::Pipe},
455 case Qt::Key_Z: 455 {Qt::Key_Dead_Tilde, Settings::NativeKeyboard::Tilde},
456 return Settings::NativeKeyboard::Z; 456 {Qt::Key_Ntilde, Settings::NativeKeyboard::Semicolon},
457 case Qt::Key_1: 457 {Qt::Key_Semicolon, Settings::NativeKeyboard::Semicolon},
458 return Settings::NativeKeyboard::N1; 458 {Qt::Key_Apostrophe, Settings::NativeKeyboard::Quote},
459 case Qt::Key_2: 459 {Qt::Key_Dead_Grave, Settings::NativeKeyboard::Backquote},
460 return Settings::NativeKeyboard::N2; 460 {Qt::Key_Comma, Settings::NativeKeyboard::Comma},
461 case Qt::Key_3: 461 {Qt::Key_Period, Settings::NativeKeyboard::Period},
462 return Settings::NativeKeyboard::N3; 462 {Qt::Key_Slash, Settings::NativeKeyboard::Slash},
463 case Qt::Key_4: 463 {Qt::Key_CapsLock, Settings::NativeKeyboard::CapsLockKey},
464 return Settings::NativeKeyboard::N4; 464 {Qt::Key_F1, Settings::NativeKeyboard::F1},
465 case Qt::Key_5: 465 {Qt::Key_F2, Settings::NativeKeyboard::F2},
466 return Settings::NativeKeyboard::N5; 466 {Qt::Key_F3, Settings::NativeKeyboard::F3},
467 case Qt::Key_6: 467 {Qt::Key_F4, Settings::NativeKeyboard::F4},
468 return Settings::NativeKeyboard::N6; 468 {Qt::Key_F5, Settings::NativeKeyboard::F5},
469 case Qt::Key_7: 469 {Qt::Key_F6, Settings::NativeKeyboard::F6},
470 return Settings::NativeKeyboard::N7; 470 {Qt::Key_F7, Settings::NativeKeyboard::F7},
471 case Qt::Key_8: 471 {Qt::Key_F8, Settings::NativeKeyboard::F8},
472 return Settings::NativeKeyboard::N8; 472 {Qt::Key_F9, Settings::NativeKeyboard::F9},
473 case Qt::Key_9: 473 {Qt::Key_F10, Settings::NativeKeyboard::F10},
474 return Settings::NativeKeyboard::N9; 474 {Qt::Key_F11, Settings::NativeKeyboard::F11},
475 case Qt::Key_0: 475 {Qt::Key_F12, Settings::NativeKeyboard::F12},
476 return Settings::NativeKeyboard::N0; 476 {Qt::Key_Print, Settings::NativeKeyboard::PrintScreen},
477 case Qt::Key_Return: 477 {Qt::Key_ScrollLock, Settings::NativeKeyboard::ScrollLockKey},
478 return Settings::NativeKeyboard::Return; 478 {Qt::Key_Pause, Settings::NativeKeyboard::Pause},
479 case Qt::Key_Escape: 479 {Qt::Key_Insert, Settings::NativeKeyboard::Insert},
480 return Settings::NativeKeyboard::Escape; 480 {Qt::Key_Home, Settings::NativeKeyboard::Home},
481 case Qt::Key_Backspace: 481 {Qt::Key_PageUp, Settings::NativeKeyboard::PageUp},
482 return Settings::NativeKeyboard::Backspace; 482 {Qt::Key_Delete, Settings::NativeKeyboard::Delete},
483 case Qt::Key_Tab: 483 {Qt::Key_End, Settings::NativeKeyboard::End},
484 return Settings::NativeKeyboard::Tab; 484 {Qt::Key_PageDown, Settings::NativeKeyboard::PageDown},
485 case Qt::Key_Space: 485 {Qt::Key_Right, Settings::NativeKeyboard::Right},
486 return Settings::NativeKeyboard::Space; 486 {Qt::Key_Left, Settings::NativeKeyboard::Left},
487 case Qt::Key_Minus: 487 {Qt::Key_Down, Settings::NativeKeyboard::Down},
488 return Settings::NativeKeyboard::Minus; 488 {Qt::Key_Up, Settings::NativeKeyboard::Up},
489 case Qt::Key_Plus: 489 {Qt::Key_NumLock, Settings::NativeKeyboard::NumLockKey},
490 case Qt::Key_questiondown: 490 // Numpad keys are missing here
491 return Settings::NativeKeyboard::Plus; 491 {Qt::Key_F13, Settings::NativeKeyboard::F13},
492 case Qt::Key_BracketLeft: 492 {Qt::Key_F14, Settings::NativeKeyboard::F14},
493 case Qt::Key_BraceLeft: 493 {Qt::Key_F15, Settings::NativeKeyboard::F15},
494 return Settings::NativeKeyboard::OpenBracket; 494 {Qt::Key_F16, Settings::NativeKeyboard::F16},
495 case Qt::Key_BracketRight: 495 {Qt::Key_F17, Settings::NativeKeyboard::F17},
496 case Qt::Key_BraceRight: 496 {Qt::Key_F18, Settings::NativeKeyboard::F18},
497 return Settings::NativeKeyboard::CloseBracket; 497 {Qt::Key_F19, Settings::NativeKeyboard::F19},
498 case Qt::Key_Bar: 498 {Qt::Key_F20, Settings::NativeKeyboard::F20},
499 return Settings::NativeKeyboard::Pipe; 499 {Qt::Key_F21, Settings::NativeKeyboard::F21},
500 case Qt::Key_Dead_Tilde: 500 {Qt::Key_F22, Settings::NativeKeyboard::F22},
501 return Settings::NativeKeyboard::Tilde; 501 {Qt::Key_F23, Settings::NativeKeyboard::F23},
502 case Qt::Key_Ntilde: 502 {Qt::Key_F24, Settings::NativeKeyboard::F24},
503 case Qt::Key_Semicolon: 503 // {Qt::..., Settings::NativeKeyboard::KPComma},
504 return Settings::NativeKeyboard::Semicolon; 504 // {Qt::..., Settings::NativeKeyboard::Ro},
505 case Qt::Key_Apostrophe: 505 {Qt::Key_Hiragana_Katakana, Settings::NativeKeyboard::KatakanaHiragana},
506 return Settings::NativeKeyboard::Quote; 506 {Qt::Key_yen, Settings::NativeKeyboard::Yen},
507 case Qt::Key_Dead_Grave: 507 {Qt::Key_Henkan, Settings::NativeKeyboard::Henkan},
508 return Settings::NativeKeyboard::Backquote; 508 {Qt::Key_Muhenkan, Settings::NativeKeyboard::Muhenkan},
509 case Qt::Key_Comma: 509 // {Qt::..., Settings::NativeKeyboard::NumPadCommaPc98},
510 return Settings::NativeKeyboard::Comma; 510 {Qt::Key_Hangul, Settings::NativeKeyboard::HangulEnglish},
511 case Qt::Key_Period: 511 {Qt::Key_Hangul_Hanja, Settings::NativeKeyboard::Hanja},
512 return Settings::NativeKeyboard::Period; 512 {Qt::Key_Katakana, Settings::NativeKeyboard::KatakanaKey},
513 case Qt::Key_Slash: 513 {Qt::Key_Hiragana, Settings::NativeKeyboard::HiraganaKey},
514 return Settings::NativeKeyboard::Slash; 514 {Qt::Key_Zenkaku_Hankaku, Settings::NativeKeyboard::ZenkakuHankaku},
515 case Qt::Key_CapsLock: 515 // Modifier keys are handled by the modifier property
516 return Settings::NativeKeyboard::CapsLock; 516 };
517 case Qt::Key_F1: 517
518 return Settings::NativeKeyboard::F1; 518 for (const auto& [qkey, nkey] : key_map) {
519 case Qt::Key_F2: 519 if (qt_key == qkey) {
520 return Settings::NativeKeyboard::F2; 520 return nkey;
521 case Qt::Key_F3: 521 }
522 return Settings::NativeKeyboard::F3;
523 case Qt::Key_F4:
524 return Settings::NativeKeyboard::F4;
525 case Qt::Key_F5:
526 return Settings::NativeKeyboard::F5;
527 case Qt::Key_F6:
528 return Settings::NativeKeyboard::F6;
529 case Qt::Key_F7:
530 return Settings::NativeKeyboard::F7;
531 case Qt::Key_F8:
532 return Settings::NativeKeyboard::F8;
533 case Qt::Key_F9:
534 return Settings::NativeKeyboard::F9;
535 case Qt::Key_F10:
536 return Settings::NativeKeyboard::F10;
537 case Qt::Key_F11:
538 return Settings::NativeKeyboard::F11;
539 case Qt::Key_F12:
540 return Settings::NativeKeyboard::F12;
541 case Qt::Key_Print:
542 return Settings::NativeKeyboard::PrintScreen;
543 case Qt::Key_ScrollLock:
544 return Settings::NativeKeyboard::ScrollLock;
545 case Qt::Key_Pause:
546 return Settings::NativeKeyboard::Pause;
547 case Qt::Key_Insert:
548 return Settings::NativeKeyboard::Insert;
549 case Qt::Key_Home:
550 return Settings::NativeKeyboard::Home;
551 case Qt::Key_PageUp:
552 return Settings::NativeKeyboard::PageUp;
553 case Qt::Key_Delete:
554 return Settings::NativeKeyboard::Delete;
555 case Qt::Key_End:
556 return Settings::NativeKeyboard::End;
557 case Qt::Key_PageDown:
558 return Settings::NativeKeyboard::PageDown;
559 case Qt::Key_Right:
560 return Settings::NativeKeyboard::Right;
561 case Qt::Key_Left:
562 return Settings::NativeKeyboard::Left;
563 case Qt::Key_Down:
564 return Settings::NativeKeyboard::Down;
565 case Qt::Key_Up:
566 return Settings::NativeKeyboard::Up;
567 case Qt::Key_NumLock:
568 return Settings::NativeKeyboard::NumLock;
569 // Numpad keys are missing here
570 case Qt::Key_F13:
571 return Settings::NativeKeyboard::F13;
572 case Qt::Key_F14:
573 return Settings::NativeKeyboard::F14;
574 case Qt::Key_F15:
575 return Settings::NativeKeyboard::F15;
576 case Qt::Key_F16:
577 return Settings::NativeKeyboard::F16;
578 case Qt::Key_F17:
579 return Settings::NativeKeyboard::F17;
580 case Qt::Key_F18:
581 return Settings::NativeKeyboard::F18;
582 case Qt::Key_F19:
583 return Settings::NativeKeyboard::F19;
584 case Qt::Key_F20:
585 return Settings::NativeKeyboard::F20;
586 case Qt::Key_F21:
587 return Settings::NativeKeyboard::F21;
588 case Qt::Key_F22:
589 return Settings::NativeKeyboard::F22;
590 case Qt::Key_F23:
591 return Settings::NativeKeyboard::F23;
592 case Qt::Key_F24:
593 return Settings::NativeKeyboard::F24;
594 // case Qt:::
595 // return Settings::NativeKeyboard::KPComma;
596 // case Qt:::
597 // return Settings::NativeKeyboard::Ro;
598 case Qt::Key_Hiragana_Katakana:
599 return Settings::NativeKeyboard::KatakanaHiragana;
600 case Qt::Key_yen:
601 return Settings::NativeKeyboard::Yen;
602 case Qt::Key_Henkan:
603 return Settings::NativeKeyboard::Henkan;
604 case Qt::Key_Muhenkan:
605 return Settings::NativeKeyboard::Muhenkan;
606 // case Qt:::
607 // return Settings::NativeKeyboard::NumPadCommaPc98;
608 case Qt::Key_Hangul:
609 return Settings::NativeKeyboard::HangulEnglish;
610 case Qt::Key_Hangul_Hanja:
611 return Settings::NativeKeyboard::Hanja;
612 case Qt::Key_Katakana:
613 return Settings::NativeKeyboard::KatakanaKey;
614 case Qt::Key_Hiragana:
615 return Settings::NativeKeyboard::HiraganaKey;
616 case Qt::Key_Zenkaku_Hankaku:
617 return Settings::NativeKeyboard::ZenkakuHankaku;
618 // Modifier keys are handled by the modifier property
619 default:
620 return Settings::NativeKeyboard::None;
621 } 522 }
523
524 return Settings::NativeKeyboard::None;
622} 525}
623 526
624int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) { 527int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 59e56633a..c27f8196d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2018,38 +2018,50 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src
2018 return true; 2018 return true;
2019} 2019}
2020 2020
2021QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
2022 switch (type) {
2023 case InstalledEntryType::Game:
2024 return tr("Error Removing Contents");
2025 case InstalledEntryType::Update:
2026 return tr("Error Removing Update");
2027 case InstalledEntryType::AddOnContent:
2028 return tr("Error Removing DLC");
2029 default:
2030 return QStringLiteral("Error Removing <Invalid Type>");
2031 }
2032}
2021void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { 2033void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) {
2022 const QString entry_type = [type] { 2034 const QString entry_question = [type] {
2023 switch (type) { 2035 switch (type) {
2024 case InstalledEntryType::Game: 2036 case InstalledEntryType::Game:
2025 return tr("Contents"); 2037 return tr("Remove Installed Game Contents?");
2026 case InstalledEntryType::Update: 2038 case InstalledEntryType::Update:
2027 return tr("Update"); 2039 return tr("Remove Installed Game Update?");
2028 case InstalledEntryType::AddOnContent: 2040 case InstalledEntryType::AddOnContent:
2029 return tr("DLC"); 2041 return tr("Remove Installed Game DLC?");
2030 default: 2042 default:
2031 return QString{}; 2043 return QStringLiteral("Remove Installed Game <Invalid Type>?");
2032 } 2044 }
2033 }(); 2045 }();
2034 2046
2035 if (QMessageBox::question( 2047 if (QMessageBox::question(this, tr("Remove Entry"), entry_question,
2036 this, tr("Remove Entry"), tr("Remove Installed Game %1?").arg(entry_type), 2048 QMessageBox::Yes | QMessageBox::No,
2037 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) { 2049 QMessageBox::No) != QMessageBox::Yes) {
2038 return; 2050 return;
2039 } 2051 }
2040 2052
2041 switch (type) { 2053 switch (type) {
2042 case InstalledEntryType::Game: 2054 case InstalledEntryType::Game:
2043 RemoveBaseContent(program_id, entry_type); 2055 RemoveBaseContent(program_id, type);
2044 [[fallthrough]]; 2056 [[fallthrough]];
2045 case InstalledEntryType::Update: 2057 case InstalledEntryType::Update:
2046 RemoveUpdateContent(program_id, entry_type); 2058 RemoveUpdateContent(program_id, type);
2047 if (type != InstalledEntryType::Game) { 2059 if (type != InstalledEntryType::Game) {
2048 break; 2060 break;
2049 } 2061 }
2050 [[fallthrough]]; 2062 [[fallthrough]];
2051 case InstalledEntryType::AddOnContent: 2063 case InstalledEntryType::AddOnContent:
2052 RemoveAddOnContent(program_id, entry_type); 2064 RemoveAddOnContent(program_id, type);
2053 break; 2065 break;
2054 } 2066 }
2055 Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / 2067 Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
@@ -2057,7 +2069,7 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
2057 game_list->PopulateAsync(UISettings::values.game_dirs); 2069 game_list->PopulateAsync(UISettings::values.game_dirs);
2058} 2070}
2059 2071
2060void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) { 2072void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) {
2061 const auto& fs_controller = system->GetFileSystemController(); 2073 const auto& fs_controller = system->GetFileSystemController();
2062 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || 2074 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
2063 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); 2075 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
@@ -2067,12 +2079,12 @@ void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
2067 tr("Successfully removed the installed base game.")); 2079 tr("Successfully removed the installed base game."));
2068 } else { 2080 } else {
2069 QMessageBox::warning( 2081 QMessageBox::warning(
2070 this, tr("Error Removing %1").arg(entry_type), 2082 this, GetGameListErrorRemoving(type),
2071 tr("The base game is not installed in the NAND and cannot be removed.")); 2083 tr("The base game is not installed in the NAND and cannot be removed."));
2072 } 2084 }
2073} 2085}
2074 2086
2075void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) { 2087void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) {
2076 const auto update_id = program_id | 0x800; 2088 const auto update_id = program_id | 0x800;
2077 const auto& fs_controller = system->GetFileSystemController(); 2089 const auto& fs_controller = system->GetFileSystemController();
2078 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || 2090 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
@@ -2082,12 +2094,12 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type)
2082 QMessageBox::information(this, tr("Successfully Removed"), 2094 QMessageBox::information(this, tr("Successfully Removed"),
2083 tr("Successfully removed the installed update.")); 2095 tr("Successfully removed the installed update."));
2084 } else { 2096 } else {
2085 QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type), 2097 QMessageBox::warning(this, GetGameListErrorRemoving(type),
2086 tr("There is no update installed for this title.")); 2098 tr("There is no update installed for this title."));
2087 } 2099 }
2088} 2100}
2089 2101
2090void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) { 2102void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) {
2091 u32 count{}; 2103 u32 count{};
2092 const auto& fs_controller = system->GetFileSystemController(); 2104 const auto& fs_controller = system->GetFileSystemController();
2093 const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( 2105 const auto dlc_entries = system->GetContentProvider().ListEntriesFilter(
@@ -2105,7 +2117,7 @@ void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type)
2105 } 2117 }
2106 2118
2107 if (count == 0) { 2119 if (count == 0) {
2108 QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type), 2120 QMessageBox::warning(this, GetGameListErrorRemoving(type),
2109 tr("There are no DLC installed for this title.")); 2121 tr("There are no DLC installed for this title."));
2110 return; 2122 return;
2111 } 2123 }
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 150ada84c..b73f550dd 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -324,9 +324,10 @@ private slots:
324 void OnMouseActivity(); 324 void OnMouseActivity();
325 325
326private: 326private:
327 void RemoveBaseContent(u64 program_id, const QString& entry_type); 327 QString GetGameListErrorRemoving(InstalledEntryType type) const;
328 void RemoveUpdateContent(u64 program_id, const QString& entry_type); 328 void RemoveBaseContent(u64 program_id, InstalledEntryType type);
329 void RemoveAddOnContent(u64 program_id, const QString& entry_type); 329 void RemoveUpdateContent(u64 program_id, InstalledEntryType type);
330 void RemoveAddOnContent(u64 program_id, InstalledEntryType type);
330 void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); 331 void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target);
331 void RemoveAllTransferableShaderCaches(u64 program_id); 332 void RemoveAllTransferableShaderCaches(u64 program_id);
332 void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); 333 void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);