summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/arm/arm_interface.h7
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp9
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h3
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp18
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h3
-rw-r--r--src/core/core.cpp14
-rw-r--r--src/core/core.h12
-rw-r--r--src/core/core_cpu.cpp19
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h4
-rw-r--r--src/core/hle/kernel/process.cpp45
-rw-r--r--src/core/hle/kernel/process.h45
-rw-r--r--src/core/hle/kernel/svc.cpp158
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/vm_manager.cpp355
-rw-r--r--src/core/hle/kernel/vm_manager.h68
-rw-r--r--src/core/hle/service/am/am.cpp84
-rw-r--r--src/core/hle/service/am/am.h9
-rw-r--r--src/core/hle/service/am/applet_ae.cpp4
-rw-r--r--src/core/hle/service/am/applet_oe.cpp2
-rw-r--r--src/core/hle/service/apm/apm.cpp13
-rw-r--r--src/core/hle/service/apm/apm.h7
-rw-r--r--src/core/hle/service/apm/controller.cpp68
-rw-r--r--src/core/hle/service/apm/controller.h70
-rw-r--r--src/core/hle/service/apm/interface.cpp82
-rw-r--r--src/core/hle/service/apm/interface.h14
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/audio/audren_u.h1
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp54
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h26
-rw-r--r--src/core/hle/service/friend/friend.cpp35
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp31
-rw-r--r--src/core/hle/service/hid/controllers/npad.h5
-rw-r--r--src/core/hle/service/hid/errors.h13
-rw-r--r--src/core/hle/service/hid/hid.cpp50
-rw-r--r--src/core/hle/service/hid/hid.h3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp32
-rw-r--r--src/core/hle/service/mii/mii.cpp16
-rw-r--r--src/core/hle/service/pm/pm.cpp124
-rw-r--r--src/core/hle/service/pm/pm.h6
-rw-r--r--src/core/hle/service/service.cpp9
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/memory.cpp2
-rw-r--r--src/core/memory.h4
-rw-r--r--src/core/reporter.cpp60
-rw-r--r--src/core/reporter.h15
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp1
52 files changed, 1321 insertions, 317 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 12f06a189..5462decee 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -210,6 +210,8 @@ add_library(core STATIC
210 hle/service/aoc/aoc_u.h 210 hle/service/aoc/aoc_u.h
211 hle/service/apm/apm.cpp 211 hle/service/apm/apm.cpp
212 hle/service/apm/apm.h 212 hle/service/apm/apm.h
213 hle/service/apm/controller.cpp
214 hle/service/apm/controller.h
213 hle/service/apm/interface.cpp 215 hle/service/apm/interface.cpp
214 hle/service/apm/interface.h 216 hle/service/apm/interface.h
215 hle/service/audio/audctl.cpp 217 hle/service/audio/audctl.cpp
@@ -295,6 +297,7 @@ add_library(core STATIC
295 hle/service/hid/irs.h 297 hle/service/hid/irs.h
296 hle/service/hid/xcd.cpp 298 hle/service/hid/xcd.cpp
297 hle/service/hid/xcd.h 299 hle/service/hid/xcd.h
300 hle/service/hid/errors.h
298 hle/service/hid/controllers/controller_base.cpp 301 hle/service/hid/controllers/controller_base.cpp
299 hle/service/hid/controllers/controller_base.h 302 hle/service/hid/controllers/controller_base.h
300 hle/service/hid/controllers/debug_pad.cpp 303 hle/service/hid/controllers/debug_pad.cpp
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index c6691a8e1..45e94e625 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -44,13 +44,6 @@ public:
44 /// Step CPU by one instruction 44 /// Step CPU by one instruction
45 virtual void Step() = 0; 45 virtual void Step() = 0;
46 46
47 /// Maps a backing memory region for the CPU
48 virtual void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
49 Kernel::VMAPermission perms) = 0;
50
51 /// Unmaps a region of memory that was previously mapped using MapBackingMemory
52 virtual void UnmapMemory(VAddr address, std::size_t size) = 0;
53
54 /// Clear all instruction cache 47 /// Clear all instruction cache
55 virtual void ClearInstructionCache() = 0; 48 virtual void ClearInstructionCache() = 0;
56 49
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 44307fa19..f1506b372 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -177,15 +177,6 @@ ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor,
177 177
178ARM_Dynarmic::~ARM_Dynarmic() = default; 178ARM_Dynarmic::~ARM_Dynarmic() = default;
179 179
180void ARM_Dynarmic::MapBackingMemory(u64 address, std::size_t size, u8* memory,
181 Kernel::VMAPermission perms) {
182 inner_unicorn.MapBackingMemory(address, size, memory, perms);
183}
184
185void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) {
186 inner_unicorn.UnmapMemory(address, size);
187}
188
189void ARM_Dynarmic::SetPC(u64 pc) { 180void ARM_Dynarmic::SetPC(u64 pc) {
190 jit->SetPC(pc); 181 jit->SetPC(pc);
191} 182}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index b701e97a3..504d46c68 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -23,9 +23,6 @@ public:
23 ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 23 ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
24 ~ARM_Dynarmic() override; 24 ~ARM_Dynarmic() override;
25 25
26 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
27 Kernel::VMAPermission perms) override;
28 void UnmapMemory(u64 address, std::size_t size) override;
29 void SetPC(u64 pc) override; 26 void SetPC(u64 pc) override;
30 u64 GetPC() const override; 27 u64 GetPC() const override;
31 u64 GetReg(int index) const override; 28 u64 GetReg(int index) const override;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 4e07fe8b5..97d5c2a8a 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -50,11 +50,14 @@ static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_
50 50
51static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value, 51static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
52 void* user_data) { 52 void* user_data) {
53 auto* const system = static_cast<System*>(user_data);
54
53 ARM_Interface::ThreadContext ctx{}; 55 ARM_Interface::ThreadContext ctx{};
54 Core::CurrentArmInterface().SaveContext(ctx); 56 system->CurrentArmInterface().SaveContext(ctx);
55 ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr, 57 ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
56 ctx.pc, ctx.cpu_registers[30]); 58 ctx.pc, ctx.cpu_registers[30]);
57 return {}; 59
60 return false;
58} 61}
59 62
60ARM_Unicorn::ARM_Unicorn(System& system) : system{system} { 63ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
@@ -65,7 +68,7 @@ ARM_Unicorn::ARM_Unicorn(System& system) : system{system} {
65 68
66 uc_hook hook{}; 69 uc_hook hook{};
67 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); 70 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1));
68 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); 71 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0, -1));
69 if (GDBStub::IsServerEnabled()) { 72 if (GDBStub::IsServerEnabled()) {
70 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); 73 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1));
71 last_bkpt_hit = false; 74 last_bkpt_hit = false;
@@ -76,15 +79,6 @@ ARM_Unicorn::~ARM_Unicorn() {
76 CHECKED(uc_close(uc)); 79 CHECKED(uc_close(uc));
77} 80}
78 81
79void ARM_Unicorn::MapBackingMemory(VAddr address, std::size_t size, u8* memory,
80 Kernel::VMAPermission perms) {
81 CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory));
82}
83
84void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) {
85 CHECKED(uc_mem_unmap(uc, address, size));
86}
87
88void ARM_Unicorn::SetPC(u64 pc) { 82void ARM_Unicorn::SetPC(u64 pc) {
89 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc)); 83 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
90} 84}
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
index 34e974b4d..fe2ffd70c 100644
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ b/src/core/arm/unicorn/arm_unicorn.h
@@ -18,9 +18,6 @@ public:
18 explicit ARM_Unicorn(System& system); 18 explicit ARM_Unicorn(System& system);
19 ~ARM_Unicorn() override; 19 ~ARM_Unicorn() override;
20 20
21 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
22 Kernel::VMAPermission perms) override;
23 void UnmapMemory(VAddr address, std::size_t size) override;
24 void SetPC(u64 pc) override; 21 void SetPC(u64 pc) override;
25 u64 GetPC() const override; 22 u64 GetPC() const override;
26 u64 GetReg(int index) const override; 23 u64 GetReg(int index) const override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d7f43f5ec..20d64f3b0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -26,6 +26,7 @@
26#include "core/hle/kernel/scheduler.h" 26#include "core/hle/kernel/scheduler.h"
27#include "core/hle/kernel/thread.h" 27#include "core/hle/kernel/thread.h"
28#include "core/hle/service/am/applets/applets.h" 28#include "core/hle/service/am/applets/applets.h"
29#include "core/hle/service/apm/controller.h"
29#include "core/hle/service/glue/manager.h" 30#include "core/hle/service/glue/manager.h"
30#include "core/hle/service/service.h" 31#include "core/hle/service/service.h"
31#include "core/hle/service/sm/sm.h" 32#include "core/hle/service/sm/sm.h"
@@ -144,7 +145,7 @@ struct System::Impl {
144 telemetry_session = std::make_unique<Core::TelemetrySession>(); 145 telemetry_session = std::make_unique<Core::TelemetrySession>();
145 service_manager = std::make_shared<Service::SM::ServiceManager>(); 146 service_manager = std::make_shared<Service::SM::ServiceManager>();
146 147
147 Service::Init(service_manager, system, *virtual_filesystem); 148 Service::Init(service_manager, system);
148 GDBStub::Init(); 149 GDBStub::Init();
149 150
150 renderer = VideoCore::CreateRenderer(emu_window, system); 151 renderer = VideoCore::CreateRenderer(emu_window, system);
@@ -308,6 +309,9 @@ struct System::Impl {
308 /// Frontend applets 309 /// Frontend applets
309 Service::AM::Applets::AppletManager applet_manager; 310 Service::AM::Applets::AppletManager applet_manager;
310 311
312 /// APM (Performance) services
313 Service::APM::Controller apm_controller{core_timing};
314
311 /// Glue services 315 /// Glue services
312 Service::Glue::ARPManager arp_manager; 316 Service::Glue::ARPManager arp_manager;
313 317
@@ -578,6 +582,14 @@ const Service::Glue::ARPManager& System::GetARPManager() const {
578 return impl->arp_manager; 582 return impl->arp_manager;
579} 583}
580 584
585Service::APM::Controller& System::GetAPMController() {
586 return impl->apm_controller;
587}
588
589const Service::APM::Controller& System::GetAPMController() const {
590 return impl->apm_controller;
591}
592
581System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 593System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
582 return impl->Init(*this, emu_window); 594 return impl->Init(*this, emu_window);
583} 595}
diff --git a/src/core/core.h b/src/core/core.h
index 53e6fdb7b..0138d93b0 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -43,6 +43,10 @@ struct AppletFrontendSet;
43class AppletManager; 43class AppletManager;
44} // namespace AM::Applets 44} // namespace AM::Applets
45 45
46namespace APM {
47class Controller;
48}
49
46namespace Glue { 50namespace Glue {
47class ARPManager; 51class ARPManager;
48} 52}
@@ -306,6 +310,10 @@ public:
306 310
307 const Service::Glue::ARPManager& GetARPManager() const; 311 const Service::Glue::ARPManager& GetARPManager() const;
308 312
313 Service::APM::Controller& GetAPMController();
314
315 const Service::APM::Controller& GetAPMController() const;
316
309private: 317private:
310 System(); 318 System();
311 319
@@ -329,10 +337,6 @@ private:
329 static System s_instance; 337 static System s_instance;
330}; 338};
331 339
332inline ARM_Interface& CurrentArmInterface() {
333 return System::GetInstance().CurrentArmInterface();
334}
335
336inline Kernel::Process* CurrentProcess() { 340inline Kernel::Process* CurrentProcess() {
337 return System::GetInstance().CurrentProcess(); 341 return System::GetInstance().CurrentProcess();
338} 342}
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 99b7d387d..21c410e34 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -53,16 +53,12 @@ bool CpuBarrier::Rendezvous() {
53Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, 53Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
54 std::size_t core_index) 54 std::size_t core_index)
55 : cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} { 55 : cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} {
56 if (Settings::values.cpu_jit_enabled) {
57#ifdef ARCHITECTURE_x86_64 56#ifdef ARCHITECTURE_x86_64
58 arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index); 57 arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
59#else 58#else
60 arm_interface = std::make_unique<ARM_Unicorn>(system); 59 arm_interface = std::make_unique<ARM_Unicorn>(system);
61 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); 60 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
62#endif 61#endif
63 } else {
64 arm_interface = std::make_unique<ARM_Unicorn>(system);
65 }
66 62
67 scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface); 63 scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface);
68} 64}
@@ -70,15 +66,12 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba
70Cpu::~Cpu() = default; 66Cpu::~Cpu() = default;
71 67
72std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { 68std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
73 if (Settings::values.cpu_jit_enabled) {
74#ifdef ARCHITECTURE_x86_64 69#ifdef ARCHITECTURE_x86_64
75 return std::make_unique<DynarmicExclusiveMonitor>(num_cores); 70 return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
76#else 71#else
77 return nullptr; // TODO(merry): Passthrough exclusive monitor 72 // TODO(merry): Passthrough exclusive monitor
73 return nullptr;
78#endif 74#endif
79 } else {
80 return nullptr; // TODO(merry): Passthrough exclusive monitor
81 }
82} 75}
83 76
84void Cpu::RunLoop(bool tight_loop) { 77void Cpu::RunLoop(bool tight_loop) {
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index eb76174c5..7310b3602 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -94,6 +94,10 @@ u64 ProgramMetadata::GetFilesystemPermissions() const {
94 return aci_file_access.permissions; 94 return aci_file_access.permissions;
95} 95}
96 96
97u32 ProgramMetadata::GetSystemResourceSize() const {
98 return npdm_header.system_resource_size;
99}
100
97const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { 101const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
98 return aci_kernel_capabilities; 102 return aci_kernel_capabilities;
99} 103}
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 43bf2820a..88ec97d85 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -58,6 +58,7 @@ public:
58 u32 GetMainThreadStackSize() const; 58 u32 GetMainThreadStackSize() const;
59 u64 GetTitleID() const; 59 u64 GetTitleID() const;
60 u64 GetFilesystemPermissions() const; 60 u64 GetFilesystemPermissions() const;
61 u32 GetSystemResourceSize() const;
61 const KernelCapabilityDescriptors& GetKernelCapabilities() const; 62 const KernelCapabilityDescriptors& GetKernelCapabilities() const;
62 63
63 void Print() const; 64 void Print() const;
@@ -76,7 +77,8 @@ private:
76 u8 reserved_3; 77 u8 reserved_3;
77 u8 main_thread_priority; 78 u8 main_thread_priority;
78 u8 main_thread_cpu; 79 u8 main_thread_cpu;
79 std::array<u8, 8> reserved_4; 80 std::array<u8, 4> reserved_4;
81 u32_le system_resource_size;
80 u32_le process_category; 82 u32_le process_category;
81 u32_le main_stack_size; 83 u32_le main_stack_size;
82 std::array<u8, 0x10> application_name; 84 std::array<u8, 0x10> application_name;
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index f45ef05f6..92169a97b 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -129,20 +129,17 @@ u64 Process::GetTotalPhysicalMemoryAvailable() const {
129 return vm_manager.GetTotalPhysicalMemoryAvailable(); 129 return vm_manager.GetTotalPhysicalMemoryAvailable();
130} 130}
131 131
132u64 Process::GetTotalPhysicalMemoryAvailableWithoutMmHeap() const { 132u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
133 // TODO: Subtract the personal heap size from this when the 133 return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
134 // personal heap is implemented.
135 return GetTotalPhysicalMemoryAvailable();
136} 134}
137 135
138u64 Process::GetTotalPhysicalMemoryUsed() const { 136u64 Process::GetTotalPhysicalMemoryUsed() const {
139 return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size; 137 return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size +
138 GetSystemResourceUsage();
140} 139}
141 140
142u64 Process::GetTotalPhysicalMemoryUsedWithoutMmHeap() const { 141u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
143 // TODO: Subtract the personal heap size from this when the 142 return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
144 // personal heap is implemented.
145 return GetTotalPhysicalMemoryUsed();
146} 143}
147 144
148void Process::RegisterThread(const Thread* thread) { 145void Process::RegisterThread(const Thread* thread) {
@@ -172,6 +169,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
172 program_id = metadata.GetTitleID(); 169 program_id = metadata.GetTitleID();
173 ideal_core = metadata.GetMainThreadCore(); 170 ideal_core = metadata.GetMainThreadCore();
174 is_64bit_process = metadata.Is64BitProgram(); 171 is_64bit_process = metadata.Is64BitProgram();
172 system_resource_size = metadata.GetSystemResourceSize();
175 173
176 vm_manager.Reset(metadata.GetAddressSpaceType()); 174 vm_manager.Reset(metadata.GetAddressSpaceType());
177 175
@@ -186,19 +184,11 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
186} 184}
187 185
188void Process::Run(s32 main_thread_priority, u64 stack_size) { 186void Process::Run(s32 main_thread_priority, u64 stack_size) {
189 // The kernel always ensures that the given stack size is page aligned. 187 AllocateMainThreadStack(stack_size);
190 main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE); 188 tls_region_address = CreateTLSRegion();
191
192 // Allocate and map the main thread stack
193 // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
194 // of the user address space.
195 const VAddr mapping_address = vm_manager.GetTLSIORegionEndAddress() - main_thread_stack_size;
196 vm_manager
197 .MapMemoryBlock(mapping_address, std::make_shared<std::vector<u8>>(main_thread_stack_size),
198 0, main_thread_stack_size, MemoryState::Stack)
199 .Unwrap();
200 189
201 vm_manager.LogLayout(); 190 vm_manager.LogLayout();
191
202 ChangeStatus(ProcessStatus::Running); 192 ChangeStatus(ProcessStatus::Running);
203 193
204 SetupMainThread(*this, kernel, main_thread_priority); 194 SetupMainThread(*this, kernel, main_thread_priority);
@@ -228,6 +218,9 @@ void Process::PrepareForTermination() {
228 stop_threads(system.Scheduler(2).GetThreadList()); 218 stop_threads(system.Scheduler(2).GetThreadList());
229 stop_threads(system.Scheduler(3).GetThreadList()); 219 stop_threads(system.Scheduler(3).GetThreadList());
230 220
221 FreeTLSRegion(tls_region_address);
222 tls_region_address = 0;
223
231 ChangeStatus(ProcessStatus::Exited); 224 ChangeStatus(ProcessStatus::Exited);
232} 225}
233 226
@@ -327,4 +320,16 @@ void Process::ChangeStatus(ProcessStatus new_status) {
327 WakeupAllWaitingThreads(); 320 WakeupAllWaitingThreads();
328} 321}
329 322
323void Process::AllocateMainThreadStack(u64 stack_size) {
324 // The kernel always ensures that the given stack size is page aligned.
325 main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE);
326
327 // Allocate and map the main thread stack
328 const VAddr mapping_address = vm_manager.GetTLSIORegionEndAddress() - main_thread_stack_size;
329 vm_manager
330 .MapMemoryBlock(mapping_address, std::make_shared<std::vector<u8>>(main_thread_stack_size),
331 0, main_thread_stack_size, MemoryState::Stack)
332 .Unwrap();
333}
334
330} // namespace Kernel 335} // namespace Kernel
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 83ea02bee..c2df451f3 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -135,6 +135,11 @@ public:
135 return mutex; 135 return mutex;
136 } 136 }
137 137
138 /// Gets the address to the process' dedicated TLS region.
139 VAddr GetTLSRegionAddress() const {
140 return tls_region_address;
141 }
142
138 /// Gets the current status of the process 143 /// Gets the current status of the process
139 ProcessStatus GetStatus() const { 144 ProcessStatus GetStatus() const {
140 return status; 145 return status;
@@ -168,8 +173,24 @@ public:
168 return capabilities.GetPriorityMask(); 173 return capabilities.GetPriorityMask();
169 } 174 }
170 175
171 u32 IsVirtualMemoryEnabled() const { 176 /// Gets the amount of secure memory to allocate for memory management.
172 return is_virtual_address_memory_enabled; 177 u32 GetSystemResourceSize() const {
178 return system_resource_size;
179 }
180
181 /// Gets the amount of secure memory currently in use for memory management.
182 u32 GetSystemResourceUsage() const {
183 // On hardware, this returns the amount of system resource memory that has
184 // been used by the kernel. This is problematic for Yuzu to emulate, because
185 // system resource memory is used for page tables -- and yuzu doesn't really
186 // have a way to calculate how much memory is required for page tables for
187 // the current process at any given time.
188 // TODO: Is this even worth implementing? Games may retrieve this value via
189 // an SDK function that gets used + available system resource size for debug
190 // or diagnostic purposes. However, it seems unlikely that a game would make
191 // decisions based on how much system memory is dedicated to its page tables.
192 // Is returning a value other than zero wise?
193 return 0;
173 } 194 }
174 195
175 /// Whether this process is an AArch64 or AArch32 process. 196 /// Whether this process is an AArch64 or AArch32 process.
@@ -196,15 +217,15 @@ public:
196 u64 GetTotalPhysicalMemoryAvailable() const; 217 u64 GetTotalPhysicalMemoryAvailable() const;
197 218
198 /// Retrieves the total physical memory available to this process in bytes, 219 /// Retrieves the total physical memory available to this process in bytes,
199 /// without the size of the personal heap added to it. 220 /// without the size of the personal system resource heap added to it.
200 u64 GetTotalPhysicalMemoryAvailableWithoutMmHeap() const; 221 u64 GetTotalPhysicalMemoryAvailableWithoutSystemResource() const;
201 222
202 /// Retrieves the total physical memory used by this process in bytes. 223 /// Retrieves the total physical memory used by this process in bytes.
203 u64 GetTotalPhysicalMemoryUsed() const; 224 u64 GetTotalPhysicalMemoryUsed() const;
204 225
205 /// Retrieves the total physical memory used by this process in bytes, 226 /// Retrieves the total physical memory used by this process in bytes,
206 /// without the size of the personal heap added to it. 227 /// without the size of the personal system resource heap added to it.
207 u64 GetTotalPhysicalMemoryUsedWithoutMmHeap() const; 228 u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
208 229
209 /// Gets the list of all threads created with this process as their owner. 230 /// Gets the list of all threads created with this process as their owner.
210 const std::list<const Thread*>& GetThreadList() const { 231 const std::list<const Thread*>& GetThreadList() const {
@@ -280,6 +301,9 @@ private:
280 /// a process signal. 301 /// a process signal.
281 void ChangeStatus(ProcessStatus new_status); 302 void ChangeStatus(ProcessStatus new_status);
282 303
304 /// Allocates the main thread stack for the process, given the stack size in bytes.
305 void AllocateMainThreadStack(u64 stack_size);
306
283 /// Memory manager for this process. 307 /// Memory manager for this process.
284 Kernel::VMManager vm_manager; 308 Kernel::VMManager vm_manager;
285 309
@@ -298,12 +322,16 @@ private:
298 /// Title ID corresponding to the process 322 /// Title ID corresponding to the process
299 u64 program_id = 0; 323 u64 program_id = 0;
300 324
325 /// Specifies additional memory to be reserved for the process's memory management by the
326 /// system. When this is non-zero, secure memory is allocated and used for page table allocation
327 /// instead of using the normal global page tables/memory block management.
328 u32 system_resource_size = 0;
329
301 /// Resource limit descriptor for this process 330 /// Resource limit descriptor for this process
302 SharedPtr<ResourceLimit> resource_limit; 331 SharedPtr<ResourceLimit> resource_limit;
303 332
304 /// The ideal CPU core for this process, threads are scheduled on this core by default. 333 /// The ideal CPU core for this process, threads are scheduled on this core by default.
305 u8 ideal_core = 0; 334 u8 ideal_core = 0;
306 u32 is_virtual_address_memory_enabled = 0;
307 335
308 /// The Thread Local Storage area is allocated as processes create threads, 336 /// The Thread Local Storage area is allocated as processes create threads,
309 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part 337 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
@@ -338,6 +366,9 @@ private:
338 /// variable related facilities. 366 /// variable related facilities.
339 Mutex mutex; 367 Mutex mutex;
340 368
369 /// Address indicating the location of the process' dedicated TLS region.
370 VAddr tls_region_address = 0;
371
341 /// Random values for svcGetInfo RandomEntropy 372 /// Random values for svcGetInfo RandomEntropy
342 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{}; 373 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
343 374
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index de6363ff2..1fd1a732a 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -98,9 +98,9 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add
98 return ERR_INVALID_ADDRESS_STATE; 98 return ERR_INVALID_ADDRESS_STATE;
99 } 99 }
100 100
101 if (!vm_manager.IsWithinNewMapRegion(dst_addr, size)) { 101 if (!vm_manager.IsWithinStackRegion(dst_addr, size)) {
102 LOG_ERROR(Kernel_SVC, 102 LOG_ERROR(Kernel_SVC,
103 "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}", 103 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
104 dst_addr, size); 104 dst_addr, size);
105 return ERR_INVALID_MEMORY_RANGE; 105 return ERR_INVALID_MEMORY_RANGE;
106 } 106 }
@@ -318,7 +318,14 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
318 return result; 318 return result;
319 } 319 }
320 320
321 return vm_manager.UnmapRange(dst_addr, size); 321 const auto unmap_res = vm_manager.UnmapRange(dst_addr, size);
322
323 // Reprotect the source mapping on success
324 if (unmap_res.IsSuccess()) {
325 ASSERT(vm_manager.ReprotectRange(src_addr, size, VMAPermission::ReadWrite).IsSuccess());
326 }
327
328 return unmap_res;
322} 329}
323 330
324/// Connect to an OS service given the port name, returns the handle to the port to out 331/// Connect to an OS service given the port name, returns the handle to the port to out
@@ -726,19 +733,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
726 // 2.0.0+ 733 // 2.0.0+
727 ASLRRegionBaseAddr = 12, 734 ASLRRegionBaseAddr = 12,
728 ASLRRegionSize = 13, 735 ASLRRegionSize = 13,
729 NewMapRegionBaseAddr = 14, 736 StackRegionBaseAddr = 14,
730 NewMapRegionSize = 15, 737 StackRegionSize = 15,
731 // 3.0.0+ 738 // 3.0.0+
732 IsVirtualAddressMemoryEnabled = 16, 739 SystemResourceSize = 16,
733 PersonalMmHeapUsage = 17, 740 SystemResourceUsage = 17,
734 TitleId = 18, 741 TitleId = 18,
735 // 4.0.0+ 742 // 4.0.0+
736 PrivilegedProcessId = 19, 743 PrivilegedProcessId = 19,
737 // 5.0.0+ 744 // 5.0.0+
738 UserExceptionContextAddr = 20, 745 UserExceptionContextAddr = 20,
739 // 6.0.0+ 746 // 6.0.0+
740 TotalPhysicalMemoryAvailableWithoutMmHeap = 21, 747 TotalPhysicalMemoryAvailableWithoutSystemResource = 21,
741 TotalPhysicalMemoryUsedWithoutMmHeap = 22, 748 TotalPhysicalMemoryUsedWithoutSystemResource = 22,
742 }; 749 };
743 750
744 const auto info_id_type = static_cast<GetInfoType>(info_id); 751 const auto info_id_type = static_cast<GetInfoType>(info_id);
@@ -752,16 +759,16 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
752 case GetInfoType::HeapRegionSize: 759 case GetInfoType::HeapRegionSize:
753 case GetInfoType::ASLRRegionBaseAddr: 760 case GetInfoType::ASLRRegionBaseAddr:
754 case GetInfoType::ASLRRegionSize: 761 case GetInfoType::ASLRRegionSize:
755 case GetInfoType::NewMapRegionBaseAddr: 762 case GetInfoType::StackRegionBaseAddr:
756 case GetInfoType::NewMapRegionSize: 763 case GetInfoType::StackRegionSize:
757 case GetInfoType::TotalPhysicalMemoryAvailable: 764 case GetInfoType::TotalPhysicalMemoryAvailable:
758 case GetInfoType::TotalPhysicalMemoryUsed: 765 case GetInfoType::TotalPhysicalMemoryUsed:
759 case GetInfoType::IsVirtualAddressMemoryEnabled: 766 case GetInfoType::SystemResourceSize:
760 case GetInfoType::PersonalMmHeapUsage: 767 case GetInfoType::SystemResourceUsage:
761 case GetInfoType::TitleId: 768 case GetInfoType::TitleId:
762 case GetInfoType::UserExceptionContextAddr: 769 case GetInfoType::UserExceptionContextAddr:
763 case GetInfoType::TotalPhysicalMemoryAvailableWithoutMmHeap: 770 case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource:
764 case GetInfoType::TotalPhysicalMemoryUsedWithoutMmHeap: { 771 case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource: {
765 if (info_sub_id != 0) { 772 if (info_sub_id != 0) {
766 return ERR_INVALID_ENUM_VALUE; 773 return ERR_INVALID_ENUM_VALUE;
767 } 774 }
@@ -806,12 +813,12 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
806 *result = process->VMManager().GetASLRRegionSize(); 813 *result = process->VMManager().GetASLRRegionSize();
807 return RESULT_SUCCESS; 814 return RESULT_SUCCESS;
808 815
809 case GetInfoType::NewMapRegionBaseAddr: 816 case GetInfoType::StackRegionBaseAddr:
810 *result = process->VMManager().GetNewMapRegionBaseAddress(); 817 *result = process->VMManager().GetStackRegionBaseAddress();
811 return RESULT_SUCCESS; 818 return RESULT_SUCCESS;
812 819
813 case GetInfoType::NewMapRegionSize: 820 case GetInfoType::StackRegionSize:
814 *result = process->VMManager().GetNewMapRegionSize(); 821 *result = process->VMManager().GetStackRegionSize();
815 return RESULT_SUCCESS; 822 return RESULT_SUCCESS;
816 823
817 case GetInfoType::TotalPhysicalMemoryAvailable: 824 case GetInfoType::TotalPhysicalMemoryAvailable:
@@ -822,8 +829,13 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
822 *result = process->GetTotalPhysicalMemoryUsed(); 829 *result = process->GetTotalPhysicalMemoryUsed();
823 return RESULT_SUCCESS; 830 return RESULT_SUCCESS;
824 831
825 case GetInfoType::IsVirtualAddressMemoryEnabled: 832 case GetInfoType::SystemResourceSize:
826 *result = process->IsVirtualMemoryEnabled(); 833 *result = process->GetSystemResourceSize();
834 return RESULT_SUCCESS;
835
836 case GetInfoType::SystemResourceUsage:
837 LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
838 *result = process->GetSystemResourceUsage();
827 return RESULT_SUCCESS; 839 return RESULT_SUCCESS;
828 840
829 case GetInfoType::TitleId: 841 case GetInfoType::TitleId:
@@ -831,17 +843,15 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
831 return RESULT_SUCCESS; 843 return RESULT_SUCCESS;
832 844
833 case GetInfoType::UserExceptionContextAddr: 845 case GetInfoType::UserExceptionContextAddr:
834 LOG_WARNING(Kernel_SVC, 846 *result = process->GetTLSRegionAddress();
835 "(STUBBED) Attempted to query user exception context address, returned 0");
836 *result = 0;
837 return RESULT_SUCCESS; 847 return RESULT_SUCCESS;
838 848
839 case GetInfoType::TotalPhysicalMemoryAvailableWithoutMmHeap: 849 case GetInfoType::TotalPhysicalMemoryAvailableWithoutSystemResource:
840 *result = process->GetTotalPhysicalMemoryAvailable(); 850 *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
841 return RESULT_SUCCESS; 851 return RESULT_SUCCESS;
842 852
843 case GetInfoType::TotalPhysicalMemoryUsedWithoutMmHeap: 853 case GetInfoType::TotalPhysicalMemoryUsedWithoutSystemResource:
844 *result = process->GetTotalPhysicalMemoryUsedWithoutMmHeap(); 854 *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
845 return RESULT_SUCCESS; 855 return RESULT_SUCCESS;
846 856
847 default: 857 default:
@@ -946,6 +956,86 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
946 } 956 }
947} 957}
948 958
959/// Maps memory at a desired address
960static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
961 LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
962
963 if (!Common::Is4KBAligned(addr)) {
964 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
965 return ERR_INVALID_ADDRESS;
966 }
967
968 if (!Common::Is4KBAligned(size)) {
969 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
970 return ERR_INVALID_SIZE;
971 }
972
973 if (size == 0) {
974 LOG_ERROR(Kernel_SVC, "Size is zero");
975 return ERR_INVALID_SIZE;
976 }
977
978 if (!(addr < addr + size)) {
979 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
980 return ERR_INVALID_MEMORY_RANGE;
981 }
982
983 Process* const current_process = system.Kernel().CurrentProcess();
984 auto& vm_manager = current_process->VMManager();
985
986 if (current_process->GetSystemResourceSize() == 0) {
987 LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
988 return ERR_INVALID_STATE;
989 }
990
991 if (!vm_manager.IsWithinMapRegion(addr, size)) {
992 LOG_ERROR(Kernel_SVC, "Range not within map region");
993 return ERR_INVALID_MEMORY_RANGE;
994 }
995
996 return vm_manager.MapPhysicalMemory(addr, size);
997}
998
999/// Unmaps memory previously mapped via MapPhysicalMemory
1000static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
1001 LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
1002
1003 if (!Common::Is4KBAligned(addr)) {
1004 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
1005 return ERR_INVALID_ADDRESS;
1006 }
1007
1008 if (!Common::Is4KBAligned(size)) {
1009 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
1010 return ERR_INVALID_SIZE;
1011 }
1012
1013 if (size == 0) {
1014 LOG_ERROR(Kernel_SVC, "Size is zero");
1015 return ERR_INVALID_SIZE;
1016 }
1017
1018 if (!(addr < addr + size)) {
1019 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
1020 return ERR_INVALID_MEMORY_RANGE;
1021 }
1022
1023 Process* const current_process = system.Kernel().CurrentProcess();
1024 auto& vm_manager = current_process->VMManager();
1025
1026 if (current_process->GetSystemResourceSize() == 0) {
1027 LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
1028 return ERR_INVALID_STATE;
1029 }
1030
1031 if (!vm_manager.IsWithinMapRegion(addr, size)) {
1032 LOG_ERROR(Kernel_SVC, "Range not within map region");
1033 return ERR_INVALID_MEMORY_RANGE;
1034 }
1035
1036 return vm_manager.UnmapPhysicalMemory(addr, size);
1037}
1038
949/// Sets the thread activity 1039/// Sets the thread activity
950static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { 1040static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
951 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); 1041 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
@@ -1647,8 +1737,8 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1647// Wait for an address (via Address Arbiter) 1737// Wait for an address (via Address Arbiter)
1648static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value, 1738static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value,
1649 s64 timeout) { 1739 s64 timeout) {
1650 LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", 1740 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address,
1651 address, type, value, timeout); 1741 type, value, timeout);
1652 1742
1653 // If the passed address is a kernel virtual address, return invalid memory state. 1743 // If the passed address is a kernel virtual address, return invalid memory state.
1654 if (Memory::IsKernelVirtualAddress(address)) { 1744 if (Memory::IsKernelVirtualAddress(address)) {
@@ -1670,8 +1760,8 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type,
1670// Signals to an address (via Address Arbiter) 1760// Signals to an address (via Address Arbiter)
1671static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, 1761static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value,
1672 s32 num_to_wake) { 1762 s32 num_to_wake) {
1673 LOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", 1763 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}",
1674 address, type, value, num_to_wake); 1764 address, type, value, num_to_wake);
1675 1765
1676 // If the passed address is a kernel virtual address, return invalid memory state. 1766 // If the passed address is a kernel virtual address, return invalid memory state.
1677 if (Memory::IsKernelVirtualAddress(address)) { 1767 if (Memory::IsKernelVirtualAddress(address)) {
@@ -2303,8 +2393,8 @@ static const FunctionDef SVC_Table[] = {
2303 {0x29, SvcWrap<GetInfo>, "GetInfo"}, 2393 {0x29, SvcWrap<GetInfo>, "GetInfo"},
2304 {0x2A, nullptr, "FlushEntireDataCache"}, 2394 {0x2A, nullptr, "FlushEntireDataCache"},
2305 {0x2B, nullptr, "FlushDataCache"}, 2395 {0x2B, nullptr, "FlushDataCache"},
2306 {0x2C, nullptr, "MapPhysicalMemory"}, 2396 {0x2C, SvcWrap<MapPhysicalMemory>, "MapPhysicalMemory"},
2307 {0x2D, nullptr, "UnmapPhysicalMemory"}, 2397 {0x2D, SvcWrap<UnmapPhysicalMemory>, "UnmapPhysicalMemory"},
2308 {0x2E, nullptr, "GetFutureThreadInfo"}, 2398 {0x2E, nullptr, "GetFutureThreadInfo"},
2309 {0x2F, nullptr, "GetLastThreadInfo"}, 2399 {0x2F, nullptr, "GetLastThreadInfo"},
2310 {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"}, 2400 {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 865473c6f..c2d8d0dc3 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -32,6 +32,11 @@ void SvcWrap(Core::System& system) {
32 FuncReturn(system, func(system, Param(system, 0)).raw); 32 FuncReturn(system, func(system, Param(system, 0)).raw);
33} 33}
34 34
35template <ResultCode func(Core::System&, u64, u64)>
36void SvcWrap(Core::System& system) {
37 FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw);
38}
39
35template <ResultCode func(Core::System&, u32)> 40template <ResultCode func(Core::System&, u32)>
36void SvcWrap(Core::System& system) { 41void SvcWrap(Core::System& system) {
37 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw); 42 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 3df5ccb7f..4f45fb03b 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -8,10 +8,11 @@
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/memory_hook.h" 10#include "common/memory_hook.h"
11#include "core/arm/arm_interface.h"
12#include "core/core.h" 11#include "core/core.h"
13#include "core/file_sys/program_metadata.h" 12#include "core/file_sys/program_metadata.h"
14#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
14#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/resource_limit.h"
15#include "core/hle/kernel/vm_manager.h" 16#include "core/hle/kernel/vm_manager.h"
16#include "core/memory.h" 17#include "core/memory.h"
17#include "core/memory_setup.h" 18#include "core/memory_setup.h"
@@ -49,10 +50,14 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
49 type != next.type) { 50 type != next.type) {
50 return false; 51 return false;
51 } 52 }
52 if (type == VMAType::AllocatedMemoryBlock && 53 if ((attribute & MemoryAttribute::DeviceMapped) == MemoryAttribute::DeviceMapped) {
53 (backing_block != next.backing_block || offset + size != next.offset)) { 54 // TODO: Can device mapped memory be merged sanely?
55 // Not merging it may cause inaccuracies versus hardware when memory layout is queried.
54 return false; 56 return false;
55 } 57 }
58 if (type == VMAType::AllocatedMemoryBlock) {
59 return true;
60 }
56 if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { 61 if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
57 return false; 62 return false;
58 } 63 }
@@ -100,7 +105,7 @@ bool VMManager::IsValidHandle(VMAHandle handle) const {
100ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, 105ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
101 std::shared_ptr<std::vector<u8>> block, 106 std::shared_ptr<std::vector<u8>> block,
102 std::size_t offset, u64 size, 107 std::size_t offset, u64 size,
103 MemoryState state) { 108 MemoryState state, VMAPermission perm) {
104 ASSERT(block != nullptr); 109 ASSERT(block != nullptr);
105 ASSERT(offset + size <= block->size()); 110 ASSERT(offset + size <= block->size());
106 111
@@ -109,17 +114,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
109 VirtualMemoryArea& final_vma = vma_handle->second; 114 VirtualMemoryArea& final_vma = vma_handle->second;
110 ASSERT(final_vma.size == size); 115 ASSERT(final_vma.size == size);
111 116
112 system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset,
113 VMAPermission::ReadWriteExecute);
114 system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset,
115 VMAPermission::ReadWriteExecute);
116 system.ArmInterface(2).MapBackingMemory(target, size, block->data() + offset,
117 VMAPermission::ReadWriteExecute);
118 system.ArmInterface(3).MapBackingMemory(target, size, block->data() + offset,
119 VMAPermission::ReadWriteExecute);
120
121 final_vma.type = VMAType::AllocatedMemoryBlock; 117 final_vma.type = VMAType::AllocatedMemoryBlock;
122 final_vma.permissions = VMAPermission::ReadWrite; 118 final_vma.permissions = perm;
123 final_vma.state = state; 119 final_vma.state = state;
124 final_vma.backing_block = std::move(block); 120 final_vma.backing_block = std::move(block);
125 final_vma.offset = offset; 121 final_vma.offset = offset;
@@ -137,11 +133,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
137 VirtualMemoryArea& final_vma = vma_handle->second; 133 VirtualMemoryArea& final_vma = vma_handle->second;
138 ASSERT(final_vma.size == size); 134 ASSERT(final_vma.size == size);
139 135
140 system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
141 system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
142 system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
143 system.ArmInterface(3).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
144
145 final_vma.type = VMAType::BackingMemory; 136 final_vma.type = VMAType::BackingMemory;
146 final_vma.permissions = VMAPermission::ReadWrite; 137 final_vma.permissions = VMAPermission::ReadWrite;
147 final_vma.state = state; 138 final_vma.state = state;
@@ -230,11 +221,6 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
230 221
231 ASSERT(FindVMA(target)->second.size >= size); 222 ASSERT(FindVMA(target)->second.size >= size);
232 223
233 system.ArmInterface(0).UnmapMemory(target, size);
234 system.ArmInterface(1).UnmapMemory(target, size);
235 system.ArmInterface(2).UnmapMemory(target, size);
236 system.ArmInterface(3).UnmapMemory(target, size);
237
238 return RESULT_SUCCESS; 224 return RESULT_SUCCESS;
239} 225}
240 226
@@ -308,6 +294,166 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
308 return MakeResult<VAddr>(heap_region_base); 294 return MakeResult<VAddr>(heap_region_base);
309} 295}
310 296
297ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
298 const auto end_addr = target + size;
299 const auto last_addr = end_addr - 1;
300 VAddr cur_addr = target;
301
302 ResultCode result = RESULT_SUCCESS;
303
304 // Check how much memory we've already mapped.
305 const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size);
306 if (mapped_size_result.Failed()) {
307 return mapped_size_result.Code();
308 }
309
310 // If we've already mapped the desired amount, return early.
311 const std::size_t mapped_size = *mapped_size_result;
312 if (mapped_size == size) {
313 return RESULT_SUCCESS;
314 }
315
316 // Check that we can map the memory we want.
317 const auto res_limit = system.CurrentProcess()->GetResourceLimit();
318 const u64 physmem_remaining = res_limit->GetMaxResourceValue(ResourceType::PhysicalMemory) -
319 res_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory);
320 if (physmem_remaining < (size - mapped_size)) {
321 return ERR_RESOURCE_LIMIT_EXCEEDED;
322 }
323
324 // Keep track of the memory regions we unmap.
325 std::vector<std::pair<u64, u64>> mapped_regions;
326
327 // Iterate, trying to map memory.
328 {
329 cur_addr = target;
330
331 auto iter = FindVMA(target);
332 ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end");
333
334 while (true) {
335 const auto& vma = iter->second;
336 const auto vma_start = vma.base;
337 const auto vma_end = vma_start + vma.size;
338 const auto vma_last = vma_end - 1;
339
340 // Map the memory block
341 const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr);
342 if (vma.state == MemoryState::Unmapped) {
343 const auto map_res =
344 MapMemoryBlock(cur_addr, std::make_shared<std::vector<u8>>(map_size, 0), 0,
345 map_size, MemoryState::Heap, VMAPermission::ReadWrite);
346 result = map_res.Code();
347 if (result.IsError()) {
348 break;
349 }
350
351 mapped_regions.emplace_back(cur_addr, map_size);
352 }
353
354 // Break once we hit the end of the range.
355 if (last_addr <= vma_last) {
356 break;
357 }
358
359 // Advance to the next block.
360 cur_addr = vma_end;
361 iter = FindVMA(cur_addr);
362 ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end");
363 }
364 }
365
366 // If we failed, unmap memory.
367 if (result.IsError()) {
368 for (const auto [unmap_address, unmap_size] : mapped_regions) {
369 ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(),
370 "MapPhysicalMemory un-map on error");
371 }
372
373 return result;
374 }
375
376 // Update amount of mapped physical memory.
377 physical_memory_mapped += size - mapped_size;
378
379 return RESULT_SUCCESS;
380}
381
382ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
383 const auto end_addr = target + size;
384 const auto last_addr = end_addr - 1;
385 VAddr cur_addr = target;
386
387 ResultCode result = RESULT_SUCCESS;
388
389 // Check how much memory is currently mapped.
390 const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size);
391 if (mapped_size_result.Failed()) {
392 return mapped_size_result.Code();
393 }
394
395 // If we've already unmapped all the memory, return early.
396 const std::size_t mapped_size = *mapped_size_result;
397 if (mapped_size == 0) {
398 return RESULT_SUCCESS;
399 }
400
401 // Keep track of the memory regions we unmap.
402 std::vector<std::pair<u64, u64>> unmapped_regions;
403
404 // Try to unmap regions.
405 {
406 cur_addr = target;
407
408 auto iter = FindVMA(target);
409 ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end");
410
411 while (true) {
412 const auto& vma = iter->second;
413 const auto vma_start = vma.base;
414 const auto vma_end = vma_start + vma.size;
415 const auto vma_last = vma_end - 1;
416
417 // Unmap the memory block
418 const auto unmap_size = std::min(end_addr - cur_addr, vma_end - cur_addr);
419 if (vma.state == MemoryState::Heap) {
420 result = UnmapRange(cur_addr, unmap_size);
421 if (result.IsError()) {
422 break;
423 }
424
425 unmapped_regions.emplace_back(cur_addr, unmap_size);
426 }
427
428 // Break once we hit the end of the range.
429 if (last_addr <= vma_last) {
430 break;
431 }
432
433 // Advance to the next block.
434 cur_addr = vma_end;
435 iter = FindVMA(cur_addr);
436 ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end");
437 }
438 }
439
440 // If we failed, re-map regions.
441 // TODO: Preserve memory contents?
442 if (result.IsError()) {
443 for (const auto [map_address, map_size] : unmapped_regions) {
444 const auto remap_res =
445 MapMemoryBlock(map_address, std::make_shared<std::vector<u8>>(map_size, 0), 0,
446 map_size, MemoryState::Heap, VMAPermission::None);
447 ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error");
448 }
449 }
450
451 // Update mapped amount
452 physical_memory_mapped -= mapped_size;
453
454 return RESULT_SUCCESS;
455}
456
311ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { 457ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) {
312 constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; 458 constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped;
313 const auto src_check_result = CheckRangeState( 459 const auto src_check_result = CheckRangeState(
@@ -455,7 +601,7 @@ ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, Mem
455 // Protect mirror with permissions from old region 601 // Protect mirror with permissions from old region
456 Reprotect(new_vma, vma->second.permissions); 602 Reprotect(new_vma, vma->second.permissions);
457 // Remove permissions from old region 603 // Remove permissions from old region
458 Reprotect(vma, VMAPermission::None); 604 ReprotectRange(src_addr, size, VMAPermission::None);
459 605
460 return RESULT_SUCCESS; 606 return RESULT_SUCCESS;
461} 607}
@@ -588,14 +734,14 @@ VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) {
588VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { 734VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
589 const VMAIter next_vma = std::next(iter); 735 const VMAIter next_vma = std::next(iter);
590 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { 736 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
591 iter->second.size += next_vma->second.size; 737 MergeAdjacentVMA(iter->second, next_vma->second);
592 vma_map.erase(next_vma); 738 vma_map.erase(next_vma);
593 } 739 }
594 740
595 if (iter != vma_map.begin()) { 741 if (iter != vma_map.begin()) {
596 VMAIter prev_vma = std::prev(iter); 742 VMAIter prev_vma = std::prev(iter);
597 if (prev_vma->second.CanBeMergedWith(iter->second)) { 743 if (prev_vma->second.CanBeMergedWith(iter->second)) {
598 prev_vma->second.size += iter->second.size; 744 MergeAdjacentVMA(prev_vma->second, iter->second);
599 vma_map.erase(iter); 745 vma_map.erase(iter);
600 iter = prev_vma; 746 iter = prev_vma;
601 } 747 }
@@ -604,6 +750,38 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
604 return iter; 750 return iter;
605} 751}
606 752
753void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryArea& right) {
754 ASSERT(left.CanBeMergedWith(right));
755
756 // Always merge allocated memory blocks, even when they don't share the same backing block.
757 if (left.type == VMAType::AllocatedMemoryBlock &&
758 (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) {
759 // Check if we can save work.
760 if (left.offset == 0 && left.size == left.backing_block->size()) {
761 // Fast case: left is an entire backing block.
762 left.backing_block->insert(left.backing_block->end(),
763 right.backing_block->begin() + right.offset,
764 right.backing_block->begin() + right.offset + right.size);
765 } else {
766 // Slow case: make a new memory block for left and right.
767 auto new_memory = std::make_shared<std::vector<u8>>();
768 new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset,
769 left.backing_block->begin() + left.offset + left.size);
770 new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset,
771 right.backing_block->begin() + right.offset + right.size);
772 left.backing_block = new_memory;
773 left.offset = 0;
774 }
775
776 // Page table update is needed, because backing memory changed.
777 left.size += right.size;
778 UpdatePageTableForVMA(left);
779 } else {
780 // Just update the size.
781 left.size += right.size;
782 }
783}
784
607void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { 785void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
608 switch (vma.type) { 786 switch (vma.type) {
609 case VMAType::Free: 787 case VMAType::Free:
@@ -625,9 +803,11 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
625void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) { 803void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {
626 u64 map_region_size = 0; 804 u64 map_region_size = 0;
627 u64 heap_region_size = 0; 805 u64 heap_region_size = 0;
628 u64 new_map_region_size = 0; 806 u64 stack_region_size = 0;
629 u64 tls_io_region_size = 0; 807 u64 tls_io_region_size = 0;
630 808
809 u64 stack_and_tls_io_end = 0;
810
631 switch (type) { 811 switch (type) {
632 case FileSys::ProgramAddressSpaceType::Is32Bit: 812 case FileSys::ProgramAddressSpaceType::Is32Bit:
633 case FileSys::ProgramAddressSpaceType::Is32BitNoMap: 813 case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
@@ -643,6 +823,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
643 map_region_size = 0; 823 map_region_size = 0;
644 heap_region_size = 0x80000000; 824 heap_region_size = 0x80000000;
645 } 825 }
826 stack_and_tls_io_end = 0x40000000;
646 break; 827 break;
647 case FileSys::ProgramAddressSpaceType::Is36Bit: 828 case FileSys::ProgramAddressSpaceType::Is36Bit:
648 address_space_width = 36; 829 address_space_width = 36;
@@ -652,6 +833,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
652 aslr_region_end = aslr_region_base + 0xFF8000000; 833 aslr_region_end = aslr_region_base + 0xFF8000000;
653 map_region_size = 0x180000000; 834 map_region_size = 0x180000000;
654 heap_region_size = 0x180000000; 835 heap_region_size = 0x180000000;
836 stack_and_tls_io_end = 0x80000000;
655 break; 837 break;
656 case FileSys::ProgramAddressSpaceType::Is39Bit: 838 case FileSys::ProgramAddressSpaceType::Is39Bit:
657 address_space_width = 39; 839 address_space_width = 39;
@@ -661,7 +843,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
661 aslr_region_end = aslr_region_base + 0x7FF8000000; 843 aslr_region_end = aslr_region_base + 0x7FF8000000;
662 map_region_size = 0x1000000000; 844 map_region_size = 0x1000000000;
663 heap_region_size = 0x180000000; 845 heap_region_size = 0x180000000;
664 new_map_region_size = 0x80000000; 846 stack_region_size = 0x80000000;
665 tls_io_region_size = 0x1000000000; 847 tls_io_region_size = 0x1000000000;
666 break; 848 break;
667 default: 849 default:
@@ -669,6 +851,8 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
669 return; 851 return;
670 } 852 }
671 853
854 const u64 stack_and_tls_io_begin = aslr_region_base;
855
672 address_space_base = 0; 856 address_space_base = 0;
673 address_space_end = 1ULL << address_space_width; 857 address_space_end = 1ULL << address_space_width;
674 858
@@ -679,15 +863,20 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
679 heap_region_end = heap_region_base + heap_region_size; 863 heap_region_end = heap_region_base + heap_region_size;
680 heap_end = heap_region_base; 864 heap_end = heap_region_base;
681 865
682 new_map_region_base = heap_region_end; 866 stack_region_base = heap_region_end;
683 new_map_region_end = new_map_region_base + new_map_region_size; 867 stack_region_end = stack_region_base + stack_region_size;
684 868
685 tls_io_region_base = new_map_region_end; 869 tls_io_region_base = stack_region_end;
686 tls_io_region_end = tls_io_region_base + tls_io_region_size; 870 tls_io_region_end = tls_io_region_base + tls_io_region_size;
687 871
688 if (new_map_region_size == 0) { 872 if (stack_region_size == 0) {
689 new_map_region_base = address_space_base; 873 stack_region_base = stack_and_tls_io_begin;
690 new_map_region_end = address_space_end; 874 stack_region_end = stack_and_tls_io_end;
875 }
876
877 if (tls_io_region_size == 0) {
878 tls_io_region_base = stack_and_tls_io_begin;
879 tls_io_region_end = stack_and_tls_io_end;
691 } 880 }
692} 881}
693 882
@@ -767,6 +956,84 @@ VMManager::CheckResults VMManager::CheckRangeState(VAddr address, u64 size, Memo
767 std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask)); 956 std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask));
768} 957}
769 958
959ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address,
960 std::size_t size) const {
961 const VAddr end_addr = address + size;
962 const VAddr last_addr = end_addr - 1;
963 std::size_t mapped_size = 0;
964
965 VAddr cur_addr = address;
966 auto iter = FindVMA(cur_addr);
967 ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end");
968
969 while (true) {
970 const auto& vma = iter->second;
971 const VAddr vma_start = vma.base;
972 const VAddr vma_end = vma_start + vma.size;
973 const VAddr vma_last = vma_end - 1;
974
975 // Add size if relevant.
976 if (vma.state != MemoryState::Unmapped) {
977 mapped_size += std::min(end_addr - cur_addr, vma_end - cur_addr);
978 }
979
980 // Break once we hit the end of the range.
981 if (last_addr <= vma_last) {
982 break;
983 }
984
985 // Advance to the next block.
986 cur_addr = vma_end;
987 iter = std::next(iter);
988 ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end");
989 }
990
991 return MakeResult(mapped_size);
992}
993
994ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr address,
995 std::size_t size) const {
996 const VAddr end_addr = address + size;
997 const VAddr last_addr = end_addr - 1;
998 std::size_t mapped_size = 0;
999
1000 VAddr cur_addr = address;
1001 auto iter = FindVMA(cur_addr);
1002 ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end");
1003
1004 while (true) {
1005 const auto& vma = iter->second;
1006 const auto vma_start = vma.base;
1007 const auto vma_end = vma_start + vma.size;
1008 const auto vma_last = vma_end - 1;
1009 const auto state = vma.state;
1010 const auto attr = vma.attribute;
1011
1012 // Memory within region must be free or mapped heap.
1013 if (!((state == MemoryState::Heap && attr == MemoryAttribute::None) ||
1014 (state == MemoryState::Unmapped))) {
1015 return ERR_INVALID_ADDRESS_STATE;
1016 }
1017
1018 // Add size if relevant.
1019 if (state != MemoryState::Unmapped) {
1020 mapped_size += std::min(end_addr - cur_addr, vma_end - cur_addr);
1021 }
1022
1023 // Break once we hit the end of the range.
1024 if (last_addr <= vma_last) {
1025 break;
1026 }
1027
1028 // Advance to the next block.
1029 cur_addr = vma_end;
1030 iter = std::next(iter);
1031 ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end");
1032 }
1033
1034 return MakeResult(mapped_size);
1035}
1036
770u64 VMManager::GetTotalPhysicalMemoryAvailable() const { 1037u64 VMManager::GetTotalPhysicalMemoryAvailable() const {
771 LOG_WARNING(Kernel, "(STUBBED) called"); 1038 LOG_WARNING(Kernel, "(STUBBED) called");
772 return 0xF8000000; 1039 return 0xF8000000;
@@ -879,21 +1146,21 @@ bool VMManager::IsWithinMapRegion(VAddr address, u64 size) const {
879 return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress()); 1146 return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress());
880} 1147}
881 1148
882VAddr VMManager::GetNewMapRegionBaseAddress() const { 1149VAddr VMManager::GetStackRegionBaseAddress() const {
883 return new_map_region_base; 1150 return stack_region_base;
884} 1151}
885 1152
886VAddr VMManager::GetNewMapRegionEndAddress() const { 1153VAddr VMManager::GetStackRegionEndAddress() const {
887 return new_map_region_end; 1154 return stack_region_end;
888} 1155}
889 1156
890u64 VMManager::GetNewMapRegionSize() const { 1157u64 VMManager::GetStackRegionSize() const {
891 return new_map_region_end - new_map_region_base; 1158 return stack_region_end - stack_region_base;
892} 1159}
893 1160
894bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const { 1161bool VMManager::IsWithinStackRegion(VAddr address, u64 size) const {
895 return IsInsideAddressRange(address, size, GetNewMapRegionBaseAddress(), 1162 return IsInsideAddressRange(address, size, GetStackRegionBaseAddress(),
896 GetNewMapRegionEndAddress()); 1163 GetStackRegionEndAddress());
897} 1164}
898 1165
899VAddr VMManager::GetTLSIORegionBaseAddress() const { 1166VAddr VMManager::GetTLSIORegionBaseAddress() const {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 752ae62f9..0aecb7499 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -349,7 +349,8 @@ public:
349 * @param state MemoryState tag to attach to the VMA. 349 * @param state MemoryState tag to attach to the VMA.
350 */ 350 */
351 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, 351 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
352 std::size_t offset, u64 size, MemoryState state); 352 std::size_t offset, u64 size, MemoryState state,
353 VMAPermission perm = VMAPermission::ReadWrite);
353 354
354 /** 355 /**
355 * Maps an unmanaged host memory pointer at a given address. 356 * Maps an unmanaged host memory pointer at a given address.
@@ -450,6 +451,34 @@ public:
450 /// 451 ///
451 ResultVal<VAddr> SetHeapSize(u64 size); 452 ResultVal<VAddr> SetHeapSize(u64 size);
452 453
454 /// Maps memory at a given address.
455 ///
456 /// @param addr The virtual address to map memory at.
457 /// @param size The amount of memory to map.
458 ///
459 /// @note The destination address must lie within the Map region.
460 ///
461 /// @note This function requires that SystemResourceSize be non-zero,
462 /// however, this is just because if it were not then the
463 /// resulting page tables could be exploited on hardware by
464 /// a malicious program. SystemResource usage does not need
465 /// to be explicitly checked or updated here.
466 ResultCode MapPhysicalMemory(VAddr target, u64 size);
467
468 /// Unmaps memory at a given address.
469 ///
470 /// @param addr The virtual address to unmap memory at.
471 /// @param size The amount of memory to unmap.
472 ///
473 /// @note The destination address must lie within the Map region.
474 ///
475 /// @note This function requires that SystemResourceSize be non-zero,
476 /// however, this is just because if it were not then the
477 /// resulting page tables could be exploited on hardware by
478 /// a malicious program. SystemResource usage does not need
479 /// to be explicitly checked or updated here.
480 ResultCode UnmapPhysicalMemory(VAddr target, u64 size);
481
453 /// Maps a region of memory as code memory. 482 /// Maps a region of memory as code memory.
454 /// 483 ///
455 /// @param dst_address The base address of the region to create the aliasing memory region. 484 /// @param dst_address The base address of the region to create the aliasing memory region.
@@ -596,17 +625,17 @@ public:
596 /// Determines whether or not the specified range is within the map region. 625 /// Determines whether or not the specified range is within the map region.
597 bool IsWithinMapRegion(VAddr address, u64 size) const; 626 bool IsWithinMapRegion(VAddr address, u64 size) const;
598 627
599 /// Gets the base address of the new map region. 628 /// Gets the base address of the stack region.
600 VAddr GetNewMapRegionBaseAddress() const; 629 VAddr GetStackRegionBaseAddress() const;
601 630
602 /// Gets the end address of the new map region. 631 /// Gets the end address of the stack region.
603 VAddr GetNewMapRegionEndAddress() const; 632 VAddr GetStackRegionEndAddress() const;
604 633
605 /// Gets the total size of the new map region in bytes. 634 /// Gets the total size of the stack region in bytes.
606 u64 GetNewMapRegionSize() const; 635 u64 GetStackRegionSize() const;
607 636
608 /// Determines whether or not the given address range is within the new map region 637 /// Determines whether or not the given address range is within the stack region
609 bool IsWithinNewMapRegion(VAddr address, u64 size) const; 638 bool IsWithinStackRegion(VAddr address, u64 size) const;
610 639
611 /// Gets the base address of the TLS IO region. 640 /// Gets the base address of the TLS IO region.
612 VAddr GetTLSIORegionBaseAddress() const; 641 VAddr GetTLSIORegionBaseAddress() const;
@@ -657,6 +686,11 @@ private:
657 */ 686 */
658 VMAIter MergeAdjacent(VMAIter vma); 687 VMAIter MergeAdjacent(VMAIter vma);
659 688
689 /**
690 * Merges two adjacent VMAs.
691 */
692 void MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryArea& right);
693
660 /// Updates the pages corresponding to this VMA so they match the VMA's attributes. 694 /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
661 void UpdatePageTableForVMA(const VirtualMemoryArea& vma); 695 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
662 696
@@ -701,6 +735,13 @@ private:
701 MemoryAttribute attribute_mask, MemoryAttribute attribute, 735 MemoryAttribute attribute_mask, MemoryAttribute attribute,
702 MemoryAttribute ignore_mask) const; 736 MemoryAttribute ignore_mask) const;
703 737
738 /// Gets the amount of memory currently mapped (state != Unmapped) in a range.
739 ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const;
740
741 /// Gets the amount of memory unmappable by UnmapPhysicalMemory in a range.
742 ResultVal<std::size_t> SizeOfUnmappablePhysicalMemoryInRange(VAddr address,
743 std::size_t size) const;
744
704 /** 745 /**
705 * A map covering the entirety of the managed address space, keyed by the `base` field of each 746 * A map covering the entirety of the managed address space, keyed by the `base` field of each
706 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant 747 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
@@ -726,8 +767,8 @@ private:
726 VAddr map_region_base = 0; 767 VAddr map_region_base = 0;
727 VAddr map_region_end = 0; 768 VAddr map_region_end = 0;
728 769
729 VAddr new_map_region_base = 0; 770 VAddr stack_region_base = 0;
730 VAddr new_map_region_end = 0; 771 VAddr stack_region_end = 0;
731 772
732 VAddr tls_io_region_base = 0; 773 VAddr tls_io_region_base = 0;
733 VAddr tls_io_region_end = 0; 774 VAddr tls_io_region_end = 0;
@@ -742,6 +783,11 @@ private:
742 // end of the range. This is essentially 'base_address + current_size'. 783 // end of the range. This is essentially 'base_address + current_size'.
743 VAddr heap_end = 0; 784 VAddr heap_end = 0;
744 785
786 // The current amount of memory mapped via MapPhysicalMemory.
787 // This is used here (and in Nintendo's kernel) only for debugging, and does not impact
788 // any behavior.
789 u64 physical_memory_mapped = 0;
790
745 Core::System& system; 791 Core::System& system;
746}; 792};
747} // namespace Kernel 793} // namespace Kernel
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 33cebb48b..a192a1f5f 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -29,7 +29,8 @@
29#include "core/hle/service/am/omm.h" 29#include "core/hle/service/am/omm.h"
30#include "core/hle/service/am/spsm.h" 30#include "core/hle/service/am/spsm.h"
31#include "core/hle/service/am/tcap.h" 31#include "core/hle/service/am/tcap.h"
32#include "core/hle/service/apm/apm.h" 32#include "core/hle/service/apm/controller.h"
33#include "core/hle/service/apm/interface.h"
33#include "core/hle/service/filesystem/filesystem.h" 34#include "core/hle/service/filesystem/filesystem.h"
34#include "core/hle/service/ns/ns.h" 35#include "core/hle/service/ns/ns.h"
35#include "core/hle/service/nvflinger/nvflinger.h" 36#include "core/hle/service/nvflinger/nvflinger.h"
@@ -265,12 +266,12 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
265 {65, nullptr, "ReportUserIsActive"}, 266 {65, nullptr, "ReportUserIsActive"},
266 {66, nullptr, "GetCurrentIlluminance"}, 267 {66, nullptr, "GetCurrentIlluminance"},
267 {67, nullptr, "IsIlluminanceAvailable"}, 268 {67, nullptr, "IsIlluminanceAvailable"},
268 {68, nullptr, "SetAutoSleepDisabled"}, 269 {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
269 {69, nullptr, "IsAutoSleepDisabled"}, 270 {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
270 {70, nullptr, "ReportMultimediaError"}, 271 {70, nullptr, "ReportMultimediaError"},
271 {71, nullptr, "GetCurrentIlluminanceEx"}, 272 {71, nullptr, "GetCurrentIlluminanceEx"},
272 {80, nullptr, "SetWirelessPriorityMode"}, 273 {80, nullptr, "SetWirelessPriorityMode"},
273 {90, nullptr, "GetAccumulatedSuspendedTickValue"}, 274 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
274 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, 275 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
275 {100, nullptr, "SetAlbumImageTakenNotificationEnabled"}, 276 {100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
276 {1000, nullptr, "GetDebugStorageChannel"}, 277 {1000, nullptr, "GetDebugStorageChannel"},
@@ -283,10 +284,14 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
283 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 284 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
284 "ISelfController:LaunchableEvent"); 285 "ISelfController:LaunchableEvent");
285 286
286 // TODO(ogniK): Figure out where, when and why this event gets signalled 287 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
288 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
289 // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
290 // suspended if the event has previously been created by a call to
291 // GetAccumulatedSuspendedTickChangedEvent.
287 accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair( 292 accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(
288 kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent"); 293 kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent");
289 accumulated_suspended_tick_changed_event.writable->Signal(); // Is signalled on creation 294 accumulated_suspended_tick_changed_event.writable->Signal();
290} 295}
291 296
292ISelfController::~ISelfController() = default; 297ISelfController::~ISelfController() = default;
@@ -449,11 +454,47 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
449 rb.Push<u32>(idle_time_detection_extension); 454 rb.Push<u32>(idle_time_detection_extension);
450} 455}
451 456
457void ISelfController::SetAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
458 IPC::RequestParser rp{ctx};
459 is_auto_sleep_disabled = rp.Pop<bool>();
460
461 // On the system itself, if the previous state of is_auto_sleep_disabled
462 // differed from the current value passed in, it'd signify the internal
463 // window manager to update (and also increment some statistics like update counts)
464 //
465 // It'd also indicate this change to an idle handling context.
466 //
467 // However, given we're emulating this behavior, most of this can be ignored
468 // and it's sufficient to simply set the member variable for querying via
469 // IsAutoSleepDisabled().
470
471 LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
472
473 IPC::ResponseBuilder rb{ctx, 2};
474 rb.Push(RESULT_SUCCESS);
475}
476
477void ISelfController::IsAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
478 LOG_DEBUG(Service_AM, "called.");
479
480 IPC::ResponseBuilder rb{ctx, 3};
481 rb.Push(RESULT_SUCCESS);
482 rb.Push(is_auto_sleep_disabled);
483}
484
485void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) {
486 LOG_DEBUG(Service_AM, "called.");
487
488 // This command returns the total number of system ticks since ISelfController creation
489 // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
490 // can just always return 0 ticks.
491 IPC::ResponseBuilder rb{ctx, 4};
492 rb.Push(RESULT_SUCCESS);
493 rb.Push<u64>(0);
494}
495
452void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) { 496void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) {
453 // The implementation of this function is fine as is, the reason we're labelling it as stubbed 497 LOG_DEBUG(Service_AM, "called.");
454 // is because we're currently unsure when and where accumulated_suspended_tick_changed_event is
455 // actually signalled for the time being.
456 LOG_WARNING(Service_AM, "(STUBBED) called");
457 498
458 IPC::ResponseBuilder rb{ctx, 2, 1}; 499 IPC::ResponseBuilder rb{ctx, 2, 1};
459 rb.Push(RESULT_SUCCESS); 500 rb.Push(RESULT_SUCCESS);
@@ -508,8 +549,9 @@ void AppletMessageQueue::OperationModeChanged() {
508 on_operation_mode_changed.writable->Signal(); 549 on_operation_mode_changed.writable->Signal();
509} 550}
510 551
511ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) 552ICommonStateGetter::ICommonStateGetter(Core::System& system,
512 : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) { 553 std::shared_ptr<AppletMessageQueue> msg_queue)
554 : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {
513 // clang-format off 555 // clang-format off
514 static const FunctionInfo functions[] = { 556 static const FunctionInfo functions[] = {
515 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, 557 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -542,7 +584,7 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
542 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, 584 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
543 {64, nullptr, "SetTvPowerStateMatchingMode"}, 585 {64, nullptr, "SetTvPowerStateMatchingMode"},
544 {65, nullptr, "GetApplicationIdByContentActionName"}, 586 {65, nullptr, "GetApplicationIdByContentActionName"},
545 {66, nullptr, "SetCpuBoostMode"}, 587 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
546 {80, nullptr, "PerformSystemButtonPressingIfInFocus"}, 588 {80, nullptr, "PerformSystemButtonPressingIfInFocus"},
547 {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, 589 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
548 {91, nullptr, "GetCurrentPerformanceConfiguration"}, 590 {91, nullptr, "GetCurrentPerformanceConfiguration"},
@@ -623,6 +665,16 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
623 } 665 }
624} 666}
625 667
668void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
669 LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
670
671 const auto& sm = system.ServiceManager();
672 const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
673 ASSERT(apm_sys != nullptr);
674
675 apm_sys->SetCpuBoostMode(ctx);
676}
677
626IStorage::IStorage(std::vector<u8> buffer) 678IStorage::IStorage(std::vector<u8> buffer)
627 : ServiceFramework("IStorage"), buffer(std::move(buffer)) { 679 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
628 // clang-format off 680 // clang-format off
@@ -651,13 +703,11 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
651} 703}
652 704
653void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 705void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
654 const bool use_docked_mode{Settings::values.use_docked_mode}; 706 LOG_DEBUG(Service_AM, "called");
655 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
656 707
657 IPC::ResponseBuilder rb{ctx, 3}; 708 IPC::ResponseBuilder rb{ctx, 3};
658 rb.Push(RESULT_SUCCESS); 709 rb.Push(RESULT_SUCCESS);
659 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked 710 rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
660 : APM::PerformanceMode::Handheld));
661} 711}
662 712
663class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 713class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 4ea609d23..6cb582483 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -133,6 +133,9 @@ private:
133 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); 133 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
134 void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 134 void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
135 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 135 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
136 void SetAutoSleepDisabled(Kernel::HLERequestContext& ctx);
137 void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
138 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
136 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); 139 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
137 140
138 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 141 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -141,11 +144,13 @@ private:
141 144
142 u32 idle_time_detection_extension = 0; 145 u32 idle_time_detection_extension = 0;
143 u64 num_fatal_sections_entered = 0; 146 u64 num_fatal_sections_entered = 0;
147 bool is_auto_sleep_disabled = false;
144}; 148};
145 149
146class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 150class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
147public: 151public:
148 explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue); 152 explicit ICommonStateGetter(Core::System& system,
153 std::shared_ptr<AppletMessageQueue> msg_queue);
149 ~ICommonStateGetter() override; 154 ~ICommonStateGetter() override;
150 155
151private: 156private:
@@ -167,7 +172,9 @@ private:
167 void GetPerformanceMode(Kernel::HLERequestContext& ctx); 172 void GetPerformanceMode(Kernel::HLERequestContext& ctx);
168 void GetBootMode(Kernel::HLERequestContext& ctx); 173 void GetBootMode(Kernel::HLERequestContext& ctx);
169 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 174 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
175 void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
170 176
177 Core::System& system;
171 std::shared_ptr<AppletMessageQueue> msg_queue; 178 std::shared_ptr<AppletMessageQueue> msg_queue;
172}; 179};
173 180
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index fe5beb8f9..a34368c8b 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -42,7 +42,7 @@ private:
42 42
43 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 43 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
44 rb.Push(RESULT_SUCCESS); 44 rb.Push(RESULT_SUCCESS);
45 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 45 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
46 } 46 }
47 47
48 void GetSelfController(Kernel::HLERequestContext& ctx) { 48 void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -146,7 +146,7 @@ private:
146 146
147 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 147 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
148 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
149 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 149 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
150 } 150 }
151 151
152 void GetSelfController(Kernel::HLERequestContext& ctx) { 152 void GetSelfController(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 6e255fe95..5d53ef113 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -80,7 +80,7 @@ private:
80 80
81 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 81 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
82 rb.Push(RESULT_SUCCESS); 82 rb.Push(RESULT_SUCCESS);
83 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 83 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
84 } 84 }
85 85
86 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 86 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index f3c09bbb1..85bbf5988 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -2,7 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 5#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/apm/apm.h" 6#include "core/hle/service/apm/apm.h"
8#include "core/hle/service/apm/interface.h" 7#include "core/hle/service/apm/interface.h"
@@ -12,11 +11,15 @@ namespace Service::APM {
12Module::Module() = default; 11Module::Module() = default;
13Module::~Module() = default; 12Module::~Module() = default;
14 13
15void InstallInterfaces(SM::ServiceManager& service_manager) { 14void InstallInterfaces(Core::System& system) {
16 auto module_ = std::make_shared<Module>(); 15 auto module_ = std::make_shared<Module>();
17 std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); 16 std::make_shared<APM>(module_, system.GetAPMController(), "apm")
18 std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager); 17 ->InstallAsService(system.ServiceManager());
19 std::make_shared<APM_Sys>()->InstallAsService(service_manager); 18 std::make_shared<APM>(module_, system.GetAPMController(), "apm:p")
19 ->InstallAsService(system.ServiceManager());
20 std::make_shared<APM>(module_, system.GetAPMController(), "apm:am")
21 ->InstallAsService(system.ServiceManager());
22 std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager());
20} 23}
21 24
22} // namespace Service::APM 25} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index 4d7d5bb7c..cf4c2bb11 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -8,11 +8,6 @@
8 8
9namespace Service::APM { 9namespace Service::APM {
10 10
11enum class PerformanceMode : u8 {
12 Handheld = 0,
13 Docked = 1,
14};
15
16class Module final { 11class Module final {
17public: 12public:
18 Module(); 13 Module();
@@ -20,6 +15,6 @@ public:
20}; 15};
21 16
22/// Registers all AM services with the specified service manager. 17/// Registers all AM services with the specified service manager.
23void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(Core::System& system);
24 19
25} // namespace Service::APM 20} // namespace Service::APM
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
new file mode 100644
index 000000000..4376612eb
--- /dev/null
+++ b/src/core/hle/service/apm/controller.cpp
@@ -0,0 +1,68 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/core_timing.h"
7#include "core/hle/service/apm/controller.h"
8#include "core/settings.h"
9
10namespace Service::APM {
11
12constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION =
13 PerformanceConfiguration::Config7;
14
15Controller::Controller(Core::Timing::CoreTiming& core_timing)
16 : core_timing(core_timing), configs{
17 {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
18 {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
19 } {}
20
21Controller::~Controller() = default;
22
23void Controller::SetPerformanceConfiguration(PerformanceMode mode,
24 PerformanceConfiguration config) {
25 static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{
26 {PerformanceConfiguration::Config1, 1020}, {PerformanceConfiguration::Config2, 1020},
27 {PerformanceConfiguration::Config3, 1224}, {PerformanceConfiguration::Config4, 1020},
28 {PerformanceConfiguration::Config5, 1020}, {PerformanceConfiguration::Config6, 1224},
29 {PerformanceConfiguration::Config7, 1020}, {PerformanceConfiguration::Config8, 1020},
30 {PerformanceConfiguration::Config9, 1020}, {PerformanceConfiguration::Config10, 1020},
31 {PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020},
32 {PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785},
33 {PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020},
34 };
35
36 SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second);
37 configs.insert_or_assign(mode, config);
38}
39
40void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
41 constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{
42 PerformanceConfiguration::Config7,
43 PerformanceConfiguration::Config13,
44 PerformanceConfiguration::Config15,
45 }};
46
47 SetPerformanceConfiguration(PerformanceMode::Docked,
48 BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode)));
49}
50
51PerformanceMode Controller::GetCurrentPerformanceMode() {
52 return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
53}
54
55PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
56 if (configs.find(mode) == configs.end()) {
57 configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION);
58 }
59
60 return configs[mode];
61}
62
63void Controller::SetClockSpeed(u32 mhz) {
64 LOG_INFO(Service_APM, "called, mhz={:08X}", mhz);
65 // TODO(DarkLordZach): Actually signal core_timing to change clock speed.
66}
67
68} // namespace Service::APM
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h
new file mode 100644
index 000000000..8ac80eaea
--- /dev/null
+++ b/src/core/hle/service/apm/controller.h
@@ -0,0 +1,70 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include "common/common_types.h"
9
10namespace Core::Timing {
11class CoreTiming;
12}
13
14namespace Service::APM {
15
16enum class PerformanceConfiguration : u32 {
17 Config1 = 0x00010000,
18 Config2 = 0x00010001,
19 Config3 = 0x00010002,
20 Config4 = 0x00020000,
21 Config5 = 0x00020001,
22 Config6 = 0x00020002,
23 Config7 = 0x00020003,
24 Config8 = 0x00020004,
25 Config9 = 0x00020005,
26 Config10 = 0x00020006,
27 Config11 = 0x92220007,
28 Config12 = 0x92220008,
29 Config13 = 0x92220009,
30 Config14 = 0x9222000A,
31 Config15 = 0x9222000B,
32 Config16 = 0x9222000C,
33};
34
35enum class CpuBoostMode : u32 {
36 Disabled = 0,
37 Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16
38 Partial = 2, // GPU Only -> Config 15 or 16
39};
40
41enum class PerformanceMode : u8 {
42 Handheld = 0,
43 Docked = 1,
44};
45
46// Class to manage the state and change of the emulated system performance.
47// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or
48// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate
49// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the
50// system during times of high load -- this simply maps to different PerformanceConfigs to use.
51class Controller {
52public:
53 Controller(Core::Timing::CoreTiming& core_timing);
54 ~Controller();
55
56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
57 void SetFromCpuBoostMode(CpuBoostMode mode);
58
59 PerformanceMode GetCurrentPerformanceMode();
60 PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode);
61
62private:
63 void SetClockSpeed(u32 mhz);
64
65 std::map<PerformanceMode, PerformanceConfiguration> configs;
66
67 Core::Timing::CoreTiming& core_timing;
68};
69
70} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index d058c0245..06f0f8edd 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -5,43 +5,32 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/apm/apm.h" 7#include "core/hle/service/apm/apm.h"
8#include "core/hle/service/apm/controller.h"
8#include "core/hle/service/apm/interface.h" 9#include "core/hle/service/apm/interface.h"
9 10
10namespace Service::APM { 11namespace Service::APM {
11 12
12class ISession final : public ServiceFramework<ISession> { 13class ISession final : public ServiceFramework<ISession> {
13public: 14public:
14 ISession() : ServiceFramework("ISession") { 15 ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) {
15 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
16 {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, 17 {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
17 {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, 18 {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
19 {2, nullptr, "SetCpuOverclockEnabled"},
18 }; 20 };
19 RegisterHandlers(functions); 21 RegisterHandlers(functions);
20 } 22 }
21 23
22private: 24private:
23 enum class PerformanceConfiguration : u32 {
24 Config1 = 0x00010000,
25 Config2 = 0x00010001,
26 Config3 = 0x00010002,
27 Config4 = 0x00020000,
28 Config5 = 0x00020001,
29 Config6 = 0x00020002,
30 Config7 = 0x00020003,
31 Config8 = 0x00020004,
32 Config9 = 0x00020005,
33 Config10 = 0x00020006,
34 Config11 = 0x92220007,
35 Config12 = 0x92220008,
36 };
37
38 void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { 25 void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
39 IPC::RequestParser rp{ctx}; 26 IPC::RequestParser rp{ctx};
40 27
41 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 28 const auto mode = rp.PopEnum<PerformanceMode>();
42 u32 config = rp.Pop<u32>(); 29 const auto config = rp.PopEnum<PerformanceConfiguration>();
43 LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), 30 LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode),
44 config); 31 static_cast<u32>(config));
32
33 controller.SetPerformanceConfiguration(mode, config);
45 34
46 IPC::ResponseBuilder rb{ctx, 2}; 35 IPC::ResponseBuilder rb{ctx, 2};
47 rb.Push(RESULT_SUCCESS); 36 rb.Push(RESULT_SUCCESS);
@@ -50,20 +39,23 @@ private:
50 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { 39 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
51 IPC::RequestParser rp{ctx}; 40 IPC::RequestParser rp{ctx};
52 41
53 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 42 const auto mode = rp.PopEnum<PerformanceMode>();
54 LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); 43 LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode));
55 44
56 IPC::ResponseBuilder rb{ctx, 3}; 45 IPC::ResponseBuilder rb{ctx, 3};
57 rb.Push(RESULT_SUCCESS); 46 rb.Push(RESULT_SUCCESS);
58 rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); 47 rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
59 } 48 }
49
50 Controller& controller;
60}; 51};
61 52
62APM::APM(std::shared_ptr<Module> apm, const char* name) 53APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name)
63 : ServiceFramework(name), apm(std::move(apm)) { 54 : ServiceFramework(name), apm(std::move(apm)), controller(controller) {
64 static const FunctionInfo functions[] = { 55 static const FunctionInfo functions[] = {
65 {0, &APM::OpenSession, "OpenSession"}, 56 {0, &APM::OpenSession, "OpenSession"},
66 {1, nullptr, "GetPerformanceMode"}, 57 {1, &APM::GetPerformanceMode, "GetPerformanceMode"},
58 {6, nullptr, "IsCpuOverclockEnabled"},
67 }; 59 };
68 RegisterHandlers(functions); 60 RegisterHandlers(functions);
69} 61}
@@ -75,10 +67,17 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
75 67
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 68 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
77 rb.Push(RESULT_SUCCESS); 69 rb.Push(RESULT_SUCCESS);
78 rb.PushIpcInterface<ISession>(); 70 rb.PushIpcInterface<ISession>(controller);
71}
72
73void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
74 LOG_DEBUG(Service_APM, "called");
75
76 IPC::ResponseBuilder rb{ctx, 2};
77 rb.PushEnum(controller.GetCurrentPerformanceMode());
79} 78}
80 79
81APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { 80APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) {
82 // clang-format off 81 // clang-format off
83 static const FunctionInfo functions[] = { 82 static const FunctionInfo functions[] = {
84 {0, nullptr, "RequestPerformanceMode"}, 83 {0, nullptr, "RequestPerformanceMode"},
@@ -87,8 +86,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
87 {3, nullptr, "GetLastThrottlingState"}, 86 {3, nullptr, "GetLastThrottlingState"},
88 {4, nullptr, "ClearLastThrottlingState"}, 87 {4, nullptr, "ClearLastThrottlingState"},
89 {5, nullptr, "LoadAndApplySettings"}, 88 {5, nullptr, "LoadAndApplySettings"},
90 {6, nullptr, "SetCpuBoostMode"}, 89 {6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"},
91 {7, nullptr, "GetCurrentPerformanceConfiguration"}, 90 {7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"},
92 }; 91 };
93 // clang-format on 92 // clang-format on
94 93
@@ -102,7 +101,28 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
102 101
103 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 102 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
104 rb.Push(RESULT_SUCCESS); 103 rb.Push(RESULT_SUCCESS);
105 rb.PushIpcInterface<ISession>(); 104 rb.PushIpcInterface<ISession>(controller);
105}
106
107void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109 const auto mode = rp.PopEnum<CpuBoostMode>();
110
111 LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode));
112
113 controller.SetFromCpuBoostMode(mode);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(RESULT_SUCCESS);
117}
118
119void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
120 LOG_DEBUG(Service_APM, "called");
121
122 IPC::ResponseBuilder rb{ctx, 3};
123 rb.Push(RESULT_SUCCESS);
124 rb.PushEnum(
125 controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode()));
106} 126}
107 127
108} // namespace Service::APM 128} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index 773541aa4..de1b89437 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -8,24 +8,34 @@
8 8
9namespace Service::APM { 9namespace Service::APM {
10 10
11class Controller;
12class Module;
13
11class APM final : public ServiceFramework<APM> { 14class APM final : public ServiceFramework<APM> {
12public: 15public:
13 explicit APM(std::shared_ptr<Module> apm, const char* name); 16 explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name);
14 ~APM() override; 17 ~APM() override;
15 18
16private: 19private:
17 void OpenSession(Kernel::HLERequestContext& ctx); 20 void OpenSession(Kernel::HLERequestContext& ctx);
21 void GetPerformanceMode(Kernel::HLERequestContext& ctx);
18 22
19 std::shared_ptr<Module> apm; 23 std::shared_ptr<Module> apm;
24 Controller& controller;
20}; 25};
21 26
22class APM_Sys final : public ServiceFramework<APM_Sys> { 27class APM_Sys final : public ServiceFramework<APM_Sys> {
23public: 28public:
24 explicit APM_Sys(); 29 explicit APM_Sys(Controller& controller);
25 ~APM_Sys() override; 30 ~APM_Sys() override;
26 31
32 void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
33
27private: 34private:
28 void GetPerformanceEvent(Kernel::HLERequestContext& ctx); 35 void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
36 void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx);
37
38 Controller& controller;
29}; 39};
30 40
31} // namespace Service::APM 41} // namespace Service::APM
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3711e1ea1..679299f68 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -25,7 +25,8 @@ namespace Service::Audio {
25 25
26class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { 26class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
27public: 27public:
28 explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params) 28 explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params,
29 const std::size_t instance_number)
29 : ServiceFramework("IAudioRenderer") { 30 : ServiceFramework("IAudioRenderer") {
30 // clang-format off 31 // clang-format off
31 static const FunctionInfo functions[] = { 32 static const FunctionInfo functions[] = {
@@ -48,8 +49,8 @@ public:
48 auto& system = Core::System::GetInstance(); 49 auto& system = Core::System::GetInstance();
49 system_event = Kernel::WritableEvent::CreateEventPair( 50 system_event = Kernel::WritableEvent::CreateEventPair(
50 system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent"); 51 system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent");
51 renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params, 52 renderer = std::make_unique<AudioCore::AudioRenderer>(
52 system_event.writable); 53 system.CoreTiming(), audren_params, system_event.writable, instance_number);
53 } 54 }
54 55
55private: 56private:
@@ -607,7 +608,7 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
607 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 608 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
608 609
609 rb.Push(RESULT_SUCCESS); 610 rb.Push(RESULT_SUCCESS);
610 rb.PushIpcInterface<IAudioRenderer>(params); 611 rb.PushIpcInterface<IAudioRenderer>(params, audren_instance_count++);
611} 612}
612 613
613bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { 614bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 1d3c8df61..49f2733cf 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -33,6 +33,7 @@ private:
33 }; 33 };
34 34
35 bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; 35 bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const;
36 std::size_t audren_instance_count = 0;
36}; 37};
37 38
38} // namespace Service::Audio 39} // namespace Service::Audio
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 1ebfeb4bf..8ce110dd1 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -472,12 +472,12 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
472 } 472 }
473} 473}
474 474
475void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { 475void InstallInterfaces(Core::System& system) {
476 romfs_factory = nullptr; 476 romfs_factory = nullptr;
477 CreateFactories(vfs, false); 477 CreateFactories(*system.GetFilesystem(), false);
478 std::make_shared<FSP_LDR>()->InstallAsService(service_manager); 478 std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
479 std::make_shared<FSP_PR>()->InstallAsService(service_manager); 479 std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
480 std::make_shared<FSP_SRV>()->InstallAsService(service_manager); 480 std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
481} 481}
482 482
483} // namespace Service::FileSystem 483} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6481f237c..3849dd89e 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -65,7 +65,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
65// above is called. 65// above is called.
66void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); 66void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
67 67
68void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs); 68void InstallInterfaces(Core::System& system);
69 69
70// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of 70// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
71// pointers and booleans. This makes using a VfsDirectory with switch services much easier and 71// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e7df8fd98..d3cd46a9b 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -26,6 +26,7 @@
26#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
27#include "core/hle/service/filesystem/filesystem.h" 27#include "core/hle/service/filesystem/filesystem.h"
28#include "core/hle/service/filesystem/fsp_srv.h" 28#include "core/hle/service/filesystem/fsp_srv.h"
29#include "core/reporter.h"
29 30
30namespace Service::FileSystem { 31namespace Service::FileSystem {
31 32
@@ -613,7 +614,7 @@ private:
613 u64 next_entry_index = 0; 614 u64 next_entry_index = 0;
614}; 615};
615 616
616FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { 617FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
617 // clang-format off 618 // clang-format off
618 static const FunctionInfo functions[] = { 619 static const FunctionInfo functions[] = {
619 {0, nullptr, "OpenFileSystem"}, 620 {0, nullptr, "OpenFileSystem"},
@@ -710,14 +711,14 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
710 {1001, nullptr, "SetSaveDataSize"}, 711 {1001, nullptr, "SetSaveDataSize"},
711 {1002, nullptr, "SetSaveDataRootPath"}, 712 {1002, nullptr, "SetSaveDataRootPath"},
712 {1003, nullptr, "DisableAutoSaveDataCreation"}, 713 {1003, nullptr, "DisableAutoSaveDataCreation"},
713 {1004, nullptr, "SetGlobalAccessLogMode"}, 714 {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
714 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, 715 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
715 {1006, nullptr, "OutputAccessLogToSdCard"}, 716 {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
716 {1007, nullptr, "RegisterUpdatePartition"}, 717 {1007, nullptr, "RegisterUpdatePartition"},
717 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 718 {1008, nullptr, "OpenRegisteredUpdatePartition"},
718 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 719 {1009, nullptr, "GetAndClearMemoryReportInfo"},
719 {1010, nullptr, "SetDataStorageRedirectTarget"}, 720 {1010, nullptr, "SetDataStorageRedirectTarget"},
720 {1011, nullptr, "OutputAccessLogToSdCard2"}, 721 {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
721 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 722 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
722 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 723 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
723 {1200, nullptr, "OpenMultiCommitManager"}, 724 {1200, nullptr, "OpenMultiCommitManager"},
@@ -814,21 +815,22 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
814 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space)); 815 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
815} 816}
816 817
817void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 818void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
818 LOG_WARNING(Service_FS, "(STUBBED) called"); 819 IPC::RequestParser rp{ctx};
820 log_mode = rp.PopEnum<LogMode>();
819 821
820 enum class LogMode : u32 { 822 LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
821 Off, 823
822 Log, 824 IPC::ResponseBuilder rb{ctx, 2};
823 RedirectToSdCard, 825 rb.Push(RESULT_SUCCESS);
824 LogToSdCard = Log | RedirectToSdCard, 826}
825 }; 827
828void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
829 LOG_DEBUG(Service_FS, "called");
826 830
827 // Given we always want to receive logging information,
828 // we always specify logging as enabled.
829 IPC::ResponseBuilder rb{ctx, 3}; 831 IPC::ResponseBuilder rb{ctx, 3};
830 rb.Push(RESULT_SUCCESS); 832 rb.Push(RESULT_SUCCESS);
831 rb.PushEnum(LogMode::Log); 833 rb.PushEnum(log_mode);
832} 834}
833 835
834void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { 836void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
@@ -902,4 +904,26 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
902 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 904 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
903} 905}
904 906
907void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
908 const auto raw = ctx.ReadBuffer();
909 auto log = Common::StringFromFixedZeroTerminatedBuffer(
910 reinterpret_cast<const char*>(raw.data()), raw.size());
911
912 LOG_DEBUG(Service_FS, "called, log='{}'", log);
913
914 reporter.SaveFilesystemAccessReport(log_mode, std::move(log));
915
916 IPC::ResponseBuilder rb{ctx, 2};
917 rb.Push(RESULT_SUCCESS);
918}
919
920void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
921 LOG_DEBUG(Service_FS, "called");
922
923 IPC::ResponseBuilder rb{ctx, 4};
924 rb.Push(RESULT_SUCCESS);
925 rb.PushEnum(AccessLogVersion::Latest);
926 rb.Push(access_log_program_index);
927}
928
905} // namespace Service::FileSystem 929} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index d7572ba7a..b5486a193 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -7,15 +7,32 @@
7#include <memory> 7#include <memory>
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core {
11class Reporter;
12}
13
10namespace FileSys { 14namespace FileSys {
11class FileSystemBackend; 15class FileSystemBackend;
12} 16}
13 17
14namespace Service::FileSystem { 18namespace Service::FileSystem {
15 19
20enum class AccessLogVersion : u32 {
21 V7_0_0 = 2,
22
23 Latest = V7_0_0,
24};
25
26enum class LogMode : u32 {
27 Off,
28 Log,
29 RedirectToSdCard,
30 LogToSdCard = Log | RedirectToSdCard,
31};
32
16class FSP_SRV final : public ServiceFramework<FSP_SRV> { 33class FSP_SRV final : public ServiceFramework<FSP_SRV> {
17public: 34public:
18 explicit FSP_SRV(); 35 explicit FSP_SRV(const Core::Reporter& reporter);
19 ~FSP_SRV() override; 36 ~FSP_SRV() override;
20 37
21private: 38private:
@@ -26,13 +43,20 @@ private:
26 void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx); 43 void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
27 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); 44 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
28 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); 45 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
46 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
29 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 47 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
30 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 48 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
31 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); 49 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
32 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 50 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
51 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
52 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
33 53
34 FileSys::VirtualFile romfs; 54 FileSys::VirtualFile romfs;
35 u64 current_process_id = 0; 55 u64 current_process_id = 0;
56 u32 access_log_program_index = 0;
57 LogMode log_mode = LogMode::LogToSdCard;
58
59 const Core::Reporter& reporter;
36}; 60};
37 61
38} // namespace Service::FileSystem 62} // namespace Service::FileSystem
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index dec541f2e..d1ec12ef9 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -22,7 +22,7 @@ public:
22 {0, nullptr, "GetCompletionEvent"}, 22 {0, nullptr, "GetCompletionEvent"},
23 {1, nullptr, "Cancel"}, 23 {1, nullptr, "Cancel"},
24 {10100, nullptr, "GetFriendListIds"}, 24 {10100, nullptr, "GetFriendListIds"},
25 {10101, nullptr, "GetFriendList"}, 25 {10101, &IFriendService::GetFriendList, "GetFriendList"},
26 {10102, nullptr, "UpdateFriendInfo"}, 26 {10102, nullptr, "UpdateFriendInfo"},
27 {10110, nullptr, "GetFriendProfileImage"}, 27 {10110, nullptr, "GetFriendProfileImage"},
28 {10200, nullptr, "SendFriendRequestForApplication"}, 28 {10200, nullptr, "SendFriendRequestForApplication"},
@@ -99,6 +99,23 @@ public:
99 } 99 }
100 100
101private: 101private:
102 enum class PresenceFilter : u32 {
103 None = 0,
104 Online = 1,
105 OnlinePlay = 2,
106 OnlineOrOnlinePlay = 3,
107 };
108
109 struct SizedFriendFilter {
110 PresenceFilter presence;
111 u8 is_favorite;
112 u8 same_app;
113 u8 same_app_played;
114 u8 arbitary_app_played;
115 u64 group_id;
116 };
117 static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
118
102 void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) { 119 void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
103 // Stub used by Splatoon 2 120 // Stub used by Splatoon 2
104 LOG_WARNING(Service_ACC, "(STUBBED) called"); 121 LOG_WARNING(Service_ACC, "(STUBBED) called");
@@ -112,6 +129,22 @@ private:
112 IPC::ResponseBuilder rb{ctx, 2}; 129 IPC::ResponseBuilder rb{ctx, 2};
113 rb.Push(RESULT_SUCCESS); 130 rb.Push(RESULT_SUCCESS);
114 } 131 }
132
133 void GetFriendList(Kernel::HLERequestContext& ctx) {
134 IPC::RequestParser rp{ctx};
135 const auto friend_offset = rp.Pop<u32>();
136 const auto uuid = rp.PopRaw<Common::UUID>();
137 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
138 const auto pid = rp.Pop<u64>();
139 LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
140 uuid.Format(), pid);
141
142 IPC::ResponseBuilder rb{ctx, 3};
143 rb.Push(RESULT_SUCCESS);
144
145 rb.Push<u32>(0); // Friend count
146 // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
147 }
115}; 148};
116 149
117class INotificationService final : public ServiceFramework<INotificationService> { 150class INotificationService final : public ServiceFramework<INotificationService> {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index fdd6d79a2..1e81f776f 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -548,6 +548,37 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
548 connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; 548 connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
549} 549}
550 550
551void Controller_NPad::StartLRAssignmentMode() {
552 // Nothing internally is used for lr assignment mode. Since we have the ability to set the
553 // controller types from boot, it doesn't really matter about showing a selection screen
554 is_in_lr_assignment_mode = true;
555}
556
557void Controller_NPad::StopLRAssignmentMode() {
558 is_in_lr_assignment_mode = false;
559}
560
561bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
562 if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
563 npad_id_2 == NPAD_UNKNOWN) {
564 return true;
565 }
566 const auto npad_index_1 = NPadIdToIndex(npad_id_1);
567 const auto npad_index_2 = NPadIdToIndex(npad_id_2);
568
569 if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
570 !IsControllerSupported(connected_controllers[npad_index_2].type)) {
571 return false;
572 }
573
574 std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
575
576 InitNewlyAddedControler(npad_index_1);
577 InitNewlyAddedControler(npad_index_2);
578
579 return true;
580}
581
551bool Controller_NPad::IsControllerSupported(NPadControllerType controller) { 582bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
552 if (controller == NPadControllerType::Handheld) { 583 if (controller == NPadControllerType::Handheld) {
553 // Handheld is not even a supported type, lets stop here 584 // Handheld is not even a supported type, lets stop here
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 4ff50b3cd..4b6c1083f 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -124,6 +124,10 @@ public:
124 void ConnectAllDisconnectedControllers(); 124 void ConnectAllDisconnectedControllers();
125 void ClearAllControllers(); 125 void ClearAllControllers();
126 126
127 void StartLRAssignmentMode();
128 void StopLRAssignmentMode();
129 bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
130
127 // Logical OR for all buttons presses on all controllers 131 // Logical OR for all buttons presses on all controllers
128 // Specifically for cheat engine and other features. 132 // Specifically for cheat engine and other features.
129 u32 GetAndResetPressState(); 133 u32 GetAndResetPressState();
@@ -321,5 +325,6 @@ private:
321 void RequestPadStateUpdate(u32 npad_id); 325 void RequestPadStateUpdate(u32 npad_id);
322 std::array<ControllerPad, 10> npad_pad_states{}; 326 std::array<ControllerPad, 10> npad_pad_states{};
323 bool IsControllerSupported(NPadControllerType controller); 327 bool IsControllerSupported(NPadControllerType controller);
328 bool is_in_lr_assignment_mode{false};
324}; 329};
325} // namespace Service::HID 330} // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
new file mode 100644
index 000000000..3583642e7
--- /dev/null
+++ b/src/core/hle/service/hid/errors.h
@@ -0,0 +1,13 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/result.h"
8
9namespace Service::HID {
10
11constexpr ResultCode ERR_NPAD_NOT_CONNECTED{ErrorModule::HID, 710};
12
13} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a4ad95d96..0bd24b8eb 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/readable_event.h" 16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/shared_memory.h" 17#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/kernel/writable_event.h" 18#include "core/hle/kernel/writable_event.h"
19#include "core/hle/service/hid/errors.h"
19#include "core/hle/service/hid/hid.h" 20#include "core/hle/service/hid/hid.h"
20#include "core/hle/service/hid/irs.h" 21#include "core/hle/service/hid/irs.h"
21#include "core/hle/service/hid/xcd.h" 22#include "core/hle/service/hid/xcd.h"
@@ -202,11 +203,11 @@ Hid::Hid() : ServiceFramework("hid") {
202 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, 203 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
203 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, 204 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
204 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, 205 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
205 {126, nullptr, "StartLrAssignmentMode"}, 206 {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
206 {127, nullptr, "StopLrAssignmentMode"}, 207 {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
207 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, 208 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
208 {129, nullptr, "GetNpadHandheldActivationMode"}, 209 {129, nullptr, "GetNpadHandheldActivationMode"},
209 {130, nullptr, "SwapNpadAssignment"}, 210 {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
210 {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, 211 {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
211 {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, 212 {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
212 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, 213 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
@@ -733,6 +734,49 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
733 rb.Push(RESULT_SUCCESS); 734 rb.Push(RESULT_SUCCESS);
734} 735}
735 736
737void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx};
739 const auto applet_resource_user_id{rp.Pop<u64>()};
740
741 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
742 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
743 controller.StartLRAssignmentMode();
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(RESULT_SUCCESS);
747}
748
749void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
750 IPC::RequestParser rp{ctx};
751 const auto applet_resource_user_id{rp.Pop<u64>()};
752
753 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
754 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
755 controller.StopLRAssignmentMode();
756
757 IPC::ResponseBuilder rb{ctx, 2};
758 rb.Push(RESULT_SUCCESS);
759}
760
761void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
762 IPC::RequestParser rp{ctx};
763 const auto npad_1{rp.Pop<u32>()};
764 const auto npad_2{rp.Pop<u32>()};
765 const auto applet_resource_user_id{rp.Pop<u64>()};
766
767 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}",
768 applet_resource_user_id, npad_1, npad_2);
769
770 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
771 IPC::ResponseBuilder rb{ctx, 2};
772 if (controller.SwapNpadAssignment(npad_1, npad_2)) {
773 rb.Push(RESULT_SUCCESS);
774 } else {
775 LOG_ERROR(Service_HID, "Npads are not connected!");
776 rb.Push(ERR_NPAD_NOT_CONNECTED);
777 }
778}
779
736class HidDbg final : public ServiceFramework<HidDbg> { 780class HidDbg final : public ServiceFramework<HidDbg> {
737public: 781public:
738 explicit HidDbg() : ServiceFramework{"hid:dbg"} { 782 explicit HidDbg() : ServiceFramework{"hid:dbg"} {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index d3660cad2..28260ef1b 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -119,6 +119,9 @@ private:
119 void StopSixAxisSensor(Kernel::HLERequestContext& ctx); 119 void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
120 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); 120 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
121 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); 121 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
122 void StartLrAssignmentMode(Kernel::HLERequestContext& ctx);
123 void StopLrAssignmentMode(Kernel::HLERequestContext& ctx);
124 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
122 125
123 std::shared_ptr<IAppletResource> applet_resource; 126 std::shared_ptr<IAppletResource> applet_resource;
124}; 127};
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index b839303ac..8ddad8682 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -345,14 +345,16 @@ public:
345 vm_manager 345 vm_manager
346 .MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode) 346 .MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode)
347 .IsSuccess()); 347 .IsSuccess());
348 ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess()); 348 ASSERT(vm_manager.ReprotectRange(nro_address, nro_size, Kernel::VMAPermission::None)
349 .IsSuccess());
349 350
350 if (bss_size > 0) { 351 if (bss_size > 0) {
351 ASSERT(vm_manager 352 ASSERT(vm_manager
352 .MirrorMemory(*map_address + nro_size, bss_address, bss_size, 353 .MirrorMemory(*map_address + nro_size, bss_address, bss_size,
353 Kernel::MemoryState::ModuleCode) 354 Kernel::MemoryState::ModuleCode)
354 .IsSuccess()); 355 .IsSuccess());
355 ASSERT(vm_manager.UnmapRange(bss_address, bss_size).IsSuccess()); 356 ASSERT(vm_manager.ReprotectRange(bss_address, bss_size, Kernel::VMAPermission::None)
357 .IsSuccess());
356 } 358 }
357 359
358 vm_manager.ReprotectRange(*map_address, header.text_size, 360 vm_manager.ReprotectRange(*map_address, header.text_size,
@@ -364,7 +366,8 @@ public:
364 366
365 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 367 Core::System::GetInstance().InvalidateCpuInstructionCaches();
366 368
367 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size}); 369 nro.insert_or_assign(*map_address,
370 NROInfo{hash, nro_address, nro_size, bss_address, bss_size});
368 371
369 IPC::ResponseBuilder rb{ctx, 4}; 372 IPC::ResponseBuilder rb{ctx, 4};
370 rb.Push(RESULT_SUCCESS); 373 rb.Push(RESULT_SUCCESS);
@@ -409,9 +412,23 @@ public:
409 } 412 }
410 413
411 auto& vm_manager = Core::CurrentProcess()->VMManager(); 414 auto& vm_manager = Core::CurrentProcess()->VMManager();
412 const auto& nro_size = iter->second.size; 415 const auto& nro_info = iter->second;
413 416
414 ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess()); 417 // Unmap the mirrored memory
418 ASSERT(
419 vm_manager.UnmapRange(nro_address, nro_info.nro_size + nro_info.bss_size).IsSuccess());
420
421 // Reprotect the source memory
422 ASSERT(vm_manager
423 .ReprotectRange(nro_info.nro_address, nro_info.nro_size,
424 Kernel::VMAPermission::ReadWrite)
425 .IsSuccess());
426 if (nro_info.bss_size > 0) {
427 ASSERT(vm_manager
428 .ReprotectRange(nro_info.bss_address, nro_info.bss_size,
429 Kernel::VMAPermission::ReadWrite)
430 .IsSuccess());
431 }
415 432
416 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 433 Core::System::GetInstance().InvalidateCpuInstructionCaches();
417 434
@@ -473,7 +490,10 @@ private:
473 490
474 struct NROInfo { 491 struct NROInfo {
475 SHA256Hash hash; 492 SHA256Hash hash;
476 u64 size; 493 VAddr nro_address;
494 u64 nro_size;
495 VAddr bss_address;
496 u64 bss_size;
477 }; 497 };
478 498
479 bool initialized = false; 499 bool initialized = false;
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index ce84e25ed..0b3923ad9 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -48,7 +48,7 @@ public:
48 {19, nullptr, "Export"}, 48 {19, nullptr, "Export"},
49 {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, 49 {20, nullptr, "IsBrokenDatabaseWithClearFlag"},
50 {21, &IDatabaseService::GetIndex, "GetIndex"}, 50 {21, &IDatabaseService::GetIndex, "GetIndex"},
51 {22, nullptr, "SetInterfaceVersion"}, 51 {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
52 {23, nullptr, "Convert"}, 52 {23, nullptr, "Convert"},
53 }; 53 };
54 // clang-format on 54 // clang-format on
@@ -350,8 +350,22 @@ private:
350 rb.Push(index); 350 rb.Push(index);
351 } 351 }
352 352
353 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
354 IPC::RequestParser rp{ctx};
355 current_interface_version = rp.PopRaw<u32>();
356
357 LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
358
359 UNIMPLEMENTED_IF(current_interface_version != 1);
360
361 IPC::ResponseBuilder rb{ctx, 2};
362 rb.Push(RESULT_SUCCESS);
363 }
364
353 MiiManager db; 365 MiiManager db;
354 366
367 u32 current_interface_version = 0;
368
355 // Last read offsets of Get functions 369 // Last read offsets of Get functions
356 std::array<u32, 4> offsets{}; 370 std::array<u32, 4> offsets{};
357}; 371};
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index ebcc41a43..fe6b5f798 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -3,11 +3,44 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/ipc_helpers.h" 5#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/process.h"
6#include "core/hle/service/pm/pm.h" 8#include "core/hle/service/pm/pm.h"
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
9namespace Service::PM { 11namespace Service::PM {
10 12
13namespace {
14
15constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
16
17constexpr u64 NO_PROCESS_FOUND_PID{0};
18
19std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList(
20 const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list,
21 std::function<bool(const Kernel::SharedPtr<Kernel::Process>&)> predicate) {
22 const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
23
24 if (iter == process_list.end()) {
25 return std::nullopt;
26 }
27
28 return *iter;
29}
30
31void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
32 const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) {
33 const auto process = SearchProcessList(process_list, [](const auto& process) {
34 return process->GetProcessID() == Kernel::Process::ProcessIDMin;
35 });
36
37 IPC::ResponseBuilder rb{ctx, 4};
38 rb.Push(RESULT_SUCCESS);
39 rb.Push(process.has_value() ? (*process)->GetProcessID() : NO_PROCESS_FOUND_PID);
40}
41
42} // Anonymous namespace
43
11class BootMode final : public ServiceFramework<BootMode> { 44class BootMode final : public ServiceFramework<BootMode> {
12public: 45public:
13 explicit BootMode() : ServiceFramework{"pm:bm"} { 46 explicit BootMode() : ServiceFramework{"pm:bm"} {
@@ -41,14 +74,15 @@ private:
41 74
42class DebugMonitor final : public ServiceFramework<DebugMonitor> { 75class DebugMonitor final : public ServiceFramework<DebugMonitor> {
43public: 76public:
44 explicit DebugMonitor() : ServiceFramework{"pm:dmnt"} { 77 explicit DebugMonitor(const Kernel::KernelCore& kernel)
78 : ServiceFramework{"pm:dmnt"}, kernel(kernel) {
45 // clang-format off 79 // clang-format off
46 static const FunctionInfo functions[] = { 80 static const FunctionInfo functions[] = {
47 {0, nullptr, "GetDebugProcesses"}, 81 {0, nullptr, "GetDebugProcesses"},
48 {1, nullptr, "StartDebugProcess"}, 82 {1, nullptr, "StartDebugProcess"},
49 {2, nullptr, "GetTitlePid"}, 83 {2, &DebugMonitor::GetTitlePid, "GetTitlePid"},
50 {3, nullptr, "EnableDebugForTitleId"}, 84 {3, nullptr, "EnableDebugForTitleId"},
51 {4, nullptr, "GetApplicationPid"}, 85 {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"},
52 {5, nullptr, "EnableDebugForApplication"}, 86 {5, nullptr, "EnableDebugForApplication"},
53 {6, nullptr, "DisableDebug"}, 87 {6, nullptr, "DisableDebug"},
54 }; 88 };
@@ -56,21 +90,77 @@ public:
56 90
57 RegisterHandlers(functions); 91 RegisterHandlers(functions);
58 } 92 }
93
94private:
95 void GetTitlePid(Kernel::HLERequestContext& ctx) {
96 IPC::RequestParser rp{ctx};
97 const auto title_id = rp.PopRaw<u64>();
98
99 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
100
101 const auto process =
102 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) {
103 return process->GetTitleID() == title_id;
104 });
105
106 if (!process.has_value()) {
107 IPC::ResponseBuilder rb{ctx, 2};
108 rb.Push(ERROR_PROCESS_NOT_FOUND);
109 return;
110 }
111
112 IPC::ResponseBuilder rb{ctx, 4};
113 rb.Push(RESULT_SUCCESS);
114 rb.Push((*process)->GetProcessID());
115 }
116
117 void GetApplicationPid(Kernel::HLERequestContext& ctx) {
118 LOG_DEBUG(Service_PM, "called");
119 GetApplicationPidGeneric(ctx, kernel.GetProcessList());
120 }
121
122 const Kernel::KernelCore& kernel;
59}; 123};
60 124
61class Info final : public ServiceFramework<Info> { 125class Info final : public ServiceFramework<Info> {
62public: 126public:
63 explicit Info() : ServiceFramework{"pm:info"} { 127 explicit Info(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list)
128 : ServiceFramework{"pm:info"}, process_list(process_list) {
64 static const FunctionInfo functions[] = { 129 static const FunctionInfo functions[] = {
65 {0, nullptr, "GetTitleId"}, 130 {0, &Info::GetTitleId, "GetTitleId"},
66 }; 131 };
67 RegisterHandlers(functions); 132 RegisterHandlers(functions);
68 } 133 }
134
135private:
136 void GetTitleId(Kernel::HLERequestContext& ctx) {
137 IPC::RequestParser rp{ctx};
138 const auto process_id = rp.PopRaw<u64>();
139
140 LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
141
142 const auto process = SearchProcessList(process_list, [process_id](const auto& process) {
143 return process->GetProcessID() == process_id;
144 });
145
146 if (!process.has_value()) {
147 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(ERROR_PROCESS_NOT_FOUND);
149 return;
150 }
151
152 IPC::ResponseBuilder rb{ctx, 4};
153 rb.Push(RESULT_SUCCESS);
154 rb.Push((*process)->GetTitleID());
155 }
156
157 const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list;
69}; 158};
70 159
71class Shell final : public ServiceFramework<Shell> { 160class Shell final : public ServiceFramework<Shell> {
72public: 161public:
73 explicit Shell() : ServiceFramework{"pm:shell"} { 162 explicit Shell(const Kernel::KernelCore& kernel)
163 : ServiceFramework{"pm:shell"}, kernel(kernel) {
74 // clang-format off 164 // clang-format off
75 static const FunctionInfo functions[] = { 165 static const FunctionInfo functions[] = {
76 {0, nullptr, "LaunchProcess"}, 166 {0, nullptr, "LaunchProcess"},
@@ -79,21 +169,31 @@ public:
79 {3, nullptr, "GetProcessEventWaiter"}, 169 {3, nullptr, "GetProcessEventWaiter"},
80 {4, nullptr, "GetProcessEventType"}, 170 {4, nullptr, "GetProcessEventType"},
81 {5, nullptr, "NotifyBootFinished"}, 171 {5, nullptr, "NotifyBootFinished"},
82 {6, nullptr, "GetApplicationPid"}, 172 {6, &Shell::GetApplicationPid, "GetApplicationPid"},
83 {7, nullptr, "BoostSystemMemoryResourceLimit"}, 173 {7, nullptr, "BoostSystemMemoryResourceLimit"},
84 {8, nullptr, "EnableAdditionalSystemThreads"}, 174 {8, nullptr, "EnableAdditionalSystemThreads"},
175 {9, nullptr, "GetUnimplementedEventHandle"},
85 }; 176 };
86 // clang-format on 177 // clang-format on
87 178
88 RegisterHandlers(functions); 179 RegisterHandlers(functions);
89 } 180 }
181
182private:
183 void GetApplicationPid(Kernel::HLERequestContext& ctx) {
184 LOG_DEBUG(Service_PM, "called");
185 GetApplicationPidGeneric(ctx, kernel.GetProcessList());
186 }
187
188 const Kernel::KernelCore& kernel;
90}; 189};
91 190
92void InstallInterfaces(SM::ServiceManager& sm) { 191void InstallInterfaces(Core::System& system) {
93 std::make_shared<BootMode>()->InstallAsService(sm); 192 std::make_shared<BootMode>()->InstallAsService(system.ServiceManager());
94 std::make_shared<DebugMonitor>()->InstallAsService(sm); 193 std::make_shared<DebugMonitor>(system.Kernel())->InstallAsService(system.ServiceManager());
95 std::make_shared<Info>()->InstallAsService(sm); 194 std::make_shared<Info>(system.Kernel().GetProcessList())
96 std::make_shared<Shell>()->InstallAsService(sm); 195 ->InstallAsService(system.ServiceManager());
196 std::make_shared<Shell>(system.Kernel())->InstallAsService(system.ServiceManager());
97} 197}
98 198
99} // namespace Service::PM 199} // namespace Service::PM
diff --git a/src/core/hle/service/pm/pm.h b/src/core/hle/service/pm/pm.h
index cc8d3f215..852e7050c 100644
--- a/src/core/hle/service/pm/pm.h
+++ b/src/core/hle/service/pm/pm.h
@@ -4,8 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Service::SM { 7namespace Core {
8class ServiceManager; 8class System;
9} 9}
10 10
11namespace Service::PM { 11namespace Service::PM {
@@ -16,6 +16,6 @@ enum class SystemBootMode {
16}; 16};
17 17
18/// Registers all PM services with the specified service manager. 18/// Registers all PM services with the specified service manager.
19void InstallInterfaces(SM::ServiceManager& service_manager); 19void InstallInterfaces(Core::System& system);
20 20
21} // namespace Service::PM 21} // namespace Service::PM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 07b1f4d43..2daa1ae49 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -195,8 +195,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
195// Module interface 195// Module interface
196 196
197/// Initialize ServiceManager 197/// Initialize ServiceManager
198void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, 198void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
199 FileSys::VfsFilesystem& vfs) {
200 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
201 // here and pass it into the respective InstallInterfaces functions. 200 // here and pass it into the respective InstallInterfaces functions.
202 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
@@ -206,7 +205,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
206 Account::InstallInterfaces(system); 205 Account::InstallInterfaces(system);
207 AM::InstallInterfaces(*sm, nv_flinger, system); 206 AM::InstallInterfaces(*sm, nv_flinger, system);
208 AOC::InstallInterfaces(*sm); 207 AOC::InstallInterfaces(*sm);
209 APM::InstallInterfaces(*sm); 208 APM::InstallInterfaces(system);
210 Audio::InstallInterfaces(*sm); 209 Audio::InstallInterfaces(*sm);
211 BCAT::InstallInterfaces(*sm); 210 BCAT::InstallInterfaces(*sm);
212 BPC::InstallInterfaces(*sm); 211 BPC::InstallInterfaces(*sm);
@@ -218,7 +217,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
218 EUPLD::InstallInterfaces(*sm); 217 EUPLD::InstallInterfaces(*sm);
219 Fatal::InstallInterfaces(*sm); 218 Fatal::InstallInterfaces(*sm);
220 FGM::InstallInterfaces(*sm); 219 FGM::InstallInterfaces(*sm);
221 FileSystem::InstallInterfaces(*sm, vfs); 220 FileSystem::InstallInterfaces(system);
222 Friend::InstallInterfaces(*sm); 221 Friend::InstallInterfaces(*sm);
223 Glue::InstallInterfaces(system); 222 Glue::InstallInterfaces(system);
224 GRC::InstallInterfaces(*sm); 223 GRC::InstallInterfaces(*sm);
@@ -242,7 +241,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
242 PCTL::InstallInterfaces(*sm); 241 PCTL::InstallInterfaces(*sm);
243 PCV::InstallInterfaces(*sm); 242 PCV::InstallInterfaces(*sm);
244 PlayReport::InstallInterfaces(*sm); 243 PlayReport::InstallInterfaces(*sm);
245 PM::InstallInterfaces(*sm); 244 PM::InstallInterfaces(system);
246 PSC::InstallInterfaces(*sm); 245 PSC::InstallInterfaces(*sm);
247 PSM::InstallInterfaces(*sm); 246 PSM::InstallInterfaces(*sm);
248 Set::InstallInterfaces(*sm); 247 Set::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index abbfe5524..c6c4bdae5 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -182,8 +182,7 @@ private:
182}; 182};
183 183
184/// Initialize ServiceManager 184/// Initialize ServiceManager
185void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, 185void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
186 FileSys::VfsFilesystem& vfs);
187 186
188/// Shutdown ServiceManager 187/// Shutdown ServiceManager
189void Shutdown(); 188void Shutdown();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index f18f6226b..8555691c0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -16,11 +16,9 @@
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/lock.h"
20#include "core/memory.h" 19#include "core/memory.h"
21#include "core/memory_setup.h" 20#include "core/memory_setup.h"
22#include "video_core/gpu.h" 21#include "video_core/gpu.h"
23#include "video_core/renderer_base.h"
24 22
25namespace Memory { 23namespace Memory {
26 24
diff --git a/src/core/memory.h b/src/core/memory.h
index 04e2c5f1d..09008e1dd 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -8,10 +8,6 @@
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10 10
11namespace Common {
12struct PageTable;
13}
14
15namespace Kernel { 11namespace Kernel {
16class Process; 12class Process;
17} 13}
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 774022569..5d4c3e6ea 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -2,8 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <ctime>
5#include <fstream> 6#include <fstream>
7
8#include <fmt/format.h>
9#include <fmt/time.h>
6#include <json.hpp> 10#include <json.hpp>
11
7#include "common/file_util.h" 12#include "common/file_util.h"
8#include "common/hex_util.h" 13#include "common/hex_util.h"
9#include "common/scm_rev.h" 14#include "common/scm_rev.h"
@@ -14,7 +19,6 @@
14#include "core/hle/result.h" 19#include "core/hle/result.h"
15#include "core/reporter.h" 20#include "core/reporter.h"
16#include "core/settings.h" 21#include "core/settings.h"
17#include "fmt/time.h"
18 22
19namespace { 23namespace {
20 24
@@ -30,9 +34,11 @@ std::string GetTimestamp() {
30 34
31using namespace nlohmann; 35using namespace nlohmann;
32 36
33void SaveToFile(const json& json, const std::string& filename) { 37void SaveToFile(json json, const std::string& filename) {
34 if (!FileUtil::CreateFullPath(filename)) 38 if (!FileUtil::CreateFullPath(filename)) {
35 LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename); 39 LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename);
40 return;
41 }
36 42
37 std::ofstream file( 43 std::ofstream file(
38 FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault)); 44 FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault));
@@ -61,8 +67,11 @@ json GetReportCommonData(u64 title_id, ResultCode result, const std::string& tim
61 {"result_description", fmt::format("{:08X}", result.description.Value())}, 67 {"result_description", fmt::format("{:08X}", result.description.Value())},
62 {"timestamp", timestamp}, 68 {"timestamp", timestamp},
63 }; 69 };
64 if (user_id.has_value()) 70
71 if (user_id.has_value()) {
65 out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]); 72 out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]);
73 }
74
66 return out; 75 return out;
67} 76}
68 77
@@ -171,14 +180,14 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {
171 out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC()); 180 out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC());
172 out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX()); 181 out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX());
173 182
174 return std::move(out); 183 return out;
175} 184}
176 185
177} // Anonymous namespace 186} // Anonymous namespace
178 187
179namespace Core { 188namespace Core {
180 189
181Reporter::Reporter(Core::System& system) : system(system) {} 190Reporter::Reporter(System& system) : system(system) {}
182 191
183Reporter::~Reporter() = default; 192Reporter::~Reporter() = default;
184 193
@@ -187,8 +196,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u
187 const std::array<u64, 31>& registers, 196 const std::array<u64, 31>& registers,
188 const std::array<u64, 32>& backtrace, u32 backtrace_size, 197 const std::array<u64, 32>& backtrace, u32 backtrace_size,
189 const std::string& arch, u32 unk10) const { 198 const std::string& arch, u32 unk10) const {
190 if (!IsReportingEnabled()) 199 if (!IsReportingEnabled()) {
191 return; 200 return;
201 }
192 202
193 const auto timestamp = GetTimestamp(); 203 const auto timestamp = GetTimestamp();
194 json out; 204 json out;
@@ -212,8 +222,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u
212 222
213void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, 223void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,
214 std::optional<std::vector<u8>> resolved_buffer) const { 224 std::optional<std::vector<u8>> resolved_buffer) const {
215 if (!IsReportingEnabled()) 225 if (!IsReportingEnabled()) {
216 return; 226 return;
227 }
217 228
218 const auto timestamp = GetTimestamp(); 229 const auto timestamp = GetTimestamp();
219 const auto title_id = system.CurrentProcess()->GetTitleID(); 230 const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -238,8 +249,9 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64
238void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, 249void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
239 const std::string& name, 250 const std::string& name,
240 const std::string& service_name) const { 251 const std::string& service_name) const {
241 if (!IsReportingEnabled()) 252 if (!IsReportingEnabled()) {
242 return; 253 return;
254 }
243 255
244 const auto timestamp = GetTimestamp(); 256 const auto timestamp = GetTimestamp();
245 const auto title_id = system.CurrentProcess()->GetTitleID(); 257 const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -259,8 +271,9 @@ void Reporter::SaveUnimplementedAppletReport(
259 u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color, 271 u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color,
260 bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel, 272 bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel,
261 std::vector<std::vector<u8>> interactive_channel) const { 273 std::vector<std::vector<u8>> interactive_channel) const {
262 if (!IsReportingEnabled()) 274 if (!IsReportingEnabled()) {
263 return; 275 return;
276 }
264 277
265 const auto timestamp = GetTimestamp(); 278 const auto timestamp = GetTimestamp();
266 const auto title_id = system.CurrentProcess()->GetTitleID(); 279 const auto title_id = system.CurrentProcess()->GetTitleID();
@@ -293,8 +306,9 @@ void Reporter::SaveUnimplementedAppletReport(
293 306
294void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vector<u8>> data, 307void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vector<u8>> data,
295 std::optional<u128> user_id) const { 308 std::optional<u128> user_id) const {
296 if (!IsReportingEnabled()) 309 if (!IsReportingEnabled()) {
297 return; 310 return;
311 }
298 312
299 const auto timestamp = GetTimestamp(); 313 const auto timestamp = GetTimestamp();
300 json out; 314 json out;
@@ -316,8 +330,9 @@ void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vec
316void Reporter::SaveErrorReport(u64 title_id, ResultCode result, 330void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
317 std::optional<std::string> custom_text_main, 331 std::optional<std::string> custom_text_main,
318 std::optional<std::string> custom_text_detail) const { 332 std::optional<std::string> custom_text_detail) const {
319 if (!IsReportingEnabled()) 333 if (!IsReportingEnabled()) {
320 return; 334 return;
335 }
321 336
322 const auto timestamp = GetTimestamp(); 337 const auto timestamp = GetTimestamp();
323 json out; 338 json out;
@@ -335,12 +350,31 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
335 SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); 350 SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
336} 351}
337 352
338void Reporter::SaveUserReport() const { 353void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
354 std::string log_message) const {
339 if (!IsReportingEnabled()) 355 if (!IsReportingEnabled())
340 return; 356 return;
341 357
342 const auto timestamp = GetTimestamp(); 358 const auto timestamp = GetTimestamp();
343 const auto title_id = system.CurrentProcess()->GetTitleID(); 359 const auto title_id = system.CurrentProcess()->GetTitleID();
360 json out;
361
362 out["yuzu_version"] = GetYuzuVersionData();
363 out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp);
364
365 out["log_mode"] = fmt::format("{:08X}", static_cast<u32>(log_mode));
366 out["log_message"] = std::move(log_message);
367
368 SaveToFile(std::move(out), GetPath("filesystem_access_report", title_id, timestamp));
369}
370
371void Reporter::SaveUserReport() const {
372 if (!IsReportingEnabled()) {
373 return;
374 }
375
376 const auto timestamp = GetTimestamp();
377 const auto title_id = system.CurrentProcess()->GetTitleID();
344 378
345 SaveToFile(GetFullDataAuto(timestamp, title_id, system), 379 SaveToFile(GetFullDataAuto(timestamp, title_id, system),
346 GetPath("user_report", title_id, timestamp)); 380 GetPath("user_report", title_id, timestamp));
diff --git a/src/core/reporter.h b/src/core/reporter.h
index 3de19c0f7..44256de50 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <optional> 8#include <optional>
9#include <string>
8#include <vector> 10#include <vector>
9#include "common/common_types.h" 11#include "common/common_types.h"
10 12
@@ -14,11 +16,17 @@ namespace Kernel {
14class HLERequestContext; 16class HLERequestContext;
15} // namespace Kernel 17} // namespace Kernel
16 18
19namespace Service::FileSystem {
20enum class LogMode : u32;
21}
22
17namespace Core { 23namespace Core {
18 24
25class System;
26
19class Reporter { 27class Reporter {
20public: 28public:
21 explicit Reporter(Core::System& system); 29 explicit Reporter(System& system);
22 ~Reporter(); 30 ~Reporter();
23 31
24 void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, 32 void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp,
@@ -45,12 +53,15 @@ public:
45 std::optional<std::string> custom_text_main = {}, 53 std::optional<std::string> custom_text_main = {},
46 std::optional<std::string> custom_text_detail = {}) const; 54 std::optional<std::string> custom_text_detail = {}) const;
47 55
56 void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
57 std::string log_message) const;
58
48 void SaveUserReport() const; 59 void SaveUserReport() const;
49 60
50private: 61private:
51 bool IsReportingEnabled() const; 62 bool IsReportingEnabled() const;
52 63
53 Core::System& system; 64 System& system;
54}; 65};
55 66
56} // namespace Core 67} // namespace Core
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 63aa59690..0dd1632ac 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -85,7 +85,6 @@ void LogSettings() {
85 LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0)); 85 LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));
86 LogSetting("System_CurrentUser", Settings::values.current_user); 86 LogSetting("System_CurrentUser", Settings::values.current_user);
87 LogSetting("System_LanguageIndex", Settings::values.language_index); 87 LogSetting("System_LanguageIndex", Settings::values.language_index);
88 LogSetting("Core_CpuJitEnabled", Settings::values.cpu_jit_enabled);
89 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core); 88 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
90 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); 89 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
91 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); 90 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);
diff --git a/src/core/settings.h b/src/core/settings.h
index acf18d653..6638ce8f9 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -378,7 +378,6 @@ struct Values {
378 std::atomic_bool is_device_reload_pending{true}; 378 std::atomic_bool is_device_reload_pending{true};
379 379
380 // Core 380 // Core
381 bool cpu_jit_enabled;
382 bool use_multi_core; 381 bool use_multi_core;
383 382
384 // Data Storage 383 // Data Storage
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 98f49042a..793d102d3 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -168,7 +168,6 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
168 AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id); 168 AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);
169 AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching", 169 AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
170 Settings::values.enable_audio_stretching); 170 Settings::values.enable_audio_stretching);
171 AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.cpu_jit_enabled);
172 AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore", 171 AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
173 Settings::values.use_multi_core); 172 Settings::values.use_multi_core);
174 AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor", 173 AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor",