diff options
Diffstat (limited to 'src/core')
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 | ||
| 178 | ARM_Dynarmic::~ARM_Dynarmic() = default; | 178 | ARM_Dynarmic::~ARM_Dynarmic() = default; |
| 179 | 179 | ||
| 180 | void 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 | |||
| 185 | void ARM_Dynarmic::UnmapMemory(u64 address, std::size_t size) { | ||
| 186 | inner_unicorn.UnmapMemory(address, size); | ||
| 187 | } | ||
| 188 | |||
| 189 | void ARM_Dynarmic::SetPC(u64 pc) { | 180 | void 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 | ||
| 51 | static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value, | 51 | static 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 | ||
| 60 | ARM_Unicorn::ARM_Unicorn(System& system) : system{system} { | 63 | ARM_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 | ||
| 79 | void 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 | |||
| 84 | void ARM_Unicorn::UnmapMemory(VAddr address, std::size_t size) { | ||
| 85 | CHECKED(uc_mem_unmap(uc, address, size)); | ||
| 86 | } | ||
| 87 | |||
| 88 | void ARM_Unicorn::SetPC(u64 pc) { | 82 | void 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 | ||
| 585 | Service::APM::Controller& System::GetAPMController() { | ||
| 586 | return impl->apm_controller; | ||
| 587 | } | ||
| 588 | |||
| 589 | const Service::APM::Controller& System::GetAPMController() const { | ||
| 590 | return impl->apm_controller; | ||
| 591 | } | ||
| 592 | |||
| 581 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 593 | System::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; | |||
| 43 | class AppletManager; | 43 | class AppletManager; |
| 44 | } // namespace AM::Applets | 44 | } // namespace AM::Applets |
| 45 | 45 | ||
| 46 | namespace APM { | ||
| 47 | class Controller; | ||
| 48 | } | ||
| 49 | |||
| 46 | namespace Glue { | 50 | namespace Glue { |
| 47 | class ARPManager; | 51 | class 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 | |||
| 309 | private: | 317 | private: |
| 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 | ||
| 332 | inline ARM_Interface& CurrentArmInterface() { | ||
| 333 | return System::GetInstance().CurrentArmInterface(); | ||
| 334 | } | ||
| 335 | |||
| 336 | inline Kernel::Process* CurrentProcess() { | 340 | inline 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() { | |||
| 53 | Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, | 53 | Cpu::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 | |||
| 70 | Cpu::~Cpu() = default; | 66 | Cpu::~Cpu() = default; |
| 71 | 67 | ||
| 72 | std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { | 68 | std::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 | ||
| 84 | void Cpu::RunLoop(bool tight_loop) { | 77 | void 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 | ||
| 97 | u32 ProgramMetadata::GetSystemResourceSize() const { | ||
| 98 | return npdm_header.system_resource_size; | ||
| 99 | } | ||
| 100 | |||
| 97 | const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { | 101 | const 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 | ||
| 132 | u64 Process::GetTotalPhysicalMemoryAvailableWithoutMmHeap() const { | 132 | u64 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 | ||
| 138 | u64 Process::GetTotalPhysicalMemoryUsed() const { | 136 | u64 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 | ||
| 142 | u64 Process::GetTotalPhysicalMemoryUsedWithoutMmHeap() const { | 141 | u64 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 | ||
| 148 | void Process::RegisterThread(const Thread* thread) { | 145 | void 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 | ||
| 188 | void Process::Run(s32 main_thread_priority, u64 stack_size) { | 186 | void 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 | ||
| 323 | void 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 | ||
| 960 | static 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 | ||
| 1000 | static 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 |
| 950 | static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { | 1040 | static 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) |
| 1648 | static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, s32 value, | 1738 | static 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) |
| 1671 | static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, | 1761 | static 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 | ||
| 35 | template <ResultCode func(Core::System&, u64, u64)> | ||
| 36 | void SvcWrap(Core::System& system) { | ||
| 37 | FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw); | ||
| 38 | } | ||
| 39 | |||
| 35 | template <ResultCode func(Core::System&, u32)> | 40 | template <ResultCode func(Core::System&, u32)> |
| 36 | void SvcWrap(Core::System& system) { | 41 | void 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 { | |||
| 100 | ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | 105 | ResultVal<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 | ||
| 297 | ResultCode 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 | |||
| 382 | ResultCode 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 | |||
| 311 | ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { | 457 | ResultCode 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) { | |||
| 588 | VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { | 734 | VMManager::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 | ||
| 753 | void 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 | |||
| 607 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | 785 | void 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) { | |||
| 625 | void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) { | 803 | void 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 | ||
| 959 | ResultVal<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 | |||
| 994 | ResultVal<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 | |||
| 770 | u64 VMManager::GetTotalPhysicalMemoryAvailable() const { | 1037 | u64 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 | ||
| 882 | VAddr VMManager::GetNewMapRegionBaseAddress() const { | 1149 | VAddr VMManager::GetStackRegionBaseAddress() const { |
| 883 | return new_map_region_base; | 1150 | return stack_region_base; |
| 884 | } | 1151 | } |
| 885 | 1152 | ||
| 886 | VAddr VMManager::GetNewMapRegionEndAddress() const { | 1153 | VAddr VMManager::GetStackRegionEndAddress() const { |
| 887 | return new_map_region_end; | 1154 | return stack_region_end; |
| 888 | } | 1155 | } |
| 889 | 1156 | ||
| 890 | u64 VMManager::GetNewMapRegionSize() const { | 1157 | u64 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 | ||
| 894 | bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const { | 1161 | bool 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 | ||
| 899 | VAddr VMManager::GetTLSIORegionBaseAddress() const { | 1166 | VAddr 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 | ||
| 292 | ISelfController::~ISelfController() = default; | 297 | ISelfController::~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 | ||
| 457 | void 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 | |||
| 477 | void 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 | |||
| 485 | void 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 | |||
| 452 | void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) { | 496 | void 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 | ||
| 511 | ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) | 552 | ICommonStateGetter::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 | ||
| 668 | void 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 | |||
| 626 | IStorage::IStorage(std::vector<u8> buffer) | 678 | IStorage::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 | ||
| 653 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | 705 | void 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 | ||
| 663 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 713 | class 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 | ||
| 146 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | 150 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
| 147 | public: | 151 | public: |
| 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 | ||
| 151 | private: | 156 | private: |
| @@ -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 { | |||
| 12 | Module::Module() = default; | 11 | Module::Module() = default; |
| 13 | Module::~Module() = default; | 12 | Module::~Module() = default; |
| 14 | 13 | ||
| 15 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 14 | void 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 | ||
| 9 | namespace Service::APM { | 9 | namespace Service::APM { |
| 10 | 10 | ||
| 11 | enum class PerformanceMode : u8 { | ||
| 12 | Handheld = 0, | ||
| 13 | Docked = 1, | ||
| 14 | }; | ||
| 15 | |||
| 16 | class Module final { | 11 | class Module final { |
| 17 | public: | 12 | public: |
| 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. |
| 23 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void 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 | |||
| 10 | namespace Service::APM { | ||
| 11 | |||
| 12 | constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION = | ||
| 13 | PerformanceConfiguration::Config7; | ||
| 14 | |||
| 15 | Controller::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 | |||
| 21 | Controller::~Controller() = default; | ||
| 22 | |||
| 23 | void 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 | |||
| 40 | void 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 | |||
| 51 | PerformanceMode Controller::GetCurrentPerformanceMode() { | ||
| 52 | return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; | ||
| 53 | } | ||
| 54 | |||
| 55 | PerformanceConfiguration 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 | |||
| 63 | void 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 | |||
| 10 | namespace Core::Timing { | ||
| 11 | class CoreTiming; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::APM { | ||
| 15 | |||
| 16 | enum 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 | |||
| 35 | enum 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 | |||
| 41 | enum 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. | ||
| 51 | class Controller { | ||
| 52 | public: | ||
| 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 | |||
| 62 | private: | ||
| 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 | ||
| 10 | namespace Service::APM { | 11 | namespace Service::APM { |
| 11 | 12 | ||
| 12 | class ISession final : public ServiceFramework<ISession> { | 13 | class ISession final : public ServiceFramework<ISession> { |
| 13 | public: | 14 | public: |
| 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 | ||
| 22 | private: | 24 | private: |
| 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 | ||
| 62 | APM::APM(std::shared_ptr<Module> apm, const char* name) | 53 | APM::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 | |||
| 73 | void 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 | ||
| 81 | APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | 80 | APM_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 | |||
| 107 | void 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 | |||
| 119 | void 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 | ||
| 9 | namespace Service::APM { | 9 | namespace Service::APM { |
| 10 | 10 | ||
| 11 | class Controller; | ||
| 12 | class Module; | ||
| 13 | |||
| 11 | class APM final : public ServiceFramework<APM> { | 14 | class APM final : public ServiceFramework<APM> { |
| 12 | public: | 15 | public: |
| 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 | ||
| 16 | private: | 19 | private: |
| 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 | ||
| 22 | class APM_Sys final : public ServiceFramework<APM_Sys> { | 27 | class APM_Sys final : public ServiceFramework<APM_Sys> { |
| 23 | public: | 28 | public: |
| 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 | |||
| 27 | private: | 34 | private: |
| 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 | ||
| 26 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | 26 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { |
| 27 | public: | 27 | public: |
| 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 | ||
| 55 | private: | 56 | private: |
| @@ -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 | ||
| 613 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { | 614 | bool 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 | ||
| 475 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { | 475 | void 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. |
| 66 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); | 66 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); |
| 67 | 67 | ||
| 68 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs); | 68 | void 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 | ||
| 30 | namespace Service::FileSystem { | 31 | namespace 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 | ||
| 616 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | 617 | FSP_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 | ||
| 817 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 818 | void 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 | |
| 828 | void 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 | ||
| 834 | void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | 836 | void 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 | ||
| 907 | void 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 | |||
| 920 | void 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 | ||
| 10 | namespace Core { | ||
| 11 | class Reporter; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace FileSys { | 14 | namespace FileSys { |
| 11 | class FileSystemBackend; | 15 | class FileSystemBackend; |
| 12 | } | 16 | } |
| 13 | 17 | ||
| 14 | namespace Service::FileSystem { | 18 | namespace Service::FileSystem { |
| 15 | 19 | ||
| 20 | enum class AccessLogVersion : u32 { | ||
| 21 | V7_0_0 = 2, | ||
| 22 | |||
| 23 | Latest = V7_0_0, | ||
| 24 | }; | ||
| 25 | |||
| 26 | enum class LogMode : u32 { | ||
| 27 | Off, | ||
| 28 | Log, | ||
| 29 | RedirectToSdCard, | ||
| 30 | LogToSdCard = Log | RedirectToSdCard, | ||
| 31 | }; | ||
| 32 | |||
| 16 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { | 33 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { |
| 17 | public: | 34 | public: |
| 18 | explicit FSP_SRV(); | 35 | explicit FSP_SRV(const Core::Reporter& reporter); |
| 19 | ~FSP_SRV() override; | 36 | ~FSP_SRV() override; |
| 20 | 37 | ||
| 21 | private: | 38 | private: |
| @@ -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 | ||
| 101 | private: | 101 | private: |
| 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 | ||
| 117 | class INotificationService final : public ServiceFramework<INotificationService> { | 150 | class 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 | ||
| 551 | void 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 | |||
| 557 | void Controller_NPad::StopLRAssignmentMode() { | ||
| 558 | is_in_lr_assignment_mode = false; | ||
| 559 | } | ||
| 560 | |||
| 561 | bool 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 | |||
| 551 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) { | 582 | bool 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 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | constexpr 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 | ||
| 737 | void 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 | |||
| 749 | void 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 | |||
| 761 | void 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 | |||
| 736 | class HidDbg final : public ServiceFramework<HidDbg> { | 780 | class HidDbg final : public ServiceFramework<HidDbg> { |
| 737 | public: | 781 | public: |
| 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 | ||
| 9 | namespace Service::PM { | 11 | namespace Service::PM { |
| 10 | 12 | ||
| 13 | namespace { | ||
| 14 | |||
| 15 | constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; | ||
| 16 | |||
| 17 | constexpr u64 NO_PROCESS_FOUND_PID{0}; | ||
| 18 | |||
| 19 | std::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 | |||
| 31 | void 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 | |||
| 11 | class BootMode final : public ServiceFramework<BootMode> { | 44 | class BootMode final : public ServiceFramework<BootMode> { |
| 12 | public: | 45 | public: |
| 13 | explicit BootMode() : ServiceFramework{"pm:bm"} { | 46 | explicit BootMode() : ServiceFramework{"pm:bm"} { |
| @@ -41,14 +74,15 @@ private: | |||
| 41 | 74 | ||
| 42 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 75 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 43 | public: | 76 | public: |
| 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 | |||
| 94 | private: | ||
| 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 | ||
| 61 | class Info final : public ServiceFramework<Info> { | 125 | class Info final : public ServiceFramework<Info> { |
| 62 | public: | 126 | public: |
| 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 | |||
| 135 | private: | ||
| 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 | ||
| 71 | class Shell final : public ServiceFramework<Shell> { | 160 | class Shell final : public ServiceFramework<Shell> { |
| 72 | public: | 161 | public: |
| 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 | |||
| 182 | private: | ||
| 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 | ||
| 92 | void InstallInterfaces(SM::ServiceManager& sm) { | 191 | void 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 | ||
| 7 | namespace Service::SM { | 7 | namespace Core { |
| 8 | class ServiceManager; | 8 | class System; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Service::PM { | 11 | namespace 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. |
| 19 | void InstallInterfaces(SM::ServiceManager& service_manager); | 19 | void 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 |
| 198 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, | 198 | void 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 |
| 185 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, | 185 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); |
| 186 | FileSys::VfsFilesystem& vfs); | ||
| 187 | 186 | ||
| 188 | /// Shutdown ServiceManager | 187 | /// Shutdown ServiceManager |
| 189 | void Shutdown(); | 188 | void 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 | ||
| 25 | namespace Memory { | 23 | namespace 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 | ||
| 11 | namespace Common { | ||
| 12 | struct PageTable; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Kernel { | 11 | namespace Kernel { |
| 16 | class Process; | 12 | class 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 | ||
| 19 | namespace { | 23 | namespace { |
| 20 | 24 | ||
| @@ -30,9 +34,11 @@ std::string GetTimestamp() { | |||
| 30 | 34 | ||
| 31 | using namespace nlohmann; | 35 | using namespace nlohmann; |
| 32 | 36 | ||
| 33 | void SaveToFile(const json& json, const std::string& filename) { | 37 | void 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 | ||
| 179 | namespace Core { | 188 | namespace Core { |
| 180 | 189 | ||
| 181 | Reporter::Reporter(Core::System& system) : system(system) {} | 190 | Reporter::Reporter(System& system) : system(system) {} |
| 182 | 191 | ||
| 183 | Reporter::~Reporter() = default; | 192 | Reporter::~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 | ||
| 213 | void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, | 223 | void 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 | |||
| 238 | void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, | 249 | void 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 | ||
| 294 | void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vector<u8>> data, | 307 | void 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 | |||
| 316 | void Reporter::SaveErrorReport(u64 title_id, ResultCode result, | 330 | void 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 | ||
| 338 | void Reporter::SaveUserReport() const { | 353 | void 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 | |||
| 371 | void 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 { | |||
| 14 | class HLERequestContext; | 16 | class HLERequestContext; |
| 15 | } // namespace Kernel | 17 | } // namespace Kernel |
| 16 | 18 | ||
| 19 | namespace Service::FileSystem { | ||
| 20 | enum class LogMode : u32; | ||
| 21 | } | ||
| 22 | |||
| 17 | namespace Core { | 23 | namespace Core { |
| 18 | 24 | ||
| 25 | class System; | ||
| 26 | |||
| 19 | class Reporter { | 27 | class Reporter { |
| 20 | public: | 28 | public: |
| 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 | ||
| 50 | private: | 61 | private: |
| 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", |