diff options
Diffstat (limited to 'src/core')
76 files changed, 1619 insertions, 472 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f4325f0f8..5462decee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -111,6 +111,8 @@ add_library(core STATIC | |||
| 111 | frontend/scope_acquire_window_context.h | 111 | frontend/scope_acquire_window_context.h |
| 112 | gdbstub/gdbstub.cpp | 112 | gdbstub/gdbstub.cpp |
| 113 | gdbstub/gdbstub.h | 113 | gdbstub/gdbstub.h |
| 114 | hardware_interrupt_manager.cpp | ||
| 115 | hardware_interrupt_manager.h | ||
| 114 | hle/ipc.h | 116 | hle/ipc.h |
| 115 | hle/ipc_helpers.h | 117 | hle/ipc_helpers.h |
| 116 | hle/kernel/address_arbiter.cpp | 118 | hle/kernel/address_arbiter.cpp |
| @@ -372,6 +374,7 @@ add_library(core STATIC | |||
| 372 | hle/service/nvdrv/devices/nvmap.h | 374 | hle/service/nvdrv/devices/nvmap.h |
| 373 | hle/service/nvdrv/interface.cpp | 375 | hle/service/nvdrv/interface.cpp |
| 374 | hle/service/nvdrv/interface.h | 376 | hle/service/nvdrv/interface.h |
| 377 | hle/service/nvdrv/nvdata.h | ||
| 375 | hle/service/nvdrv/nvdrv.cpp | 378 | hle/service/nvdrv/nvdrv.cpp |
| 376 | hle/service/nvdrv/nvdrv.h | 379 | hle/service/nvdrv/nvdrv.h |
| 377 | hle/service/nvdrv/nvmemp.cpp | 380 | hle/service/nvdrv/nvmemp.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 4aceee785..20d64f3b0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "core/file_sys/vfs_concat.h" | 19 | #include "core/file_sys/vfs_concat.h" |
| 20 | #include "core/file_sys/vfs_real.h" | 20 | #include "core/file_sys/vfs_real.h" |
| 21 | #include "core/gdbstub/gdbstub.h" | 21 | #include "core/gdbstub/gdbstub.h" |
| 22 | #include "core/hardware_interrupt_manager.h" | ||
| 22 | #include "core/hle/kernel/client_port.h" | 23 | #include "core/hle/kernel/client_port.h" |
| 23 | #include "core/hle/kernel/kernel.h" | 24 | #include "core/hle/kernel/kernel.h" |
| 24 | #include "core/hle/kernel/process.h" | 25 | #include "core/hle/kernel/process.h" |
| @@ -151,7 +152,7 @@ struct System::Impl { | |||
| 151 | if (!renderer->Init()) { | 152 | if (!renderer->Init()) { |
| 152 | return ResultStatus::ErrorVideoCore; | 153 | return ResultStatus::ErrorVideoCore; |
| 153 | } | 154 | } |
| 154 | 155 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); | |
| 155 | gpu_core = VideoCore::CreateGPU(system); | 156 | gpu_core = VideoCore::CreateGPU(system); |
| 156 | 157 | ||
| 157 | is_powered_on = true; | 158 | is_powered_on = true; |
| @@ -298,6 +299,7 @@ struct System::Impl { | |||
| 298 | std::unique_ptr<VideoCore::RendererBase> renderer; | 299 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 299 | std::unique_ptr<Tegra::GPU> gpu_core; | 300 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 300 | std::shared_ptr<Tegra::DebugContext> debug_context; | 301 | std::shared_ptr<Tegra::DebugContext> debug_context; |
| 302 | std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; | ||
| 301 | CpuCoreManager cpu_core_manager; | 303 | CpuCoreManager cpu_core_manager; |
| 302 | bool is_powered_on = false; | 304 | bool is_powered_on = false; |
| 303 | 305 | ||
| @@ -444,6 +446,14 @@ const Tegra::GPU& System::GPU() const { | |||
| 444 | return *impl->gpu_core; | 446 | return *impl->gpu_core; |
| 445 | } | 447 | } |
| 446 | 448 | ||
| 449 | Core::Hardware::InterruptManager& System::InterruptManager() { | ||
| 450 | return *impl->interrupt_manager; | ||
| 451 | } | ||
| 452 | |||
| 453 | const Core::Hardware::InterruptManager& System::InterruptManager() const { | ||
| 454 | return *impl->interrupt_manager; | ||
| 455 | } | ||
| 456 | |||
| 447 | VideoCore::RendererBase& System::Renderer() { | 457 | VideoCore::RendererBase& System::Renderer() { |
| 448 | return *impl->renderer; | 458 | return *impl->renderer; |
| 449 | } | 459 | } |
diff --git a/src/core/core.h b/src/core/core.h index 11e73278e..0138d93b0 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -70,6 +70,10 @@ namespace Core::Timing { | |||
| 70 | class CoreTiming; | 70 | class CoreTiming; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | namespace Core::Hardware { | ||
| 74 | class InterruptManager; | ||
| 75 | } | ||
| 76 | |||
| 73 | namespace Core { | 77 | namespace Core { |
| 74 | 78 | ||
| 75 | class ARM_Interface; | 79 | class ARM_Interface; |
| @@ -234,6 +238,12 @@ public: | |||
| 234 | /// Provides a constant reference to the core timing instance. | 238 | /// Provides a constant reference to the core timing instance. |
| 235 | const Timing::CoreTiming& CoreTiming() const; | 239 | const Timing::CoreTiming& CoreTiming() const; |
| 236 | 240 | ||
| 241 | /// Provides a reference to the interrupt manager instance. | ||
| 242 | Core::Hardware::InterruptManager& InterruptManager(); | ||
| 243 | |||
| 244 | /// Provides a constant reference to the interrupt manager instance. | ||
| 245 | const Core::Hardware::InterruptManager& InterruptManager() const; | ||
| 246 | |||
| 237 | /// Provides a reference to the kernel instance. | 247 | /// Provides a reference to the kernel instance. |
| 238 | Kernel::KernelCore& Kernel(); | 248 | Kernel::KernelCore& Kernel(); |
| 239 | 249 | ||
| @@ -327,10 +337,6 @@ private: | |||
| 327 | static System s_instance; | 337 | static System s_instance; |
| 328 | }; | 338 | }; |
| 329 | 339 | ||
| 330 | inline ARM_Interface& CurrentArmInterface() { | ||
| 331 | return System::GetInstance().CurrentArmInterface(); | ||
| 332 | } | ||
| 333 | |||
| 334 | inline Kernel::Process* CurrentProcess() { | 340 | inline Kernel::Process* CurrentProcess() { |
| 335 | return System::GetInstance().CurrentProcess(); | 341 | return System::GetInstance().CurrentProcess(); |
| 336 | } | 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/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp new file mode 100644 index 000000000..c2115db2d --- /dev/null +++ b/src/core/hardware_interrupt_manager.cpp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2019 Yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hardware_interrupt_manager.h" | ||
| 8 | #include "core/hle/service/nvdrv/interface.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | namespace Core::Hardware { | ||
| 12 | |||
| 13 | InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { | ||
| 14 | gpu_interrupt_event = | ||
| 15 | system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 message, s64) { | ||
| 16 | auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); | ||
| 17 | const u32 syncpt = static_cast<u32>(message >> 32); | ||
| 18 | const u32 value = static_cast<u32>(message); | ||
| 19 | nvdrv->SignalGPUInterruptSyncpt(syncpt, value); | ||
| 20 | }); | ||
| 21 | } | ||
| 22 | |||
| 23 | InterruptManager::~InterruptManager() = default; | ||
| 24 | |||
| 25 | void InterruptManager::GPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { | ||
| 26 | const u64 msg = (static_cast<u64>(syncpoint_id) << 32ULL) | value; | ||
| 27 | system.CoreTiming().ScheduleEvent(10, gpu_interrupt_event, msg); | ||
| 28 | } | ||
| 29 | |||
| 30 | } // namespace Core::Hardware | ||
diff --git a/src/core/hardware_interrupt_manager.h b/src/core/hardware_interrupt_manager.h new file mode 100644 index 000000000..494db883a --- /dev/null +++ b/src/core/hardware_interrupt_manager.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2019 Yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Core::Timing { | ||
| 14 | struct EventType; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Core::Hardware { | ||
| 18 | |||
| 19 | class InterruptManager { | ||
| 20 | public: | ||
| 21 | explicit InterruptManager(Core::System& system); | ||
| 22 | ~InterruptManager(); | ||
| 23 | |||
| 24 | void GPUInterruptSyncpt(u32 syncpoint_id, u32 value); | ||
| 25 | |||
| 26 | private: | ||
| 27 | Core::System& system; | ||
| 28 | Core::Timing::EventType* gpu_interrupt_event{}; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Core::Hardware | ||
diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h index 879957dcb..d8ad54030 100644 --- a/src/core/hle/kernel/code_set.h +++ b/src/core/hle/kernel/code_set.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/physical_memory.h" | ||
| 11 | 12 | ||
| 12 | namespace Kernel { | 13 | namespace Kernel { |
| 13 | 14 | ||
| @@ -77,7 +78,7 @@ struct CodeSet final { | |||
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | /// The overall data that backs this code set. | 80 | /// The overall data that backs this code set. |
| 80 | std::vector<u8> memory; | 81 | Kernel::PhysicalMemory memory; |
| 81 | 82 | ||
| 82 | /// The segments that comprise this code set. | 83 | /// The segments that comprise this code set. |
| 83 | std::array<Segment, 3> segments; | 84 | std::array<Segment, 3> segments; |
diff --git a/src/core/hle/kernel/physical_memory.h b/src/core/hle/kernel/physical_memory.h new file mode 100644 index 000000000..090565310 --- /dev/null +++ b/src/core/hle/kernel/physical_memory.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/alignment.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | // This encapsulation serves 2 purposes: | ||
| 12 | // - First, to encapsulate host physical memory under a single type and set an | ||
| 13 | // standard for managing it. | ||
| 14 | // - Second to ensure all host backing memory used is aligned to 256 bytes due | ||
| 15 | // to strict alignment restrictions on GPU memory. | ||
| 16 | |||
| 17 | using PhysicalMemory = std::vector<u8, Common::AlignmentAllocator<u8, 256>>; | ||
| 18 | |||
| 19 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index f45ef05f6..e80a12ac3 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 | ||
| @@ -254,7 +247,7 @@ VAddr Process::CreateTLSRegion() { | |||
| 254 | ASSERT(region_address.Succeeded()); | 247 | ASSERT(region_address.Succeeded()); |
| 255 | 248 | ||
| 256 | const auto map_result = vm_manager.MapMemoryBlock( | 249 | const auto map_result = vm_manager.MapMemoryBlock( |
| 257 | *region_address, std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE), 0, | 250 | *region_address, std::make_shared<PhysicalMemory>(Memory::PAGE_SIZE), 0, |
| 258 | Memory::PAGE_SIZE, MemoryState::ThreadLocal); | 251 | Memory::PAGE_SIZE, MemoryState::ThreadLocal); |
| 259 | ASSERT(map_result.Succeeded()); | 252 | ASSERT(map_result.Succeeded()); |
| 260 | 253 | ||
| @@ -284,7 +277,7 @@ void Process::FreeTLSRegion(VAddr tls_address) { | |||
| 284 | } | 277 | } |
| 285 | 278 | ||
| 286 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { | 279 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { |
| 287 | const auto memory = std::make_shared<std::vector<u8>>(std::move(module_.memory)); | 280 | const auto memory = std::make_shared<PhysicalMemory>(std::move(module_.memory)); |
| 288 | 281 | ||
| 289 | const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions, | 282 | const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions, |
| 290 | MemoryState memory_state) { | 283 | MemoryState memory_state) { |
| @@ -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<PhysicalMemory>(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/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index f15c5ee36..a815c4eea 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -28,7 +28,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_ | |||
| 28 | shared_memory->other_permissions = other_permissions; | 28 | shared_memory->other_permissions = other_permissions; |
| 29 | 29 | ||
| 30 | if (address == 0) { | 30 | if (address == 0) { |
| 31 | shared_memory->backing_block = std::make_shared<std::vector<u8>>(size); | 31 | shared_memory->backing_block = std::make_shared<Kernel::PhysicalMemory>(size); |
| 32 | shared_memory->backing_block_offset = 0; | 32 | shared_memory->backing_block_offset = 0; |
| 33 | 33 | ||
| 34 | // Refresh the address mappings for the current process. | 34 | // Refresh the address mappings for the current process. |
| @@ -59,8 +59,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_ | |||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | 61 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet( |
| 62 | KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, std::size_t offset, u64 size, | 62 | KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, |
| 63 | MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { | 63 | u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { |
| 64 | SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); | 64 | SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); |
| 65 | 65 | ||
| 66 | shared_memory->owner_process = nullptr; | 66 | shared_memory->owner_process = nullptr; |
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index c2b6155e1..01ca6dcd2 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/object.h" | 12 | #include "core/hle/kernel/object.h" |
| 13 | #include "core/hle/kernel/physical_memory.h" | ||
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 15 | 16 | ||
| @@ -62,12 +63,10 @@ public: | |||
| 62 | * block. | 63 | * block. |
| 63 | * @param name Optional object name, used for debugging purposes. | 64 | * @param name Optional object name, used for debugging purposes. |
| 64 | */ | 65 | */ |
| 65 | static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel, | 66 | static SharedPtr<SharedMemory> CreateForApplet( |
| 66 | std::shared_ptr<std::vector<u8>> heap_block, | 67 | KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, |
| 67 | std::size_t offset, u64 size, | 68 | u64 size, MemoryPermission permissions, MemoryPermission other_permissions, |
| 68 | MemoryPermission permissions, | 69 | std::string name = "Unknown Applet"); |
| 69 | MemoryPermission other_permissions, | ||
| 70 | std::string name = "Unknown Applet"); | ||
| 71 | 70 | ||
| 72 | std::string GetTypeName() const override { | 71 | std::string GetTypeName() const override { |
| 73 | return "SharedMemory"; | 72 | return "SharedMemory"; |
| @@ -135,7 +134,7 @@ private: | |||
| 135 | ~SharedMemory() override; | 134 | ~SharedMemory() override; |
| 136 | 135 | ||
| 137 | /// Backing memory for this shared memory block. | 136 | /// Backing memory for this shared memory block. |
| 138 | std::shared_ptr<std::vector<u8>> backing_block; | 137 | std::shared_ptr<PhysicalMemory> backing_block; |
| 139 | /// Offset into the backing block for this shared memory. | 138 | /// Offset into the backing block for this shared memory. |
| 140 | std::size_t backing_block_offset = 0; | 139 | std::size_t backing_block_offset = 0; |
| 141 | /// Size of the memory block. Page-aligned. | 140 | /// Size of the memory block. Page-aligned. |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 332573a95..1fd1a732a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -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 |
| @@ -729,16 +736,16 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 729 | StackRegionBaseAddr = 14, | 736 | StackRegionBaseAddr = 14, |
| 730 | StackRegionSize = 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); |
| @@ -756,12 +763,12 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 756 | case GetInfoType::StackRegionSize: | 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 | } |
| @@ -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/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 26c4e5e67..1113c815e 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp | |||
| @@ -47,7 +47,7 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p | |||
| 47 | return ERR_INVALID_STATE; | 47 | return ERR_INVALID_STATE; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | backing_block = std::make_shared<std::vector<u8>>(size); | 50 | backing_block = std::make_shared<PhysicalMemory>(size); |
| 51 | 51 | ||
| 52 | const auto map_state = owner_permissions == MemoryPermission::None | 52 | const auto map_state = owner_permissions == MemoryPermission::None |
| 53 | ? MemoryState::TransferMemoryIsolated | 53 | ? MemoryState::TransferMemoryIsolated |
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index a140b1e2b..6be9dc094 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "core/hle/kernel/object.h" | 10 | #include "core/hle/kernel/object.h" |
| 11 | #include "core/hle/kernel/physical_memory.h" | ||
| 11 | 12 | ||
| 12 | union ResultCode; | 13 | union ResultCode; |
| 13 | 14 | ||
| @@ -82,7 +83,7 @@ private: | |||
| 82 | ~TransferMemory() override; | 83 | ~TransferMemory() override; |
| 83 | 84 | ||
| 84 | /// Memory block backing this instance. | 85 | /// Memory block backing this instance. |
| 85 | std::shared_ptr<std::vector<u8>> backing_block; | 86 | std::shared_ptr<PhysicalMemory> backing_block; |
| 86 | 87 | ||
| 87 | /// The base address for the memory managed by this instance. | 88 | /// The base address for the memory managed by this instance. |
| 88 | VAddr base_address = 0; | 89 | VAddr base_address = 0; |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 501544090..40cea1e7c 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -5,13 +5,15 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <iterator> | 6 | #include <iterator> |
| 7 | #include <utility> | 7 | #include <utility> |
| 8 | #include "common/alignment.h" | ||
| 8 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "common/memory_hook.h" | 11 | #include "common/memory_hook.h" |
| 11 | #include "core/arm/arm_interface.h" | ||
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/file_sys/program_metadata.h" | 13 | #include "core/file_sys/program_metadata.h" |
| 14 | #include "core/hle/kernel/errors.h" | 14 | #include "core/hle/kernel/errors.h" |
| 15 | #include "core/hle/kernel/process.h" | ||
| 16 | #include "core/hle/kernel/resource_limit.h" | ||
| 15 | #include "core/hle/kernel/vm_manager.h" | 17 | #include "core/hle/kernel/vm_manager.h" |
| 16 | #include "core/memory.h" | 18 | #include "core/memory.h" |
| 17 | #include "core/memory_setup.h" | 19 | #include "core/memory_setup.h" |
| @@ -49,10 +51,14 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | |||
| 49 | type != next.type) { | 51 | type != next.type) { |
| 50 | return false; | 52 | return false; |
| 51 | } | 53 | } |
| 52 | if (type == VMAType::AllocatedMemoryBlock && | 54 | if ((attribute & MemoryAttribute::DeviceMapped) == MemoryAttribute::DeviceMapped) { |
| 53 | (backing_block != next.backing_block || offset + size != next.offset)) { | 55 | // TODO: Can device mapped memory be merged sanely? |
| 56 | // Not merging it may cause inaccuracies versus hardware when memory layout is queried. | ||
| 54 | return false; | 57 | return false; |
| 55 | } | 58 | } |
| 59 | if (type == VMAType::AllocatedMemoryBlock) { | ||
| 60 | return true; | ||
| 61 | } | ||
| 56 | if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { | 62 | if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { |
| 57 | return false; | 63 | return false; |
| 58 | } | 64 | } |
| @@ -98,9 +104,9 @@ bool VMManager::IsValidHandle(VMAHandle handle) const { | |||
| 98 | } | 104 | } |
| 99 | 105 | ||
| 100 | ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | 106 | ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, |
| 101 | std::shared_ptr<std::vector<u8>> block, | 107 | std::shared_ptr<PhysicalMemory> block, |
| 102 | std::size_t offset, u64 size, | 108 | std::size_t offset, u64 size, |
| 103 | MemoryState state) { | 109 | MemoryState state, VMAPermission perm) { |
| 104 | ASSERT(block != nullptr); | 110 | ASSERT(block != nullptr); |
| 105 | ASSERT(offset + size <= block->size()); | 111 | ASSERT(offset + size <= block->size()); |
| 106 | 112 | ||
| @@ -109,17 +115,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | |||
| 109 | VirtualMemoryArea& final_vma = vma_handle->second; | 115 | VirtualMemoryArea& final_vma = vma_handle->second; |
| 110 | ASSERT(final_vma.size == size); | 116 | ASSERT(final_vma.size == size); |
| 111 | 117 | ||
| 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; | 118 | final_vma.type = VMAType::AllocatedMemoryBlock; |
| 122 | final_vma.permissions = VMAPermission::ReadWrite; | 119 | final_vma.permissions = perm; |
| 123 | final_vma.state = state; | 120 | final_vma.state = state; |
| 124 | final_vma.backing_block = std::move(block); | 121 | final_vma.backing_block = std::move(block); |
| 125 | final_vma.offset = offset; | 122 | final_vma.offset = offset; |
| @@ -137,11 +134,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me | |||
| 137 | VirtualMemoryArea& final_vma = vma_handle->second; | 134 | VirtualMemoryArea& final_vma = vma_handle->second; |
| 138 | ASSERT(final_vma.size == size); | 135 | ASSERT(final_vma.size == size); |
| 139 | 136 | ||
| 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; | 137 | final_vma.type = VMAType::BackingMemory; |
| 146 | final_vma.permissions = VMAPermission::ReadWrite; | 138 | final_vma.permissions = VMAPermission::ReadWrite; |
| 147 | final_vma.state = state; | 139 | final_vma.state = state; |
| @@ -230,11 +222,6 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) { | |||
| 230 | 222 | ||
| 231 | ASSERT(FindVMA(target)->second.size >= size); | 223 | ASSERT(FindVMA(target)->second.size >= size); |
| 232 | 224 | ||
| 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; | 225 | return RESULT_SUCCESS; |
| 239 | } | 226 | } |
| 240 | 227 | ||
| @@ -274,7 +261,7 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { | |||
| 274 | 261 | ||
| 275 | if (heap_memory == nullptr) { | 262 | if (heap_memory == nullptr) { |
| 276 | // Initialize heap | 263 | // Initialize heap |
| 277 | heap_memory = std::make_shared<std::vector<u8>>(size); | 264 | heap_memory = std::make_shared<PhysicalMemory>(size); |
| 278 | heap_end = heap_region_base + size; | 265 | heap_end = heap_region_base + size; |
| 279 | } else { | 266 | } else { |
| 280 | UnmapRange(heap_region_base, GetCurrentHeapSize()); | 267 | UnmapRange(heap_region_base, GetCurrentHeapSize()); |
| @@ -308,6 +295,166 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { | |||
| 308 | return MakeResult<VAddr>(heap_region_base); | 295 | return MakeResult<VAddr>(heap_region_base); |
| 309 | } | 296 | } |
| 310 | 297 | ||
| 298 | ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { | ||
| 299 | const auto end_addr = target + size; | ||
| 300 | const auto last_addr = end_addr - 1; | ||
| 301 | VAddr cur_addr = target; | ||
| 302 | |||
| 303 | ResultCode result = RESULT_SUCCESS; | ||
| 304 | |||
| 305 | // Check how much memory we've already mapped. | ||
| 306 | const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size); | ||
| 307 | if (mapped_size_result.Failed()) { | ||
| 308 | return mapped_size_result.Code(); | ||
| 309 | } | ||
| 310 | |||
| 311 | // If we've already mapped the desired amount, return early. | ||
| 312 | const std::size_t mapped_size = *mapped_size_result; | ||
| 313 | if (mapped_size == size) { | ||
| 314 | return RESULT_SUCCESS; | ||
| 315 | } | ||
| 316 | |||
| 317 | // Check that we can map the memory we want. | ||
| 318 | const auto res_limit = system.CurrentProcess()->GetResourceLimit(); | ||
| 319 | const u64 physmem_remaining = res_limit->GetMaxResourceValue(ResourceType::PhysicalMemory) - | ||
| 320 | res_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory); | ||
| 321 | if (physmem_remaining < (size - mapped_size)) { | ||
| 322 | return ERR_RESOURCE_LIMIT_EXCEEDED; | ||
| 323 | } | ||
| 324 | |||
| 325 | // Keep track of the memory regions we unmap. | ||
| 326 | std::vector<std::pair<u64, u64>> mapped_regions; | ||
| 327 | |||
| 328 | // Iterate, trying to map memory. | ||
| 329 | { | ||
| 330 | cur_addr = target; | ||
| 331 | |||
| 332 | auto iter = FindVMA(target); | ||
| 333 | ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); | ||
| 334 | |||
| 335 | while (true) { | ||
| 336 | const auto& vma = iter->second; | ||
| 337 | const auto vma_start = vma.base; | ||
| 338 | const auto vma_end = vma_start + vma.size; | ||
| 339 | const auto vma_last = vma_end - 1; | ||
| 340 | |||
| 341 | // Map the memory block | ||
| 342 | const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr); | ||
| 343 | if (vma.state == MemoryState::Unmapped) { | ||
| 344 | const auto map_res = | ||
| 345 | MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size, 0), 0, | ||
| 346 | map_size, MemoryState::Heap, VMAPermission::ReadWrite); | ||
| 347 | result = map_res.Code(); | ||
| 348 | if (result.IsError()) { | ||
| 349 | break; | ||
| 350 | } | ||
| 351 | |||
| 352 | mapped_regions.emplace_back(cur_addr, map_size); | ||
| 353 | } | ||
| 354 | |||
| 355 | // Break once we hit the end of the range. | ||
| 356 | if (last_addr <= vma_last) { | ||
| 357 | break; | ||
| 358 | } | ||
| 359 | |||
| 360 | // Advance to the next block. | ||
| 361 | cur_addr = vma_end; | ||
| 362 | iter = FindVMA(cur_addr); | ||
| 363 | ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | // If we failed, unmap memory. | ||
| 368 | if (result.IsError()) { | ||
| 369 | for (const auto [unmap_address, unmap_size] : mapped_regions) { | ||
| 370 | ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(), | ||
| 371 | "MapPhysicalMemory un-map on error"); | ||
| 372 | } | ||
| 373 | |||
| 374 | return result; | ||
| 375 | } | ||
| 376 | |||
| 377 | // Update amount of mapped physical memory. | ||
| 378 | physical_memory_mapped += size - mapped_size; | ||
| 379 | |||
| 380 | return RESULT_SUCCESS; | ||
| 381 | } | ||
| 382 | |||
| 383 | ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { | ||
| 384 | const auto end_addr = target + size; | ||
| 385 | const auto last_addr = end_addr - 1; | ||
| 386 | VAddr cur_addr = target; | ||
| 387 | |||
| 388 | ResultCode result = RESULT_SUCCESS; | ||
| 389 | |||
| 390 | // Check how much memory is currently mapped. | ||
| 391 | const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size); | ||
| 392 | if (mapped_size_result.Failed()) { | ||
| 393 | return mapped_size_result.Code(); | ||
| 394 | } | ||
| 395 | |||
| 396 | // If we've already unmapped all the memory, return early. | ||
| 397 | const std::size_t mapped_size = *mapped_size_result; | ||
| 398 | if (mapped_size == 0) { | ||
| 399 | return RESULT_SUCCESS; | ||
| 400 | } | ||
| 401 | |||
| 402 | // Keep track of the memory regions we unmap. | ||
| 403 | std::vector<std::pair<u64, u64>> unmapped_regions; | ||
| 404 | |||
| 405 | // Try to unmap regions. | ||
| 406 | { | ||
| 407 | cur_addr = target; | ||
| 408 | |||
| 409 | auto iter = FindVMA(target); | ||
| 410 | ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); | ||
| 411 | |||
| 412 | while (true) { | ||
| 413 | const auto& vma = iter->second; | ||
| 414 | const auto vma_start = vma.base; | ||
| 415 | const auto vma_end = vma_start + vma.size; | ||
| 416 | const auto vma_last = vma_end - 1; | ||
| 417 | |||
| 418 | // Unmap the memory block | ||
| 419 | const auto unmap_size = std::min(end_addr - cur_addr, vma_end - cur_addr); | ||
| 420 | if (vma.state == MemoryState::Heap) { | ||
| 421 | result = UnmapRange(cur_addr, unmap_size); | ||
| 422 | if (result.IsError()) { | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | |||
| 426 | unmapped_regions.emplace_back(cur_addr, unmap_size); | ||
| 427 | } | ||
| 428 | |||
| 429 | // Break once we hit the end of the range. | ||
| 430 | if (last_addr <= vma_last) { | ||
| 431 | break; | ||
| 432 | } | ||
| 433 | |||
| 434 | // Advance to the next block. | ||
| 435 | cur_addr = vma_end; | ||
| 436 | iter = FindVMA(cur_addr); | ||
| 437 | ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | // If we failed, re-map regions. | ||
| 442 | // TODO: Preserve memory contents? | ||
| 443 | if (result.IsError()) { | ||
| 444 | for (const auto [map_address, map_size] : unmapped_regions) { | ||
| 445 | const auto remap_res = | ||
| 446 | MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size, 0), 0, | ||
| 447 | map_size, MemoryState::Heap, VMAPermission::None); | ||
| 448 | ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error"); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | // Update mapped amount | ||
| 453 | physical_memory_mapped -= mapped_size; | ||
| 454 | |||
| 455 | return RESULT_SUCCESS; | ||
| 456 | } | ||
| 457 | |||
| 311 | ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { | 458 | ResultCode VMManager::MapCodeMemory(VAddr dst_address, VAddr src_address, u64 size) { |
| 312 | constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; | 459 | constexpr auto ignore_attribute = MemoryAttribute::LockedForIPC | MemoryAttribute::DeviceMapped; |
| 313 | const auto src_check_result = CheckRangeState( | 460 | const auto src_check_result = CheckRangeState( |
| @@ -447,7 +594,7 @@ ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, Mem | |||
| 447 | ASSERT_MSG(vma_offset + size <= vma->second.size, | 594 | ASSERT_MSG(vma_offset + size <= vma->second.size, |
| 448 | "Shared memory exceeds bounds of mapped block"); | 595 | "Shared memory exceeds bounds of mapped block"); |
| 449 | 596 | ||
| 450 | const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; | 597 | const std::shared_ptr<PhysicalMemory>& backing_block = vma->second.backing_block; |
| 451 | const std::size_t backing_block_offset = vma->second.offset + vma_offset; | 598 | const std::size_t backing_block_offset = vma->second.offset + vma_offset; |
| 452 | 599 | ||
| 453 | CASCADE_RESULT(auto new_vma, | 600 | CASCADE_RESULT(auto new_vma, |
| @@ -455,12 +602,12 @@ ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, Mem | |||
| 455 | // Protect mirror with permissions from old region | 602 | // Protect mirror with permissions from old region |
| 456 | Reprotect(new_vma, vma->second.permissions); | 603 | Reprotect(new_vma, vma->second.permissions); |
| 457 | // Remove permissions from old region | 604 | // Remove permissions from old region |
| 458 | Reprotect(vma, VMAPermission::None); | 605 | ReprotectRange(src_addr, size, VMAPermission::None); |
| 459 | 606 | ||
| 460 | return RESULT_SUCCESS; | 607 | return RESULT_SUCCESS; |
| 461 | } | 608 | } |
| 462 | 609 | ||
| 463 | void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { | 610 | void VMManager::RefreshMemoryBlockMappings(const PhysicalMemory* block) { |
| 464 | // If this ever proves to have a noticeable performance impact, allow users of the function to | 611 | // If this ever proves to have a noticeable performance impact, allow users of the function to |
| 465 | // specify a specific range of addresses to limit the scan to. | 612 | // specify a specific range of addresses to limit the scan to. |
| 466 | for (const auto& p : vma_map) { | 613 | for (const auto& p : vma_map) { |
| @@ -588,14 +735,14 @@ VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) { | |||
| 588 | VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { | 735 | VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { |
| 589 | const VMAIter next_vma = std::next(iter); | 736 | const VMAIter next_vma = std::next(iter); |
| 590 | if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { | 737 | if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { |
| 591 | iter->second.size += next_vma->second.size; | 738 | MergeAdjacentVMA(iter->second, next_vma->second); |
| 592 | vma_map.erase(next_vma); | 739 | vma_map.erase(next_vma); |
| 593 | } | 740 | } |
| 594 | 741 | ||
| 595 | if (iter != vma_map.begin()) { | 742 | if (iter != vma_map.begin()) { |
| 596 | VMAIter prev_vma = std::prev(iter); | 743 | VMAIter prev_vma = std::prev(iter); |
| 597 | if (prev_vma->second.CanBeMergedWith(iter->second)) { | 744 | if (prev_vma->second.CanBeMergedWith(iter->second)) { |
| 598 | prev_vma->second.size += iter->second.size; | 745 | MergeAdjacentVMA(prev_vma->second, iter->second); |
| 599 | vma_map.erase(iter); | 746 | vma_map.erase(iter); |
| 600 | iter = prev_vma; | 747 | iter = prev_vma; |
| 601 | } | 748 | } |
| @@ -604,6 +751,38 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { | |||
| 604 | return iter; | 751 | return iter; |
| 605 | } | 752 | } |
| 606 | 753 | ||
| 754 | void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryArea& right) { | ||
| 755 | ASSERT(left.CanBeMergedWith(right)); | ||
| 756 | |||
| 757 | // Always merge allocated memory blocks, even when they don't share the same backing block. | ||
| 758 | if (left.type == VMAType::AllocatedMemoryBlock && | ||
| 759 | (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { | ||
| 760 | // Check if we can save work. | ||
| 761 | if (left.offset == 0 && left.size == left.backing_block->size()) { | ||
| 762 | // Fast case: left is an entire backing block. | ||
| 763 | left.backing_block->insert(left.backing_block->end(), | ||
| 764 | right.backing_block->begin() + right.offset, | ||
| 765 | right.backing_block->begin() + right.offset + right.size); | ||
| 766 | } else { | ||
| 767 | // Slow case: make a new memory block for left and right. | ||
| 768 | auto new_memory = std::make_shared<PhysicalMemory>(); | ||
| 769 | new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset, | ||
| 770 | left.backing_block->begin() + left.offset + left.size); | ||
| 771 | new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset, | ||
| 772 | right.backing_block->begin() + right.offset + right.size); | ||
| 773 | left.backing_block = new_memory; | ||
| 774 | left.offset = 0; | ||
| 775 | } | ||
| 776 | |||
| 777 | // Page table update is needed, because backing memory changed. | ||
| 778 | left.size += right.size; | ||
| 779 | UpdatePageTableForVMA(left); | ||
| 780 | } else { | ||
| 781 | // Just update the size. | ||
| 782 | left.size += right.size; | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 607 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | 786 | void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { |
| 608 | switch (vma.type) { | 787 | switch (vma.type) { |
| 609 | case VMAType::Free: | 788 | case VMAType::Free: |
| @@ -778,6 +957,84 @@ VMManager::CheckResults VMManager::CheckRangeState(VAddr address, u64 size, Memo | |||
| 778 | std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask)); | 957 | std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask)); |
| 779 | } | 958 | } |
| 780 | 959 | ||
| 960 | ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address, | ||
| 961 | std::size_t size) const { | ||
| 962 | const VAddr end_addr = address + size; | ||
| 963 | const VAddr last_addr = end_addr - 1; | ||
| 964 | std::size_t mapped_size = 0; | ||
| 965 | |||
| 966 | VAddr cur_addr = address; | ||
| 967 | auto iter = FindVMA(cur_addr); | ||
| 968 | ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); | ||
| 969 | |||
| 970 | while (true) { | ||
| 971 | const auto& vma = iter->second; | ||
| 972 | const VAddr vma_start = vma.base; | ||
| 973 | const VAddr vma_end = vma_start + vma.size; | ||
| 974 | const VAddr vma_last = vma_end - 1; | ||
| 975 | |||
| 976 | // Add size if relevant. | ||
| 977 | if (vma.state != MemoryState::Unmapped) { | ||
| 978 | mapped_size += std::min(end_addr - cur_addr, vma_end - cur_addr); | ||
| 979 | } | ||
| 980 | |||
| 981 | // Break once we hit the end of the range. | ||
| 982 | if (last_addr <= vma_last) { | ||
| 983 | break; | ||
| 984 | } | ||
| 985 | |||
| 986 | // Advance to the next block. | ||
| 987 | cur_addr = vma_end; | ||
| 988 | iter = std::next(iter); | ||
| 989 | ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); | ||
| 990 | } | ||
| 991 | |||
| 992 | return MakeResult(mapped_size); | ||
| 993 | } | ||
| 994 | |||
| 995 | ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr address, | ||
| 996 | std::size_t size) const { | ||
| 997 | const VAddr end_addr = address + size; | ||
| 998 | const VAddr last_addr = end_addr - 1; | ||
| 999 | std::size_t mapped_size = 0; | ||
| 1000 | |||
| 1001 | VAddr cur_addr = address; | ||
| 1002 | auto iter = FindVMA(cur_addr); | ||
| 1003 | ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); | ||
| 1004 | |||
| 1005 | while (true) { | ||
| 1006 | const auto& vma = iter->second; | ||
| 1007 | const auto vma_start = vma.base; | ||
| 1008 | const auto vma_end = vma_start + vma.size; | ||
| 1009 | const auto vma_last = vma_end - 1; | ||
| 1010 | const auto state = vma.state; | ||
| 1011 | const auto attr = vma.attribute; | ||
| 1012 | |||
| 1013 | // Memory within region must be free or mapped heap. | ||
| 1014 | if (!((state == MemoryState::Heap && attr == MemoryAttribute::None) || | ||
| 1015 | (state == MemoryState::Unmapped))) { | ||
| 1016 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | // Add size if relevant. | ||
| 1020 | if (state != MemoryState::Unmapped) { | ||
| 1021 | mapped_size += std::min(end_addr - cur_addr, vma_end - cur_addr); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | // Break once we hit the end of the range. | ||
| 1025 | if (last_addr <= vma_last) { | ||
| 1026 | break; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | // Advance to the next block. | ||
| 1030 | cur_addr = vma_end; | ||
| 1031 | iter = std::next(iter); | ||
| 1032 | ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | return MakeResult(mapped_size); | ||
| 1036 | } | ||
| 1037 | |||
| 781 | u64 VMManager::GetTotalPhysicalMemoryAvailable() const { | 1038 | u64 VMManager::GetTotalPhysicalMemoryAvailable() const { |
| 782 | LOG_WARNING(Kernel, "(STUBBED) called"); | 1039 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 783 | return 0xF8000000; | 1040 | return 0xF8000000; |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 9fe6ac3f4..b18cde619 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/memory_hook.h" | 12 | #include "common/memory_hook.h" |
| 13 | #include "common/page_table.h" | 13 | #include "common/page_table.h" |
| 14 | #include "core/hle/kernel/physical_memory.h" | ||
| 14 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 15 | #include "core/memory.h" | 16 | #include "core/memory.h" |
| 16 | 17 | ||
| @@ -290,7 +291,7 @@ struct VirtualMemoryArea { | |||
| 290 | 291 | ||
| 291 | // Settings for type = AllocatedMemoryBlock | 292 | // Settings for type = AllocatedMemoryBlock |
| 292 | /// Memory block backing this VMA. | 293 | /// Memory block backing this VMA. |
| 293 | std::shared_ptr<std::vector<u8>> backing_block = nullptr; | 294 | std::shared_ptr<PhysicalMemory> backing_block = nullptr; |
| 294 | /// Offset into the backing_memory the mapping starts from. | 295 | /// Offset into the backing_memory the mapping starts from. |
| 295 | std::size_t offset = 0; | 296 | std::size_t offset = 0; |
| 296 | 297 | ||
| @@ -348,8 +349,9 @@ public: | |||
| 348 | * @param size Size of the mapping. | 349 | * @param size Size of the mapping. |
| 349 | * @param state MemoryState tag to attach to the VMA. | 350 | * @param state MemoryState tag to attach to the VMA. |
| 350 | */ | 351 | */ |
| 351 | ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, | 352 | ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<PhysicalMemory> block, |
| 352 | std::size_t offset, u64 size, MemoryState state); | 353 | std::size_t offset, u64 size, MemoryState state, |
| 354 | VMAPermission perm = VMAPermission::ReadWrite); | ||
| 353 | 355 | ||
| 354 | /** | 356 | /** |
| 355 | * Maps an unmanaged host memory pointer at a given address. | 357 | * Maps an unmanaged host memory pointer at a given address. |
| @@ -450,6 +452,34 @@ public: | |||
| 450 | /// | 452 | /// |
| 451 | ResultVal<VAddr> SetHeapSize(u64 size); | 453 | ResultVal<VAddr> SetHeapSize(u64 size); |
| 452 | 454 | ||
| 455 | /// Maps memory at a given address. | ||
| 456 | /// | ||
| 457 | /// @param addr The virtual address to map memory at. | ||
| 458 | /// @param size The amount of memory to map. | ||
| 459 | /// | ||
| 460 | /// @note The destination address must lie within the Map region. | ||
| 461 | /// | ||
| 462 | /// @note This function requires that SystemResourceSize be non-zero, | ||
| 463 | /// however, this is just because if it were not then the | ||
| 464 | /// resulting page tables could be exploited on hardware by | ||
| 465 | /// a malicious program. SystemResource usage does not need | ||
| 466 | /// to be explicitly checked or updated here. | ||
| 467 | ResultCode MapPhysicalMemory(VAddr target, u64 size); | ||
| 468 | |||
| 469 | /// Unmaps memory at a given address. | ||
| 470 | /// | ||
| 471 | /// @param addr The virtual address to unmap memory at. | ||
| 472 | /// @param size The amount of memory to unmap. | ||
| 473 | /// | ||
| 474 | /// @note The destination address must lie within the Map region. | ||
| 475 | /// | ||
| 476 | /// @note This function requires that SystemResourceSize be non-zero, | ||
| 477 | /// however, this is just because if it were not then the | ||
| 478 | /// resulting page tables could be exploited on hardware by | ||
| 479 | /// a malicious program. SystemResource usage does not need | ||
| 480 | /// to be explicitly checked or updated here. | ||
| 481 | ResultCode UnmapPhysicalMemory(VAddr target, u64 size); | ||
| 482 | |||
| 453 | /// Maps a region of memory as code memory. | 483 | /// Maps a region of memory as code memory. |
| 454 | /// | 484 | /// |
| 455 | /// @param dst_address The base address of the region to create the aliasing memory region. | 485 | /// @param dst_address The base address of the region to create the aliasing memory region. |
| @@ -518,7 +548,7 @@ public: | |||
| 518 | * Scans all VMAs and updates the page table range of any that use the given vector as backing | 548 | * Scans all VMAs and updates the page table range of any that use the given vector as backing |
| 519 | * memory. This should be called after any operation that causes reallocation of the vector. | 549 | * memory. This should be called after any operation that causes reallocation of the vector. |
| 520 | */ | 550 | */ |
| 521 | void RefreshMemoryBlockMappings(const std::vector<u8>* block); | 551 | void RefreshMemoryBlockMappings(const PhysicalMemory* block); |
| 522 | 552 | ||
| 523 | /// Dumps the address space layout to the log, for debugging | 553 | /// Dumps the address space layout to the log, for debugging |
| 524 | void LogLayout() const; | 554 | void LogLayout() const; |
| @@ -657,6 +687,11 @@ private: | |||
| 657 | */ | 687 | */ |
| 658 | VMAIter MergeAdjacent(VMAIter vma); | 688 | VMAIter MergeAdjacent(VMAIter vma); |
| 659 | 689 | ||
| 690 | /** | ||
| 691 | * Merges two adjacent VMAs. | ||
| 692 | */ | ||
| 693 | void MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryArea& right); | ||
| 694 | |||
| 660 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. | 695 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. |
| 661 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); | 696 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); |
| 662 | 697 | ||
| @@ -701,6 +736,13 @@ private: | |||
| 701 | MemoryAttribute attribute_mask, MemoryAttribute attribute, | 736 | MemoryAttribute attribute_mask, MemoryAttribute attribute, |
| 702 | MemoryAttribute ignore_mask) const; | 737 | MemoryAttribute ignore_mask) const; |
| 703 | 738 | ||
| 739 | /// Gets the amount of memory currently mapped (state != Unmapped) in a range. | ||
| 740 | ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; | ||
| 741 | |||
| 742 | /// Gets the amount of memory unmappable by UnmapPhysicalMemory in a range. | ||
| 743 | ResultVal<std::size_t> SizeOfUnmappablePhysicalMemoryInRange(VAddr address, | ||
| 744 | std::size_t size) const; | ||
| 745 | |||
| 704 | /** | 746 | /** |
| 705 | * A map covering the entirety of the managed address space, keyed by the `base` field of each | 747 | * 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 | 748 | * VMA. It must always be modified by splitting or merging VMAs, so that the invariant |
| @@ -736,12 +778,17 @@ private: | |||
| 736 | // the entire virtual address space extents that bound the allocations, including any holes. | 778 | // the entire virtual address space extents that bound the allocations, including any holes. |
| 737 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous | 779 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous |
| 738 | // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. | 780 | // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. |
| 739 | std::shared_ptr<std::vector<u8>> heap_memory; | 781 | std::shared_ptr<PhysicalMemory> heap_memory; |
| 740 | 782 | ||
| 741 | // The end of the currently allocated heap. This is not an inclusive | 783 | // The end of the currently allocated heap. This is not an inclusive |
| 742 | // end of the range. This is essentially 'base_address + current_size'. | 784 | // end of the range. This is essentially 'base_address + current_size'. |
| 743 | VAddr heap_end = 0; | 785 | VAddr heap_end = 0; |
| 744 | 786 | ||
| 787 | // The current amount of memory mapped via MapPhysicalMemory. | ||
| 788 | // This is used here (and in Nintendo's kernel) only for debugging, and does not impact | ||
| 789 | // any behavior. | ||
| 790 | u64 physical_memory_mapped = 0; | ||
| 791 | |||
| 745 | Core::System& system; | 792 | Core::System& system; |
| 746 | }; | 793 | }; |
| 747 | } // namespace Kernel | 794 | } // namespace Kernel |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9fdcf2965..a192a1f5f 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -266,8 +266,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 266 | {65, nullptr, "ReportUserIsActive"}, | 266 | {65, nullptr, "ReportUserIsActive"}, |
| 267 | {66, nullptr, "GetCurrentIlluminance"}, | 267 | {66, nullptr, "GetCurrentIlluminance"}, |
| 268 | {67, nullptr, "IsIlluminanceAvailable"}, | 268 | {67, nullptr, "IsIlluminanceAvailable"}, |
| 269 | {68, nullptr, "SetAutoSleepDisabled"}, | 269 | {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, |
| 270 | {69, nullptr, "IsAutoSleepDisabled"}, | 270 | {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, |
| 271 | {70, nullptr, "ReportMultimediaError"}, | 271 | {70, nullptr, "ReportMultimediaError"}, |
| 272 | {71, nullptr, "GetCurrentIlluminanceEx"}, | 272 | {71, nullptr, "GetCurrentIlluminanceEx"}, |
| 273 | {80, nullptr, "SetWirelessPriorityMode"}, | 273 | {80, nullptr, "SetWirelessPriorityMode"}, |
| @@ -454,6 +454,34 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c | |||
| 454 | rb.Push<u32>(idle_time_detection_extension); | 454 | rb.Push<u32>(idle_time_detection_extension); |
| 455 | } | 455 | } |
| 456 | 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 | |||
| 457 | void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) { | 485 | void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) { |
| 458 | LOG_DEBUG(Service_AM, "called."); | 486 | LOG_DEBUG(Service_AM, "called."); |
| 459 | 487 | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 14b010164..6cb582483 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -133,6 +133,8 @@ 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); | ||
| 136 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); | 138 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); |
| 137 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); | 139 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); |
| 138 | 140 | ||
| @@ -142,6 +144,7 @@ private: | |||
| 142 | 144 | ||
| 143 | u32 idle_time_detection_extension = 0; | 145 | u32 idle_time_detection_extension = 0; |
| 144 | u64 num_fatal_sections_entered = 0; | 146 | u64 num_fatal_sections_entered = 0; |
| 147 | bool is_auto_sleep_disabled = false; | ||
| 145 | }; | 148 | }; |
| 146 | 149 | ||
| 147 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | 150 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 128df7db5..1781bec83 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp | |||
| @@ -19,16 +19,16 @@ | |||
| 19 | 19 | ||
| 20 | namespace Service::Audio { | 20 | namespace Service::Audio { |
| 21 | 21 | ||
| 22 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 22 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 23 | std::make_shared<AudCtl>()->InstallAsService(service_manager); | 23 | std::make_shared<AudCtl>()->InstallAsService(service_manager); |
| 24 | std::make_shared<AudOutA>()->InstallAsService(service_manager); | 24 | std::make_shared<AudOutA>()->InstallAsService(service_manager); |
| 25 | std::make_shared<AudOutU>()->InstallAsService(service_manager); | 25 | std::make_shared<AudOutU>(system)->InstallAsService(service_manager); |
| 26 | std::make_shared<AudInA>()->InstallAsService(service_manager); | 26 | std::make_shared<AudInA>()->InstallAsService(service_manager); |
| 27 | std::make_shared<AudInU>()->InstallAsService(service_manager); | 27 | std::make_shared<AudInU>()->InstallAsService(service_manager); |
| 28 | std::make_shared<AudRecA>()->InstallAsService(service_manager); | 28 | std::make_shared<AudRecA>()->InstallAsService(service_manager); |
| 29 | std::make_shared<AudRecU>()->InstallAsService(service_manager); | 29 | std::make_shared<AudRecU>()->InstallAsService(service_manager); |
| 30 | std::make_shared<AudRenA>()->InstallAsService(service_manager); | 30 | std::make_shared<AudRenA>()->InstallAsService(service_manager); |
| 31 | std::make_shared<AudRenU>()->InstallAsService(service_manager); | 31 | std::make_shared<AudRenU>(system)->InstallAsService(service_manager); |
| 32 | std::make_shared<CodecCtl>()->InstallAsService(service_manager); | 32 | std::make_shared<CodecCtl>()->InstallAsService(service_manager); |
| 33 | std::make_shared<HwOpus>()->InstallAsService(service_manager); | 33 | std::make_shared<HwOpus>()->InstallAsService(service_manager); |
| 34 | 34 | ||
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h index f5bd3bf5f..b6d13912e 100644 --- a/src/core/hle/service/audio/audio.h +++ b/src/core/hle/service/audio/audio.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::Audio { | 15 | namespace Service::Audio { |
| 12 | 16 | ||
| 13 | /// Registers all Audio services with the specified service manager. | 17 | /// Registers all Audio services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::Audio | 20 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 7db6eb08d..fb84a8f13 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -40,8 +40,8 @@ enum class AudioState : u32 { | |||
| 40 | 40 | ||
| 41 | class IAudioOut final : public ServiceFramework<IAudioOut> { | 41 | class IAudioOut final : public ServiceFramework<IAudioOut> { |
| 42 | public: | 42 | public: |
| 43 | IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, | 43 | IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, |
| 44 | std::string&& unique_name) | 44 | std::string&& device_name, std::string&& unique_name) |
| 45 | : ServiceFramework("IAudioOut"), audio_core(audio_core), | 45 | : ServiceFramework("IAudioOut"), audio_core(audio_core), |
| 46 | device_name(std::move(device_name)), audio_params(audio_params) { | 46 | device_name(std::move(device_name)), audio_params(audio_params) { |
| 47 | // clang-format off | 47 | // clang-format off |
| @@ -65,7 +65,6 @@ public: | |||
| 65 | RegisterHandlers(functions); | 65 | RegisterHandlers(functions); |
| 66 | 66 | ||
| 67 | // This is the event handle used to check if the audio buffer was released | 67 | // This is the event handle used to check if the audio buffer was released |
| 68 | auto& system = Core::System::GetInstance(); | ||
| 69 | buffer_event = Kernel::WritableEvent::CreateEventPair( | 68 | buffer_event = Kernel::WritableEvent::CreateEventPair( |
| 70 | system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased"); | 69 | system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased"); |
| 71 | 70 | ||
| @@ -212,6 +211,22 @@ private: | |||
| 212 | Kernel::EventPair buffer_event; | 211 | Kernel::EventPair buffer_event; |
| 213 | }; | 212 | }; |
| 214 | 213 | ||
| 214 | AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { | ||
| 215 | // clang-format off | ||
| 216 | static const FunctionInfo functions[] = { | ||
| 217 | {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, | ||
| 218 | {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"}, | ||
| 219 | {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, | ||
| 220 | {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}, | ||
| 221 | }; | ||
| 222 | // clang-format on | ||
| 223 | |||
| 224 | RegisterHandlers(functions); | ||
| 225 | audio_core = std::make_unique<AudioCore::AudioOut>(); | ||
| 226 | } | ||
| 227 | |||
| 228 | AudOutU::~AudOutU() = default; | ||
| 229 | |||
| 215 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { | 230 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { |
| 216 | LOG_DEBUG(Service_Audio, "called"); | 231 | LOG_DEBUG(Service_Audio, "called"); |
| 217 | 232 | ||
| @@ -248,7 +263,7 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 248 | 263 | ||
| 249 | std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())}; | 264 | std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())}; |
| 250 | auto audio_out_interface = std::make_shared<IAudioOut>( | 265 | auto audio_out_interface = std::make_shared<IAudioOut>( |
| 251 | params, *audio_core, std::move(device_name), std::move(unique_name)); | 266 | system, params, *audio_core, std::move(device_name), std::move(unique_name)); |
| 252 | 267 | ||
| 253 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | 268 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
| 254 | rb.Push(RESULT_SUCCESS); | 269 | rb.Push(RESULT_SUCCESS); |
| @@ -256,20 +271,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 256 | rb.Push<u32>(params.channel_count); | 271 | rb.Push<u32>(params.channel_count); |
| 257 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); | 272 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); |
| 258 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); | 273 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); |
| 259 | rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); | 274 | rb.PushIpcInterface<IAudioOut>(audio_out_interface); |
| 260 | 275 | ||
| 261 | audio_out_interfaces.push_back(std::move(audio_out_interface)); | 276 | audio_out_interfaces.push_back(std::move(audio_out_interface)); |
| 262 | } | 277 | } |
| 263 | 278 | ||
| 264 | AudOutU::AudOutU() : ServiceFramework("audout:u") { | ||
| 265 | static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, | ||
| 266 | {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"}, | ||
| 267 | {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, | ||
| 268 | {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}}; | ||
| 269 | RegisterHandlers(functions); | ||
| 270 | audio_core = std::make_unique<AudioCore::AudioOut>(); | ||
| 271 | } | ||
| 272 | |||
| 273 | AudOutU::~AudOutU() = default; | ||
| 274 | |||
| 275 | } // namespace Service::Audio | 279 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index aed4c43b2..c9f532ccd 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h | |||
| @@ -11,6 +11,10 @@ namespace AudioCore { | |||
| 11 | class AudioOut; | 11 | class AudioOut; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace Kernel { | 18 | namespace Kernel { |
| 15 | class HLERequestContext; | 19 | class HLERequestContext; |
| 16 | } | 20 | } |
| @@ -21,15 +25,17 @@ class IAudioOut; | |||
| 21 | 25 | ||
| 22 | class AudOutU final : public ServiceFramework<AudOutU> { | 26 | class AudOutU final : public ServiceFramework<AudOutU> { |
| 23 | public: | 27 | public: |
| 24 | AudOutU(); | 28 | explicit AudOutU(Core::System& system_); |
| 25 | ~AudOutU() override; | 29 | ~AudOutU() override; |
| 26 | 30 | ||
| 27 | private: | 31 | private: |
| 32 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); | ||
| 33 | void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); | ||
| 34 | |||
| 28 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; | 35 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; |
| 29 | std::unique_ptr<AudioCore::AudioOut> audio_core; | 36 | std::unique_ptr<AudioCore::AudioOut> audio_core; |
| 30 | 37 | ||
| 31 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); | 38 | Core::System& system; |
| 32 | void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); | ||
| 33 | }; | 39 | }; |
| 34 | 40 | ||
| 35 | } // namespace Service::Audio | 41 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 3711e1ea1..5b0b7f17e 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string_view> | ||
| 8 | 9 | ||
| 9 | #include "audio_core/audio_renderer.h" | 10 | #include "audio_core/audio_renderer.h" |
| 10 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| @@ -25,7 +26,8 @@ namespace Service::Audio { | |||
| 25 | 26 | ||
| 26 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | 27 | class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { |
| 27 | public: | 28 | public: |
| 28 | explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params) | 29 | explicit IAudioRenderer(Core::System& system, AudioCore::AudioRendererParameter audren_params, |
| 30 | const std::size_t instance_number) | ||
| 29 | : ServiceFramework("IAudioRenderer") { | 31 | : ServiceFramework("IAudioRenderer") { |
| 30 | // clang-format off | 32 | // clang-format off |
| 31 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| @@ -45,11 +47,10 @@ public: | |||
| 45 | // clang-format on | 47 | // clang-format on |
| 46 | RegisterHandlers(functions); | 48 | RegisterHandlers(functions); |
| 47 | 49 | ||
| 48 | 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: |
| @@ -159,7 +160,8 @@ private: | |||
| 159 | 160 | ||
| 160 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 161 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
| 161 | public: | 162 | public: |
| 162 | IAudioDevice() : ServiceFramework("IAudioDevice") { | 163 | explicit IAudioDevice(Core::System& system, u32_le revision_num) |
| 164 | : ServiceFramework("IAudioDevice"), revision{revision_num} { | ||
| 163 | static const FunctionInfo functions[] = { | 165 | static const FunctionInfo functions[] = { |
| 164 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, | 166 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, |
| 165 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, | 167 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, |
| @@ -177,7 +179,7 @@ public: | |||
| 177 | }; | 179 | }; |
| 178 | RegisterHandlers(functions); | 180 | RegisterHandlers(functions); |
| 179 | 181 | ||
| 180 | auto& kernel = Core::System::GetInstance().Kernel(); | 182 | auto& kernel = system.Kernel(); |
| 181 | buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | 183 | buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, |
| 182 | "IAudioOutBufferReleasedEvent"); | 184 | "IAudioOutBufferReleasedEvent"); |
| 183 | 185 | ||
| @@ -188,15 +190,47 @@ public: | |||
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | private: | 192 | private: |
| 193 | using AudioDeviceName = std::array<char, 256>; | ||
| 194 | static constexpr std::array<std::string_view, 4> audio_device_names{{ | ||
| 195 | "AudioStereoJackOutput", | ||
| 196 | "AudioBuiltInSpeakerOutput", | ||
| 197 | "AudioTvOutput", | ||
| 198 | "AudioUsbDeviceOutput", | ||
| 199 | }}; | ||
| 200 | enum class DeviceType { | ||
| 201 | AHUBHeadphones, | ||
| 202 | AHUBSpeakers, | ||
| 203 | HDA, | ||
| 204 | USBOutput, | ||
| 205 | }; | ||
| 206 | |||
| 191 | void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { | 207 | void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { |
| 192 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 208 | LOG_DEBUG(Service_Audio, "called"); |
| 193 | 209 | ||
| 194 | constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; | 210 | const bool usb_output_supported = |
| 195 | ctx.WriteBuffer(audio_interface); | 211 | IsFeatureSupported(AudioFeatures::AudioUSBDeviceOutput, revision); |
| 212 | const std::size_t count = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName); | ||
| 213 | |||
| 214 | std::vector<AudioDeviceName> name_buffer; | ||
| 215 | name_buffer.reserve(audio_device_names.size()); | ||
| 216 | |||
| 217 | for (std::size_t i = 0; i < count && i < audio_device_names.size(); i++) { | ||
| 218 | const auto type = static_cast<DeviceType>(i); | ||
| 219 | |||
| 220 | if (!usb_output_supported && type == DeviceType::USBOutput) { | ||
| 221 | continue; | ||
| 222 | } | ||
| 223 | |||
| 224 | const auto& device_name = audio_device_names[i]; | ||
| 225 | auto& entry = name_buffer.emplace_back(); | ||
| 226 | device_name.copy(entry.data(), device_name.size()); | ||
| 227 | } | ||
| 228 | |||
| 229 | ctx.WriteBuffer(name_buffer); | ||
| 196 | 230 | ||
| 197 | IPC::ResponseBuilder rb{ctx, 3}; | 231 | IPC::ResponseBuilder rb{ctx, 3}; |
| 198 | rb.Push(RESULT_SUCCESS); | 232 | rb.Push(RESULT_SUCCESS); |
| 199 | rb.Push<u32>(1); | 233 | rb.Push(static_cast<u32>(name_buffer.size())); |
| 200 | } | 234 | } |
| 201 | 235 | ||
| 202 | void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { | 236 | void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { |
| @@ -215,12 +249,16 @@ private: | |||
| 215 | void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { | 249 | void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { |
| 216 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 250 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 217 | 251 | ||
| 218 | constexpr std::array<char, 12> audio_interface{{"AudioDevice"}}; | 252 | // Currently set to always be TV audio output. |
| 219 | ctx.WriteBuffer(audio_interface); | 253 | const auto& device_name = audio_device_names[2]; |
| 220 | 254 | ||
| 221 | IPC::ResponseBuilder rb{ctx, 3}; | 255 | AudioDeviceName out_device_name{}; |
| 256 | device_name.copy(out_device_name.data(), device_name.size()); | ||
| 257 | |||
| 258 | ctx.WriteBuffer(out_device_name); | ||
| 259 | |||
| 260 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 222 | rb.Push(RESULT_SUCCESS); | 261 | rb.Push(RESULT_SUCCESS); |
| 223 | rb.Push<u32>(1); | ||
| 224 | } | 262 | } |
| 225 | 263 | ||
| 226 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { | 264 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { |
| @@ -249,12 +287,13 @@ private: | |||
| 249 | rb.PushCopyObjects(audio_output_device_switch_event.readable); | 287 | rb.PushCopyObjects(audio_output_device_switch_event.readable); |
| 250 | } | 288 | } |
| 251 | 289 | ||
| 290 | u32_le revision = 0; | ||
| 252 | Kernel::EventPair buffer_event; | 291 | Kernel::EventPair buffer_event; |
| 253 | Kernel::EventPair audio_output_device_switch_event; | 292 | Kernel::EventPair audio_output_device_switch_event; |
| 254 | 293 | ||
| 255 | }; // namespace Audio | 294 | }; // namespace Audio |
| 256 | 295 | ||
| 257 | AudRenU::AudRenU() : ServiceFramework("audren:u") { | 296 | AudRenU::AudRenU(Core::System& system_) : ServiceFramework("audren:u"), system{system_} { |
| 258 | // clang-format off | 297 | // clang-format off |
| 259 | static const FunctionInfo functions[] = { | 298 | static const FunctionInfo functions[] = { |
| 260 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, | 299 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, |
| @@ -327,7 +366,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 327 | }; | 366 | }; |
| 328 | 367 | ||
| 329 | // Calculates the portion of the size related to the mix data (and the sorting thereof). | 368 | // Calculates the portion of the size related to the mix data (and the sorting thereof). |
| 330 | const auto calculate_mix_info_size = [this](const AudioCore::AudioRendererParameter& params) { | 369 | const auto calculate_mix_info_size = [](const AudioCore::AudioRendererParameter& params) { |
| 331 | // The size of the mixing info data structure. | 370 | // The size of the mixing info data structure. |
| 332 | constexpr u64 mix_info_size = 0x940; | 371 | constexpr u64 mix_info_size = 0x940; |
| 333 | 372 | ||
| @@ -399,7 +438,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 399 | 438 | ||
| 400 | // Calculates the part of the size related to the splitter context. | 439 | // Calculates the part of the size related to the splitter context. |
| 401 | const auto calculate_splitter_context_size = | 440 | const auto calculate_splitter_context_size = |
| 402 | [this](const AudioCore::AudioRendererParameter& params) -> u64 { | 441 | [](const AudioCore::AudioRendererParameter& params) -> u64 { |
| 403 | if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { | 442 | if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { |
| 404 | return 0; | 443 | return 0; |
| 405 | } | 444 | } |
| @@ -446,7 +485,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 446 | }; | 485 | }; |
| 447 | 486 | ||
| 448 | // Calculates the part of the size related to performance statistics. | 487 | // Calculates the part of the size related to performance statistics. |
| 449 | const auto calculate_perf_size = [this](const AudioCore::AudioRendererParameter& params) { | 488 | const auto calculate_perf_size = [](const AudioCore::AudioRendererParameter& params) { |
| 450 | // Extra size value appended to the end of the calculation. | 489 | // Extra size value appended to the end of the calculation. |
| 451 | constexpr u64 appended = 128; | 490 | constexpr u64 appended = 128; |
| 452 | 491 | ||
| @@ -473,78 +512,76 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 473 | }; | 512 | }; |
| 474 | 513 | ||
| 475 | // Calculates the part of the size that relates to the audio command buffer. | 514 | // Calculates the part of the size that relates to the audio command buffer. |
| 476 | const auto calculate_command_buffer_size = | 515 | const auto calculate_command_buffer_size = [](const AudioCore::AudioRendererParameter& params) { |
| 477 | [this](const AudioCore::AudioRendererParameter& params) { | 516 | constexpr u64 alignment = (buffer_alignment_size - 1) * 2; |
| 478 | constexpr u64 alignment = (buffer_alignment_size - 1) * 2; | ||
| 479 | 517 | ||
| 480 | if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { | 518 | if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) { |
| 481 | constexpr u64 command_buffer_size = 0x18000; | 519 | constexpr u64 command_buffer_size = 0x18000; |
| 482 | 520 | ||
| 483 | return command_buffer_size + alignment; | 521 | return command_buffer_size + alignment; |
| 484 | } | 522 | } |
| 485 | 523 | ||
| 486 | // When the variadic command buffer is supported, this means | 524 | // When the variadic command buffer is supported, this means |
| 487 | // the command generator for the audio renderer can issue commands | 525 | // the command generator for the audio renderer can issue commands |
| 488 | // that are (as one would expect), variable in size. So what we need to do | 526 | // that are (as one would expect), variable in size. So what we need to do |
| 489 | // is determine the maximum possible size for a few command data structures | 527 | // is determine the maximum possible size for a few command data structures |
| 490 | // then multiply them by the amount of present commands indicated by the given | 528 | // then multiply them by the amount of present commands indicated by the given |
| 491 | // respective audio parameters. | 529 | // respective audio parameters. |
| 492 | 530 | ||
| 493 | constexpr u64 max_biquad_filters = 2; | 531 | constexpr u64 max_biquad_filters = 2; |
| 494 | constexpr u64 max_mix_buffers = 24; | 532 | constexpr u64 max_mix_buffers = 24; |
| 495 | 533 | ||
| 496 | constexpr u64 biquad_filter_command_size = 0x2C; | 534 | constexpr u64 biquad_filter_command_size = 0x2C; |
| 497 | 535 | ||
| 498 | constexpr u64 depop_mix_command_size = 0x24; | 536 | constexpr u64 depop_mix_command_size = 0x24; |
| 499 | constexpr u64 depop_setup_command_size = 0x50; | 537 | constexpr u64 depop_setup_command_size = 0x50; |
| 500 | 538 | ||
| 501 | constexpr u64 effect_command_max_size = 0x540; | 539 | constexpr u64 effect_command_max_size = 0x540; |
| 502 | 540 | ||
| 503 | constexpr u64 mix_command_size = 0x1C; | 541 | constexpr u64 mix_command_size = 0x1C; |
| 504 | constexpr u64 mix_ramp_command_size = 0x24; | 542 | constexpr u64 mix_ramp_command_size = 0x24; |
| 505 | constexpr u64 mix_ramp_grouped_command_size = 0x13C; | 543 | constexpr u64 mix_ramp_grouped_command_size = 0x13C; |
| 506 | 544 | ||
| 507 | constexpr u64 perf_command_size = 0x28; | 545 | constexpr u64 perf_command_size = 0x28; |
| 508 | 546 | ||
| 509 | constexpr u64 sink_command_size = 0x130; | 547 | constexpr u64 sink_command_size = 0x130; |
| 510 | 548 | ||
| 511 | constexpr u64 submix_command_max_size = | 549 | constexpr u64 submix_command_max_size = |
| 512 | depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; | 550 | depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers; |
| 513 | 551 | ||
| 514 | constexpr u64 volume_command_size = 0x1C; | 552 | constexpr u64 volume_command_size = 0x1C; |
| 515 | constexpr u64 volume_ramp_command_size = 0x20; | 553 | constexpr u64 volume_ramp_command_size = 0x20; |
| 516 | 554 | ||
| 517 | constexpr u64 voice_biquad_filter_command_size = | 555 | constexpr u64 voice_biquad_filter_command_size = |
| 518 | biquad_filter_command_size * max_biquad_filters; | 556 | biquad_filter_command_size * max_biquad_filters; |
| 519 | constexpr u64 voice_data_command_size = 0x9C; | 557 | constexpr u64 voice_data_command_size = 0x9C; |
| 520 | const u64 voice_command_max_size = | 558 | const u64 voice_command_max_size = |
| 521 | (params.splitter_count * depop_setup_command_size) + | 559 | (params.splitter_count * depop_setup_command_size) + |
| 522 | (voice_data_command_size + voice_biquad_filter_command_size + | 560 | (voice_data_command_size + voice_biquad_filter_command_size + volume_ramp_command_size + |
| 523 | volume_ramp_command_size + mix_ramp_grouped_command_size); | 561 | mix_ramp_grouped_command_size); |
| 524 | 562 | ||
| 525 | // Now calculate the individual elements that comprise the size and add them together. | 563 | // Now calculate the individual elements that comprise the size and add them together. |
| 526 | const u64 effect_commands_size = params.effect_count * effect_command_max_size; | 564 | const u64 effect_commands_size = params.effect_count * effect_command_max_size; |
| 527 | 565 | ||
| 528 | const u64 final_mix_commands_size = | 566 | const u64 final_mix_commands_size = |
| 529 | depop_mix_command_size + volume_command_size * max_mix_buffers; | 567 | depop_mix_command_size + volume_command_size * max_mix_buffers; |
| 530 | 568 | ||
| 531 | const u64 perf_commands_size = | 569 | const u64 perf_commands_size = |
| 532 | perf_command_size * | 570 | perf_command_size * (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); |
| 533 | (CalculateNumPerformanceEntries(params) + max_perf_detail_entries); | ||
| 534 | 571 | ||
| 535 | const u64 sink_commands_size = params.sink_count * sink_command_size; | 572 | const u64 sink_commands_size = params.sink_count * sink_command_size; |
| 536 | 573 | ||
| 537 | const u64 splitter_commands_size = | 574 | const u64 splitter_commands_size = |
| 538 | params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; | 575 | params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size; |
| 539 | 576 | ||
| 540 | const u64 submix_commands_size = params.submix_count * submix_command_max_size; | 577 | const u64 submix_commands_size = params.submix_count * submix_command_max_size; |
| 541 | 578 | ||
| 542 | const u64 voice_commands_size = params.voice_count * voice_command_max_size; | 579 | const u64 voice_commands_size = params.voice_count * voice_command_max_size; |
| 543 | 580 | ||
| 544 | return effect_commands_size + final_mix_commands_size + perf_commands_size + | 581 | return effect_commands_size + final_mix_commands_size + perf_commands_size + |
| 545 | sink_commands_size + splitter_commands_size + submix_commands_size + | 582 | sink_commands_size + splitter_commands_size + submix_commands_size + |
| 546 | voice_commands_size + alignment; | 583 | voice_commands_size + alignment; |
| 547 | }; | 584 | }; |
| 548 | 585 | ||
| 549 | IPC::RequestParser rp{ctx}; | 586 | IPC::RequestParser rp{ctx}; |
| 550 | const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); | 587 | const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); |
| @@ -577,12 +614,16 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 577 | } | 614 | } |
| 578 | 615 | ||
| 579 | void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { | 616 | void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { |
| 580 | LOG_DEBUG(Service_Audio, "called"); | 617 | IPC::RequestParser rp{ctx}; |
| 618 | const u64 aruid = rp.Pop<u64>(); | ||
| 581 | 619 | ||
| 582 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 620 | LOG_DEBUG(Service_Audio, "called. aruid={:016X}", aruid); |
| 583 | 621 | ||
| 622 | // Revisionless variant of GetAudioDeviceServiceWithRevisionInfo that | ||
| 623 | // always assumes the initial release revision (REV1). | ||
| 624 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 584 | rb.Push(RESULT_SUCCESS); | 625 | rb.Push(RESULT_SUCCESS); |
| 585 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 626 | rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); |
| 586 | } | 627 | } |
| 587 | 628 | ||
| 588 | void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { | 629 | void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { |
| @@ -592,13 +633,19 @@ void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { | |||
| 592 | } | 633 | } |
| 593 | 634 | ||
| 594 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { | 635 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { |
| 595 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 636 | struct Parameters { |
| 637 | u32 revision; | ||
| 638 | u64 aruid; | ||
| 639 | }; | ||
| 596 | 640 | ||
| 597 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 641 | IPC::RequestParser rp{ctx}; |
| 642 | const auto [revision, aruid] = rp.PopRaw<Parameters>(); | ||
| 643 | |||
| 644 | LOG_DEBUG(Service_Audio, "called. revision={:08X}, aruid={:016X}", revision, aruid); | ||
| 598 | 645 | ||
| 646 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 599 | rb.Push(RESULT_SUCCESS); | 647 | rb.Push(RESULT_SUCCESS); |
| 600 | rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different | 648 | rb.PushIpcInterface<IAudioDevice>(system, revision); |
| 601 | // based on the current revision | ||
| 602 | } | 649 | } |
| 603 | 650 | ||
| 604 | void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { | 651 | void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { |
| @@ -607,14 +654,16 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { | |||
| 607 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 654 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 608 | 655 | ||
| 609 | rb.Push(RESULT_SUCCESS); | 656 | rb.Push(RESULT_SUCCESS); |
| 610 | rb.PushIpcInterface<IAudioRenderer>(params); | 657 | rb.PushIpcInterface<IAudioRenderer>(system, params, audren_instance_count++); |
| 611 | } | 658 | } |
| 612 | 659 | ||
| 613 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { | 660 | bool IsFeatureSupported(AudioFeatures feature, u32_le revision) { |
| 614 | // Byte swap | 661 | // Byte swap |
| 615 | const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); | 662 | const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); |
| 616 | 663 | ||
| 617 | switch (feature) { | 664 | switch (feature) { |
| 665 | case AudioFeatures::AudioUSBDeviceOutput: | ||
| 666 | return version_num >= 4U; | ||
| 618 | case AudioFeatures::Splitter: | 667 | case AudioFeatures::Splitter: |
| 619 | return version_num >= 2U; | 668 | return version_num >= 2U; |
| 620 | case AudioFeatures::PerformanceMetricsVersion2: | 669 | case AudioFeatures::PerformanceMetricsVersion2: |
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 1d3c8df61..4e0ccc792 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,7 +18,7 @@ namespace Service::Audio { | |||
| 14 | 18 | ||
| 15 | class AudRenU final : public ServiceFramework<AudRenU> { | 19 | class AudRenU final : public ServiceFramework<AudRenU> { |
| 16 | public: | 20 | public: |
| 17 | explicit AudRenU(); | 21 | explicit AudRenU(Core::System& system_); |
| 18 | ~AudRenU() override; | 22 | ~AudRenU() override; |
| 19 | 23 | ||
| 20 | private: | 24 | private: |
| @@ -26,13 +30,19 @@ private: | |||
| 26 | 30 | ||
| 27 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); | 31 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); |
| 28 | 32 | ||
| 29 | enum class AudioFeatures : u32 { | 33 | std::size_t audren_instance_count = 0; |
| 30 | Splitter, | 34 | Core::System& system; |
| 31 | PerformanceMetricsVersion2, | 35 | }; |
| 32 | VariadicCommandBuffer, | ||
| 33 | }; | ||
| 34 | 36 | ||
| 35 | bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const; | 37 | // Describes a particular audio feature that may be supported in a particular revision. |
| 38 | enum class AudioFeatures : u32 { | ||
| 39 | AudioUSBDeviceOutput, | ||
| 40 | Splitter, | ||
| 41 | PerformanceMetricsVersion2, | ||
| 42 | VariadicCommandBuffer, | ||
| 36 | }; | 43 | }; |
| 37 | 44 | ||
| 45 | // Tests if a particular audio feature is supported with a given audio revision. | ||
| 46 | bool IsFeatureSupported(AudioFeatures feature, u32_le revision); | ||
| 47 | |||
| 38 | } // namespace Service::Audio | 48 | } // namespace Service::Audio |
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/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/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index ad176f89d..2a522136d 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -77,7 +77,7 @@ enum class LoadState : u32 { | |||
| 77 | Done = 1, | 77 | Done = 1, |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, | 80 | static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output, |
| 81 | std::size_t& offset) { | 81 | std::size_t& offset) { |
| 82 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, | 82 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, |
| 83 | "Shared fonts exceeds 17mb!"); | 83 | "Shared fonts exceeds 17mb!"); |
| @@ -94,7 +94,7 @@ static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& ou | |||
| 94 | offset += transformed_font.size() * sizeof(u32); | 94 | offset += transformed_font.size() * sizeof(u32); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& output, | 97 | static void EncryptSharedFont(const std::vector<u8>& input, Kernel::PhysicalMemory& output, |
| 98 | std::size_t& offset) { | 98 | std::size_t& offset) { |
| 99 | ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); | 99 | ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); |
| 100 | const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT; | 100 | const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT; |
| @@ -121,7 +121,7 @@ struct PL_U::Impl { | |||
| 121 | return shared_font_regions.at(index); | 121 | return shared_font_regions.at(index); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | void BuildSharedFontsRawRegions(const std::vector<u8>& input) { | 124 | void BuildSharedFontsRawRegions(const Kernel::PhysicalMemory& input) { |
| 125 | // As we can derive the xor key we can just populate the offsets | 125 | // As we can derive the xor key we can just populate the offsets |
| 126 | // based on the shared memory dump | 126 | // based on the shared memory dump |
| 127 | unsigned cur_offset = 0; | 127 | unsigned cur_offset = 0; |
| @@ -144,7 +144,7 @@ struct PL_U::Impl { | |||
| 144 | Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | 144 | Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; |
| 145 | 145 | ||
| 146 | /// Backing memory for the shared font data | 146 | /// Backing memory for the shared font data |
| 147 | std::shared_ptr<std::vector<u8>> shared_font; | 147 | std::shared_ptr<Kernel::PhysicalMemory> shared_font; |
| 148 | 148 | ||
| 149 | // Automatically populated based on shared_fonts dump or system archives. | 149 | // Automatically populated based on shared_fonts dump or system archives. |
| 150 | std::vector<FontRegion> shared_font_regions; | 150 | std::vector<FontRegion> shared_font_regions; |
| @@ -166,7 +166,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { | |||
| 166 | // Rebuild shared fonts from data ncas | 166 | // Rebuild shared fonts from data ncas |
| 167 | if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), | 167 | if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), |
| 168 | FileSys::ContentRecordType::Data)) { | 168 | FileSys::ContentRecordType::Data)) { |
| 169 | impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); | 169 | impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(SHARED_FONT_MEM_SIZE); |
| 170 | for (auto font : SHARED_FONTS) { | 170 | for (auto font : SHARED_FONTS) { |
| 171 | const auto nca = | 171 | const auto nca = |
| 172 | nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); | 172 | nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); |
| @@ -207,7 +207,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { | |||
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | } else { | 209 | } else { |
| 210 | impl->shared_font = std::make_shared<std::vector<u8>>( | 210 | impl->shared_font = std::make_shared<Kernel::PhysicalMemory>( |
| 211 | SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size | 211 | SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size |
| 212 | 212 | ||
| 213 | const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); | 213 | const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); |
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 4f6042b00..5b8248433 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -8,6 +8,11 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | class System; | ||
| 15 | } | ||
| 11 | 16 | ||
| 12 | namespace Service::Nvidia::Devices { | 17 | namespace Service::Nvidia::Devices { |
| 13 | 18 | ||
| @@ -15,7 +20,7 @@ namespace Service::Nvidia::Devices { | |||
| 15 | /// implement the ioctl interface. | 20 | /// implement the ioctl interface. |
| 16 | class nvdevice { | 21 | class nvdevice { |
| 17 | public: | 22 | public: |
| 18 | nvdevice() = default; | 23 | explicit nvdevice(Core::System& system) : system{system} {}; |
| 19 | virtual ~nvdevice() = default; | 24 | virtual ~nvdevice() = default; |
| 20 | union Ioctl { | 25 | union Ioctl { |
| 21 | u32_le raw; | 26 | u32_le raw; |
| @@ -33,7 +38,11 @@ public: | |||
| 33 | * @param output A buffer where the output data will be written to. | 38 | * @param output A buffer where the output data will be written to. |
| 34 | * @returns The result code of the ioctl. | 39 | * @returns The result code of the ioctl. |
| 35 | */ | 40 | */ |
| 36 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) = 0; | 41 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 42 | IoctlCtrl& ctrl) = 0; | ||
| 43 | |||
| 44 | protected: | ||
| 45 | Core::System& system; | ||
| 37 | }; | 46 | }; |
| 38 | 47 | ||
| 39 | } // namespace Service::Nvidia::Devices | 48 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 20c7c39aa..926a1285d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -13,10 +13,12 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Nvidia::Devices { | 14 | namespace Service::Nvidia::Devices { |
| 15 | 15 | ||
| 16 | nvdisp_disp0::nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} | 16 | nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | ||
| 17 | nvdisp_disp0 ::~nvdisp_disp0() = default; | 18 | nvdisp_disp0 ::~nvdisp_disp0() = default; |
| 18 | 19 | ||
| 19 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 20 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 21 | IoctlCtrl& ctrl) { | ||
| 20 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 22 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); |
| 21 | return 0; | 23 | return 0; |
| 22 | } | 24 | } |
| @@ -34,9 +36,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 | |||
| 34 | addr, offset, width, height, stride, static_cast<PixelFormat>(format), | 36 | addr, offset, width, height, stride, static_cast<PixelFormat>(format), |
| 35 | transform, crop_rect}; | 37 | transform, crop_rect}; |
| 36 | 38 | ||
| 37 | auto& instance = Core::System::GetInstance(); | 39 | system.GetPerfStats().EndGameFrame(); |
| 38 | instance.GetPerfStats().EndGameFrame(); | 40 | system.GPU().SwapBuffers(&framebuffer); |
| 39 | instance.GPU().SwapBuffers(framebuffer); | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | } // namespace Service::Nvidia::Devices | 43 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 12f3ef825..e79e490ff 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -17,10 +17,11 @@ class nvmap; | |||
| 17 | 17 | ||
| 18 | class nvdisp_disp0 final : public nvdevice { | 18 | class nvdisp_disp0 final : public nvdevice { |
| 19 | public: | 19 | public: |
| 20 | explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvdisp_disp0() override; | 21 | ~nvdisp_disp0() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 24 | IoctlCtrl& ctrl) override; | ||
| 24 | 25 | ||
| 25 | /// Performs a screen flip, drawing the buffer pointed to by the handle. | 26 | /// Performs a screen flip, drawing the buffer pointed to by the handle. |
| 26 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, | 27 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index af62d33d2..24ab3f2e9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -22,10 +22,12 @@ enum { | |||
| 22 | }; | 22 | }; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} | 25 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 26 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | ||
| 26 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 27 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 27 | 28 | ||
| 28 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 29 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 30 | IoctlCtrl& ctrl) { | ||
| 29 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 31 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 30 | command.raw, input.size(), output.size()); | 32 | command.raw, input.size(), output.size()); |
| 31 | 33 | ||
| @@ -65,7 +67,7 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& | |||
| 65 | LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, | 67 | LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, |
| 66 | params.page_size, params.flags); | 68 | params.page_size, params.flags); |
| 67 | 69 | ||
| 68 | auto& gpu = Core::System::GetInstance().GPU(); | 70 | auto& gpu = system.GPU(); |
| 69 | const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; | 71 | const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; |
| 70 | if (params.flags & 1) { | 72 | if (params.flags & 1) { |
| 71 | params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1); | 73 | params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1); |
| @@ -85,7 +87,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 85 | std::vector<IoctlRemapEntry> entries(num_entries); | 87 | std::vector<IoctlRemapEntry> entries(num_entries); |
| 86 | std::memcpy(entries.data(), input.data(), input.size()); | 88 | std::memcpy(entries.data(), input.data(), input.size()); |
| 87 | 89 | ||
| 88 | auto& gpu = Core::System::GetInstance().GPU(); | 90 | auto& gpu = system.GPU(); |
| 89 | for (const auto& entry : entries) { | 91 | for (const auto& entry : entries) { |
| 90 | LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", | 92 | LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", |
| 91 | entry.offset, entry.nvmap_handle, entry.pages); | 93 | entry.offset, entry.nvmap_handle, entry.pages); |
| @@ -136,7 +138,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 136 | // case to prevent unexpected behavior. | 138 | // case to prevent unexpected behavior. |
| 137 | ASSERT(object->id == params.nvmap_handle); | 139 | ASSERT(object->id == params.nvmap_handle); |
| 138 | 140 | ||
| 139 | auto& gpu = Core::System::GetInstance().GPU(); | 141 | auto& gpu = system.GPU(); |
| 140 | 142 | ||
| 141 | if (params.flags & 1) { | 143 | if (params.flags & 1) { |
| 142 | params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size); | 144 | params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size); |
| @@ -173,8 +175,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 173 | return 0; | 175 | return 0; |
| 174 | } | 176 | } |
| 175 | 177 | ||
| 176 | params.offset = Core::System::GetInstance().GPU().MemoryManager().UnmapBuffer(params.offset, | 178 | params.offset = system.GPU().MemoryManager().UnmapBuffer(params.offset, itr->second.size); |
| 177 | itr->second.size); | ||
| 178 | buffer_mappings.erase(itr->second.offset); | 179 | buffer_mappings.erase(itr->second.offset); |
| 179 | 180 | ||
| 180 | std::memcpy(output.data(), ¶ms, output.size()); | 181 | std::memcpy(output.data(), ¶ms, output.size()); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index eb14b1da8..30ca5f4c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -17,10 +17,11 @@ class nvmap; | |||
| 17 | 17 | ||
| 18 | class nvhost_as_gpu final : public nvdevice { | 18 | class nvhost_as_gpu final : public nvdevice { |
| 19 | public: | 19 | public: |
| 20 | explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvhost_as_gpu() override; | 21 | ~nvhost_as_gpu() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 24 | IoctlCtrl& ctrl) override; | ||
| 24 | 25 | ||
| 25 | private: | 26 | private: |
| 26 | enum class IoctlCommand : u32_le { | 27 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index b39fb9ef9..9a66a5f88 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -7,14 +7,20 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | ||
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" | 13 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" |
| 14 | #include "video_core/gpu.h" | ||
| 11 | 15 | ||
| 12 | namespace Service::Nvidia::Devices { | 16 | namespace Service::Nvidia::Devices { |
| 13 | 17 | ||
| 14 | nvhost_ctrl::nvhost_ctrl() = default; | 18 | nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) |
| 19 | : nvdevice(system), events_interface{events_interface} {} | ||
| 15 | nvhost_ctrl::~nvhost_ctrl() = default; | 20 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 16 | 21 | ||
| 17 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 22 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 23 | IoctlCtrl& ctrl) { | ||
| 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 24 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 19 | command.raw, input.size(), output.size()); | 25 | command.raw, input.size(), output.size()); |
| 20 | 26 | ||
| @@ -22,11 +28,15 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector< | |||
| 22 | case IoctlCommand::IocGetConfigCommand: | 28 | case IoctlCommand::IocGetConfigCommand: |
| 23 | return NvOsGetConfigU32(input, output); | 29 | return NvOsGetConfigU32(input, output); |
| 24 | case IoctlCommand::IocCtrlEventWaitCommand: | 30 | case IoctlCommand::IocCtrlEventWaitCommand: |
| 25 | return IocCtrlEventWait(input, output, false); | 31 | return IocCtrlEventWait(input, output, false, ctrl); |
| 26 | case IoctlCommand::IocCtrlEventWaitAsyncCommand: | 32 | case IoctlCommand::IocCtrlEventWaitAsyncCommand: |
| 27 | return IocCtrlEventWait(input, output, true); | 33 | return IocCtrlEventWait(input, output, true, ctrl); |
| 28 | case IoctlCommand::IocCtrlEventRegisterCommand: | 34 | case IoctlCommand::IocCtrlEventRegisterCommand: |
| 29 | return IocCtrlEventRegister(input, output); | 35 | return IocCtrlEventRegister(input, output); |
| 36 | case IoctlCommand::IocCtrlEventUnregisterCommand: | ||
| 37 | return IocCtrlEventUnregister(input, output); | ||
| 38 | case IoctlCommand::IocCtrlEventSignalCommand: | ||
| 39 | return IocCtrlEventSignal(input, output); | ||
| 30 | } | 40 | } |
| 31 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 41 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); |
| 32 | return 0; | 42 | return 0; |
| @@ -41,23 +51,137 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& | |||
| 41 | } | 51 | } |
| 42 | 52 | ||
| 43 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, | 53 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, |
| 44 | bool is_async) { | 54 | bool is_async, IoctlCtrl& ctrl) { |
| 45 | IocCtrlEventWaitParams params{}; | 55 | IocCtrlEventWaitParams params{}; |
| 46 | std::memcpy(¶ms, input.data(), sizeof(params)); | 56 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 47 | LOG_WARNING(Service_NVDRV, | 57 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", |
| 48 | "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}", | 58 | params.syncpt_id, params.threshold, params.timeout, is_async); |
| 49 | params.syncpt_id, params.threshold, params.timeout, is_async); | ||
| 50 | 59 | ||
| 51 | // TODO(Subv): Implement actual syncpt waiting. | 60 | if (params.syncpt_id >= MaxSyncPoints) { |
| 52 | params.value = 0; | 61 | return NvResult::BadParameter; |
| 62 | } | ||
| 63 | |||
| 64 | auto& gpu = system.GPU(); | ||
| 65 | // This is mostly to take into account unimplemented features. As synced | ||
| 66 | // gpu is always synced. | ||
| 67 | if (!gpu.IsAsync()) { | ||
| 68 | return NvResult::Success; | ||
| 69 | } | ||
| 70 | auto lock = gpu.LockSync(); | ||
| 71 | const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); | ||
| 72 | const s32 diff = current_syncpoint_value - params.threshold; | ||
| 73 | if (diff >= 0) { | ||
| 74 | params.value = current_syncpoint_value; | ||
| 75 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 76 | return NvResult::Success; | ||
| 77 | } | ||
| 78 | const u32 target_value = current_syncpoint_value - diff; | ||
| 79 | |||
| 80 | if (!is_async) { | ||
| 81 | params.value = 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (params.timeout == 0) { | ||
| 85 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 86 | return NvResult::Timeout; | ||
| 87 | } | ||
| 88 | |||
| 89 | u32 event_id; | ||
| 90 | if (is_async) { | ||
| 91 | event_id = params.value & 0x00FF; | ||
| 92 | if (event_id >= MaxNvEvents) { | ||
| 93 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 94 | return NvResult::BadParameter; | ||
| 95 | } | ||
| 96 | } else { | ||
| 97 | if (ctrl.fresh_call) { | ||
| 98 | const auto result = events_interface.GetFreeEvent(); | ||
| 99 | if (result) { | ||
| 100 | event_id = *result; | ||
| 101 | } else { | ||
| 102 | LOG_CRITICAL(Service_NVDRV, "No Free Events available!"); | ||
| 103 | event_id = params.value & 0x00FF; | ||
| 104 | } | ||
| 105 | } else { | ||
| 106 | event_id = ctrl.event_id; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | EventState status = events_interface.status[event_id]; | ||
| 111 | if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) { | ||
| 112 | events_interface.SetEventStatus(event_id, EventState::Waiting); | ||
| 113 | events_interface.assigned_syncpt[event_id] = params.syncpt_id; | ||
| 114 | events_interface.assigned_value[event_id] = target_value; | ||
| 115 | if (is_async) { | ||
| 116 | params.value = params.syncpt_id << 4; | ||
| 117 | } else { | ||
| 118 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; | ||
| 119 | } | ||
| 120 | params.value |= event_id; | ||
| 121 | events_interface.events[event_id].writable->Clear(); | ||
| 122 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | ||
| 123 | if (!is_async && ctrl.fresh_call) { | ||
| 124 | ctrl.must_delay = true; | ||
| 125 | ctrl.timeout = params.timeout; | ||
| 126 | ctrl.event_id = event_id; | ||
| 127 | return NvResult::Timeout; | ||
| 128 | } | ||
| 129 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 130 | return NvResult::Timeout; | ||
| 131 | } | ||
| 53 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 132 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 54 | return 0; | 133 | return NvResult::BadParameter; |
| 55 | } | 134 | } |
| 56 | 135 | ||
| 57 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { | 136 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { |
| 58 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 137 | IocCtrlEventRegisterParams params{}; |
| 59 | // TODO(bunnei): Implement this. | 138 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 60 | return 0; | 139 | const u32 event_id = params.user_event_id & 0x00FF; |
| 140 | LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); | ||
| 141 | if (event_id >= MaxNvEvents) { | ||
| 142 | return NvResult::BadParameter; | ||
| 143 | } | ||
| 144 | if (events_interface.registered[event_id]) { | ||
| 145 | return NvResult::BadParameter; | ||
| 146 | } | ||
| 147 | events_interface.RegisterEvent(event_id); | ||
| 148 | return NvResult::Success; | ||
| 149 | } | ||
| 150 | |||
| 151 | u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 152 | IocCtrlEventUnregisterParams params{}; | ||
| 153 | std::memcpy(¶ms, input.data(), sizeof(params)); | ||
| 154 | const u32 event_id = params.user_event_id & 0x00FF; | ||
| 155 | LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); | ||
| 156 | if (event_id >= MaxNvEvents) { | ||
| 157 | return NvResult::BadParameter; | ||
| 158 | } | ||
| 159 | if (!events_interface.registered[event_id]) { | ||
| 160 | return NvResult::BadParameter; | ||
| 161 | } | ||
| 162 | events_interface.UnregisterEvent(event_id); | ||
| 163 | return NvResult::Success; | ||
| 164 | } | ||
| 165 | |||
| 166 | u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 167 | IocCtrlEventSignalParams params{}; | ||
| 168 | std::memcpy(¶ms, input.data(), sizeof(params)); | ||
| 169 | // TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization | ||
| 170 | // It is believed from RE to cancel the GPU Event. However, better research is required | ||
| 171 | u32 event_id = params.user_event_id & 0x00FF; | ||
| 172 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id); | ||
| 173 | if (event_id >= MaxNvEvents) { | ||
| 174 | return NvResult::BadParameter; | ||
| 175 | } | ||
| 176 | if (events_interface.status[event_id] == EventState::Waiting) { | ||
| 177 | auto& gpu = system.GPU(); | ||
| 178 | if (gpu.CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], | ||
| 179 | events_interface.assigned_value[event_id])) { | ||
| 180 | events_interface.LiberateEvent(event_id); | ||
| 181 | events_interface.events[event_id].writable->Signal(); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | return NvResult::Success; | ||
| 61 | } | 185 | } |
| 62 | 186 | ||
| 63 | } // namespace Service::Nvidia::Devices | 187 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 6d0de2212..14e6e7e57 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -8,15 +8,17 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 10 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 11 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 11 | 12 | ||
| 12 | namespace Service::Nvidia::Devices { | 13 | namespace Service::Nvidia::Devices { |
| 13 | 14 | ||
| 14 | class nvhost_ctrl final : public nvdevice { | 15 | class nvhost_ctrl final : public nvdevice { |
| 15 | public: | 16 | public: |
| 16 | nvhost_ctrl(); | 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); |
| 17 | ~nvhost_ctrl() override; | 18 | ~nvhost_ctrl() override; |
| 18 | 19 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 20 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 21 | IoctlCtrl& ctrl) override; | ||
| 20 | 22 | ||
| 21 | private: | 23 | private: |
| 22 | enum class IoctlCommand : u32_le { | 24 | enum class IoctlCommand : u32_le { |
| @@ -132,9 +134,16 @@ private: | |||
| 132 | 134 | ||
| 133 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); | 135 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); |
| 134 | 136 | ||
| 135 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); | 137 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, |
| 138 | IoctlCtrl& ctrl); | ||
| 136 | 139 | ||
| 137 | u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); | 140 | u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); |
| 141 | |||
| 142 | u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 143 | |||
| 144 | u32 IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 145 | |||
| 146 | EventInterface& events_interface; | ||
| 138 | }; | 147 | }; |
| 139 | 148 | ||
| 140 | } // namespace Service::Nvidia::Devices | 149 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 0e28755bd..988effd90 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -12,10 +12,11 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::Nvidia::Devices { | 13 | namespace Service::Nvidia::Devices { |
| 14 | 14 | ||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu() = default; | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} |
| 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 19 | IoctlCtrl& ctrl) { | ||
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 20 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 20 | command.raw, input.size(), output.size()); | 21 | command.raw, input.size(), output.size()); |
| 21 | 22 | ||
| @@ -185,7 +186,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o | |||
| 185 | 186 | ||
| 186 | IoctlGetGpuTime params{}; | 187 | IoctlGetGpuTime params{}; |
| 187 | std::memcpy(¶ms, input.data(), input.size()); | 188 | std::memcpy(¶ms, input.data(), input.size()); |
| 188 | const auto ns = Core::Timing::CyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks()); | 189 | const auto ns = Core::Timing::CyclesToNs(system.CoreTiming().GetTicks()); |
| 189 | params.gpu_time = static_cast<u64_le>(ns.count()); | 190 | params.gpu_time = static_cast<u64_le>(ns.count()); |
| 190 | std::memcpy(output.data(), ¶ms, output.size()); | 191 | std::memcpy(output.data(), ¶ms, output.size()); |
| 191 | return 0; | 192 | return 0; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 240435eea..2b035ae3f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -13,10 +13,11 @@ namespace Service::Nvidia::Devices { | |||
| 13 | 13 | ||
| 14 | class nvhost_ctrl_gpu final : public nvdevice { | 14 | class nvhost_ctrl_gpu final : public nvdevice { |
| 15 | public: | 15 | public: |
| 16 | nvhost_ctrl_gpu(); | 16 | explicit nvhost_ctrl_gpu(Core::System& system); |
| 17 | ~nvhost_ctrl_gpu() override; | 17 | ~nvhost_ctrl_gpu() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 20 | IoctlCtrl& ctrl) override; | ||
| 20 | 21 | ||
| 21 | private: | 22 | private: |
| 22 | enum class IoctlCommand : u32_le { | 23 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 8ce7bc7a5..241dac881 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -13,10 +13,12 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Nvidia::Devices { | 14 | namespace Service::Nvidia::Devices { |
| 15 | 15 | ||
| 16 | nvhost_gpu::nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} | 16 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | ||
| 17 | nvhost_gpu::~nvhost_gpu() = default; | 18 | nvhost_gpu::~nvhost_gpu() = default; |
| 18 | 19 | ||
| 19 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 21 | IoctlCtrl& ctrl) { | ||
| 20 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 22 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 21 | command.raw, input.size(), output.size()); | 23 | command.raw, input.size(), output.size()); |
| 22 | 24 | ||
| @@ -119,8 +121,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 119 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 121 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 120 | params.unk3); | 122 | params.unk3); |
| 121 | 123 | ||
| 122 | params.fence_out.id = 0; | 124 | auto& gpu = system.GPU(); |
| 123 | params.fence_out.value = 0; | 125 | params.fence_out.id = assigned_syncpoints; |
| 126 | params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints); | ||
| 127 | assigned_syncpoints++; | ||
| 124 | std::memcpy(output.data(), ¶ms, output.size()); | 128 | std::memcpy(output.data(), ¶ms, output.size()); |
| 125 | return 0; | 129 | return 0; |
| 126 | } | 130 | } |
| @@ -143,7 +147,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 143 | IoctlSubmitGpfifo params{}; | 147 | IoctlSubmitGpfifo params{}; |
| 144 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 148 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 145 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 149 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 146 | params.address, params.num_entries, params.flags); | 150 | params.address, params.num_entries, params.flags.raw); |
| 147 | 151 | ||
| 148 | ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + | 152 | ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + |
| 149 | params.num_entries * sizeof(Tegra::CommandListHeader), | 153 | params.num_entries * sizeof(Tegra::CommandListHeader), |
| @@ -153,10 +157,18 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 153 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | 157 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], |
| 154 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 158 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 155 | 159 | ||
| 156 | Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); | 160 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); |
| 161 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | ||
| 162 | |||
| 163 | auto& gpu = system.GPU(); | ||
| 164 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | ||
| 165 | if (params.flags.increment.Value()) { | ||
| 166 | params.fence_out.value += current_syncpoint_value; | ||
| 167 | } else { | ||
| 168 | params.fence_out.value = current_syncpoint_value; | ||
| 169 | } | ||
| 170 | gpu.PushGPUEntries(std::move(entries)); | ||
| 157 | 171 | ||
| 158 | params.fence_out.id = 0; | ||
| 159 | params.fence_out.value = 0; | ||
| 160 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 172 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 161 | return 0; | 173 | return 0; |
| 162 | } | 174 | } |
| @@ -168,16 +180,24 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 168 | IoctlSubmitGpfifo params{}; | 180 | IoctlSubmitGpfifo params{}; |
| 169 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 181 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 170 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 182 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 171 | params.address, params.num_entries, params.flags); | 183 | params.address, params.num_entries, params.flags.raw); |
| 172 | 184 | ||
| 173 | Tegra::CommandList entries(params.num_entries); | 185 | Tegra::CommandList entries(params.num_entries); |
| 174 | Memory::ReadBlock(params.address, entries.data(), | 186 | Memory::ReadBlock(params.address, entries.data(), |
| 175 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 187 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 176 | 188 | ||
| 177 | Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); | 189 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); |
| 190 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | ||
| 191 | |||
| 192 | auto& gpu = system.GPU(); | ||
| 193 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | ||
| 194 | if (params.flags.increment.Value()) { | ||
| 195 | params.fence_out.value += current_syncpoint_value; | ||
| 196 | } else { | ||
| 197 | params.fence_out.value = current_syncpoint_value; | ||
| 198 | } | ||
| 199 | gpu.PushGPUEntries(std::move(entries)); | ||
| 178 | 200 | ||
| 179 | params.fence_out.id = 0; | ||
| 180 | params.fence_out.value = 0; | ||
| 181 | std::memcpy(output.data(), ¶ms, output.size()); | 201 | std::memcpy(output.data(), ¶ms, output.size()); |
| 182 | return 0; | 202 | return 0; |
| 183 | } | 203 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 62beb5c0c..d2e8fbae9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 13 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 13 | 14 | ||
| 14 | namespace Service::Nvidia::Devices { | 15 | namespace Service::Nvidia::Devices { |
| 15 | 16 | ||
| @@ -20,10 +21,11 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | |||
| 20 | 21 | ||
| 21 | class nvhost_gpu final : public nvdevice { | 22 | class nvhost_gpu final : public nvdevice { |
| 22 | public: | 23 | public: |
| 23 | explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev); | 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 24 | ~nvhost_gpu() override; | 25 | ~nvhost_gpu() override; |
| 25 | 26 | ||
| 26 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 28 | IoctlCtrl& ctrl) override; | ||
| 27 | 29 | ||
| 28 | private: | 30 | private: |
| 29 | enum class IoctlCommand : u32_le { | 31 | enum class IoctlCommand : u32_le { |
| @@ -113,11 +115,7 @@ private: | |||
| 113 | static_assert(sizeof(IoctlGetErrorNotification) == 16, | 115 | static_assert(sizeof(IoctlGetErrorNotification) == 16, |
| 114 | "IoctlGetErrorNotification is incorrect size"); | 116 | "IoctlGetErrorNotification is incorrect size"); |
| 115 | 117 | ||
| 116 | struct IoctlFence { | 118 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); |
| 117 | u32_le id; | ||
| 118 | u32_le value; | ||
| 119 | }; | ||
| 120 | static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); | ||
| 121 | 119 | ||
| 122 | struct IoctlAllocGpfifoEx { | 120 | struct IoctlAllocGpfifoEx { |
| 123 | u32_le num_entries; | 121 | u32_le num_entries; |
| @@ -132,13 +130,13 @@ private: | |||
| 132 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); | 130 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); |
| 133 | 131 | ||
| 134 | struct IoctlAllocGpfifoEx2 { | 132 | struct IoctlAllocGpfifoEx2 { |
| 135 | u32_le num_entries; // in | 133 | u32_le num_entries; // in |
| 136 | u32_le flags; // in | 134 | u32_le flags; // in |
| 137 | u32_le unk0; // in (1 works) | 135 | u32_le unk0; // in (1 works) |
| 138 | IoctlFence fence_out; // out | 136 | Fence fence_out; // out |
| 139 | u32_le unk1; // in | 137 | u32_le unk1; // in |
| 140 | u32_le unk2; // in | 138 | u32_le unk2; // in |
| 141 | u32_le unk3; // in | 139 | u32_le unk3; // in |
| 142 | }; | 140 | }; |
| 143 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); | 141 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); |
| 144 | 142 | ||
| @@ -153,10 +151,16 @@ private: | |||
| 153 | struct IoctlSubmitGpfifo { | 151 | struct IoctlSubmitGpfifo { |
| 154 | u64_le address; // pointer to gpfifo entry structs | 152 | u64_le address; // pointer to gpfifo entry structs |
| 155 | u32_le num_entries; // number of fence objects being submitted | 153 | u32_le num_entries; // number of fence objects being submitted |
| 156 | u32_le flags; | 154 | union { |
| 157 | IoctlFence fence_out; // returned new fence object for others to wait on | 155 | u32_le raw; |
| 158 | }; | 156 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| 159 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(IoctlFence), | 157 | BitField<1, 1, u32_le> add_increment; // append an increment to the list |
| 158 | BitField<2, 1, u32_le> new_hw_format; // Mostly ignored | ||
| 159 | BitField<8, 1, u32_le> increment; // increment the returned fence | ||
| 160 | } flags; | ||
| 161 | Fence fence_out; // returned new fence object for others to wait on | ||
| 162 | }; | ||
| 163 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), | ||
| 160 | "IoctlSubmitGpfifo is incorrect size"); | 164 | "IoctlSubmitGpfifo is incorrect size"); |
| 161 | 165 | ||
| 162 | struct IoctlGetWaitbase { | 166 | struct IoctlGetWaitbase { |
| @@ -184,6 +188,7 @@ private: | |||
| 184 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 188 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 185 | 189 | ||
| 186 | std::shared_ptr<nvmap> nvmap_dev; | 190 | std::shared_ptr<nvmap> nvmap_dev; |
| 191 | u32 assigned_syncpoints{}; | ||
| 187 | }; | 192 | }; |
| 188 | 193 | ||
| 189 | } // namespace Service::Nvidia::Devices | 194 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f5e8ea7c3..f572ad30f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -10,10 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Nvidia::Devices { | 11 | namespace Service::Nvidia::Devices { |
| 12 | 12 | ||
| 13 | nvhost_nvdec::nvhost_nvdec() = default; | 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvdec::~nvhost_nvdec() = default; | 14 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 17 | IoctlCtrl& ctrl) { | ||
| 17 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 18 | command.raw, input.size(), output.size()); | 19 | command.raw, input.size(), output.size()); |
| 19 | 20 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 0e7b284f8..2710f0511 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -13,10 +13,11 @@ namespace Service::Nvidia::Devices { | |||
| 13 | 13 | ||
| 14 | class nvhost_nvdec final : public nvdevice { | 14 | class nvhost_nvdec final : public nvdevice { |
| 15 | public: | 15 | public: |
| 16 | nvhost_nvdec(); | 16 | explicit nvhost_nvdec(Core::System& system); |
| 17 | ~nvhost_nvdec() override; | 17 | ~nvhost_nvdec() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 20 | IoctlCtrl& ctrl) override; | ||
| 20 | 21 | ||
| 21 | private: | 22 | private: |
| 22 | enum class IoctlCommand : u32_le { | 23 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 3e0951ab0..38282956f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -10,10 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Nvidia::Devices { | 11 | namespace Service::Nvidia::Devices { |
| 12 | 12 | ||
| 13 | nvhost_nvjpg::nvhost_nvjpg() = default; | 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 17 | IoctlCtrl& ctrl) { | ||
| 17 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 18 | command.raw, input.size(), output.size()); | 19 | command.raw, input.size(), output.size()); |
| 19 | 20 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 89fd5e95e..379766693 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -13,10 +13,11 @@ namespace Service::Nvidia::Devices { | |||
| 13 | 13 | ||
| 14 | class nvhost_nvjpg final : public nvdevice { | 14 | class nvhost_nvjpg final : public nvdevice { |
| 15 | public: | 15 | public: |
| 16 | nvhost_nvjpg(); | 16 | explicit nvhost_nvjpg(Core::System& system); |
| 17 | ~nvhost_nvjpg() override; | 17 | ~nvhost_nvjpg() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 20 | IoctlCtrl& ctrl) override; | ||
| 20 | 21 | ||
| 21 | private: | 22 | private: |
| 22 | enum class IoctlCommand : u32_le { | 23 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index d544f0f31..70e8091db 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -10,10 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Nvidia::Devices { | 11 | namespace Service::Nvidia::Devices { |
| 12 | 12 | ||
| 13 | nvhost_vic::nvhost_vic() = default; | 13 | nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_vic::~nvhost_vic() = default; | 14 | nvhost_vic::~nvhost_vic() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 17 | IoctlCtrl& ctrl) { | ||
| 17 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 18 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", |
| 18 | command.raw, input.size(), output.size()); | 19 | command.raw, input.size(), output.size()); |
| 19 | 20 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index fc24c3f9c..7d111977e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -13,10 +13,11 @@ namespace Service::Nvidia::Devices { | |||
| 13 | 13 | ||
| 14 | class nvhost_vic final : public nvdevice { | 14 | class nvhost_vic final : public nvdevice { |
| 15 | public: | 15 | public: |
| 16 | nvhost_vic(); | 16 | explicit nvhost_vic(Core::System& system); |
| 17 | ~nvhost_vic() override; | 17 | ~nvhost_vic() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 20 | IoctlCtrl& ctrl) override; | ||
| 20 | 21 | ||
| 21 | private: | 22 | private: |
| 22 | enum class IoctlCommand : u32_le { | 23 | enum class IoctlCommand : u32_le { |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 1ec796fc6..223b496b7 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -18,7 +18,7 @@ enum { | |||
| 18 | }; | 18 | }; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | nvmap::nvmap() = default; | 21 | nvmap::nvmap(Core::System& system) : nvdevice(system) {} |
| 22 | nvmap::~nvmap() = default; | 22 | nvmap::~nvmap() = default; |
| 23 | 23 | ||
| 24 | VAddr nvmap::GetObjectAddress(u32 handle) const { | 24 | VAddr nvmap::GetObjectAddress(u32 handle) const { |
| @@ -28,7 +28,8 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { | |||
| 28 | return object->addr; | 28 | return object->addr; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | 31 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 32 | IoctlCtrl& ctrl) { | ||
| 32 | switch (static_cast<IoctlCommand>(command.raw)) { | 33 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 33 | case IoctlCommand::Create: | 34 | case IoctlCommand::Create: |
| 34 | return IocCreate(input, output); | 35 | return IocCreate(input, output); |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 396230c19..bf4a101c2 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -16,13 +16,14 @@ namespace Service::Nvidia::Devices { | |||
| 16 | 16 | ||
| 17 | class nvmap final : public nvdevice { | 17 | class nvmap final : public nvdevice { |
| 18 | public: | 18 | public: |
| 19 | nvmap(); | 19 | explicit nvmap(Core::System& system); |
| 20 | ~nvmap() override; | 20 | ~nvmap() override; |
| 21 | 21 | ||
| 22 | /// Returns the allocated address of an nvmap object given its handle. | 22 | /// Returns the allocated address of an nvmap object given its handle. |
| 23 | VAddr GetObjectAddress(u32 handle) const; | 23 | VAddr GetObjectAddress(u32 handle) const; |
| 24 | 24 | ||
| 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 26 | IoctlCtrl& ctrl) override; | ||
| 26 | 27 | ||
| 27 | /// Represents an nvmap object. | 28 | /// Represents an nvmap object. |
| 28 | struct Object { | 29 | struct Object { |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index b60fc748b..d5be64ed2 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -8,12 +8,18 @@ | |||
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | 10 | #include "core/hle/kernel/readable_event.h" |
| 11 | #include "core/hle/kernel/thread.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | 12 | #include "core/hle/kernel/writable_event.h" |
| 12 | #include "core/hle/service/nvdrv/interface.h" | 13 | #include "core/hle/service/nvdrv/interface.h" |
| 14 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 13 | #include "core/hle/service/nvdrv/nvdrv.h" | 15 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 14 | 16 | ||
| 15 | namespace Service::Nvidia { | 17 | namespace Service::Nvidia { |
| 16 | 18 | ||
| 19 | void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { | ||
| 20 | nvdrv->SignalSyncpt(syncpoint_id, value); | ||
| 21 | } | ||
| 22 | |||
| 17 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 18 | LOG_DEBUG(Service_NVDRV, "called"); | 24 | LOG_DEBUG(Service_NVDRV, "called"); |
| 19 | 25 | ||
| @@ -36,11 +42,31 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | |||
| 36 | 42 | ||
| 37 | std::vector<u8> output(ctx.GetWriteBufferSize()); | 43 | std::vector<u8> output(ctx.GetWriteBufferSize()); |
| 38 | 44 | ||
| 45 | IoctlCtrl ctrl{}; | ||
| 46 | |||
| 47 | u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output, ctrl); | ||
| 48 | |||
| 49 | if (ctrl.must_delay) { | ||
| 50 | ctrl.fresh_call = false; | ||
| 51 | ctx.SleepClientThread( | ||
| 52 | "NVServices::DelayedResponse", ctrl.timeout, | ||
| 53 | [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, | ||
| 54 | Kernel::ThreadWakeupReason reason) { | ||
| 55 | IoctlCtrl ctrl2{ctrl}; | ||
| 56 | std::vector<u8> output2 = output; | ||
| 57 | u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output2, ctrl2); | ||
| 58 | ctx.WriteBuffer(output2); | ||
| 59 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 60 | rb.Push(RESULT_SUCCESS); | ||
| 61 | rb.Push(result); | ||
| 62 | }, | ||
| 63 | nvdrv->GetEventWriteable(ctrl.event_id)); | ||
| 64 | } else { | ||
| 65 | ctx.WriteBuffer(output); | ||
| 66 | } | ||
| 39 | IPC::ResponseBuilder rb{ctx, 3}; | 67 | IPC::ResponseBuilder rb{ctx, 3}; |
| 40 | rb.Push(RESULT_SUCCESS); | 68 | rb.Push(RESULT_SUCCESS); |
| 41 | rb.Push(nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output)); | 69 | rb.Push(result); |
| 42 | |||
| 43 | ctx.WriteBuffer(output); | ||
| 44 | } | 70 | } |
| 45 | 71 | ||
| 46 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 72 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| @@ -66,13 +92,19 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | |||
| 66 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | 92 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { |
| 67 | IPC::RequestParser rp{ctx}; | 93 | IPC::RequestParser rp{ctx}; |
| 68 | u32 fd = rp.Pop<u32>(); | 94 | u32 fd = rp.Pop<u32>(); |
| 69 | u32 event_id = rp.Pop<u32>(); | 95 | // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 |
| 96 | u32 event_id = rp.Pop<u32>() & 0x000000FF; | ||
| 70 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); | 97 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); |
| 71 | 98 | ||
| 72 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 99 | IPC::ResponseBuilder rb{ctx, 3, 1}; |
| 73 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 74 | rb.PushCopyObjects(query_event.readable); | 101 | if (event_id < MaxNvEvents) { |
| 75 | rb.Push<u32>(0); | 102 | rb.PushCopyObjects(nvdrv->GetEvent(event_id)); |
| 103 | rb.Push<u32>(NvResult::Success); | ||
| 104 | } else { | ||
| 105 | rb.Push<u32>(0); | ||
| 106 | rb.Push<u32>(NvResult::BadParameter); | ||
| 107 | } | ||
| 76 | } | 108 | } |
| 77 | 109 | ||
| 78 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | 110 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { |
| @@ -127,10 +159,6 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 127 | {13, &NVDRV::FinishInitialize, "FinishInitialize"}, | 159 | {13, &NVDRV::FinishInitialize, "FinishInitialize"}, |
| 128 | }; | 160 | }; |
| 129 | RegisterHandlers(functions); | 161 | RegisterHandlers(functions); |
| 130 | |||
| 131 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 132 | query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, | ||
| 133 | "NVDRV::query_event"); | ||
| 134 | } | 162 | } |
| 135 | 163 | ||
| 136 | NVDRV::~NVDRV() = default; | 164 | NVDRV::~NVDRV() = default; |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 5b4889910..10a0ecd52 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -19,6 +19,8 @@ public: | |||
| 19 | NVDRV(std::shared_ptr<Module> nvdrv, const char* name); | 19 | NVDRV(std::shared_ptr<Module> nvdrv, const char* name); |
| 20 | ~NVDRV() override; | 20 | ~NVDRV() override; |
| 21 | 21 | ||
| 22 | void SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value); | ||
| 23 | |||
| 22 | private: | 24 | private: |
| 23 | void Open(Kernel::HLERequestContext& ctx); | 25 | void Open(Kernel::HLERequestContext& ctx); |
| 24 | void Ioctl(Kernel::HLERequestContext& ctx); | 26 | void Ioctl(Kernel::HLERequestContext& ctx); |
| @@ -33,8 +35,6 @@ private: | |||
| 33 | std::shared_ptr<Module> nvdrv; | 35 | std::shared_ptr<Module> nvdrv; |
| 34 | 36 | ||
| 35 | u64 pid{}; | 37 | u64 pid{}; |
| 36 | |||
| 37 | Kernel::EventPair query_event; | ||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | } // namespace Service::Nvidia | 40 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h new file mode 100644 index 000000000..ac03cbc23 --- /dev/null +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <array> | ||
| 4 | #include "common/common_types.h" | ||
| 5 | |||
| 6 | namespace Service::Nvidia { | ||
| 7 | |||
| 8 | constexpr u32 MaxSyncPoints = 192; | ||
| 9 | constexpr u32 MaxNvEvents = 64; | ||
| 10 | |||
| 11 | struct Fence { | ||
| 12 | s32 id; | ||
| 13 | u32 value; | ||
| 14 | }; | ||
| 15 | |||
| 16 | static_assert(sizeof(Fence) == 8, "Fence has wrong size"); | ||
| 17 | |||
| 18 | struct MultiFence { | ||
| 19 | u32 num_fences; | ||
| 20 | std::array<Fence, 4> fences; | ||
| 21 | }; | ||
| 22 | |||
| 23 | enum NvResult : u32 { | ||
| 24 | Success = 0, | ||
| 25 | BadParameter = 4, | ||
| 26 | Timeout = 5, | ||
| 27 | ResourceError = 15, | ||
| 28 | }; | ||
| 29 | |||
| 30 | enum class EventState { | ||
| 31 | Free = 0, | ||
| 32 | Registered = 1, | ||
| 33 | Waiting = 2, | ||
| 34 | Busy = 3, | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct IoctlCtrl { | ||
| 38 | // First call done to the servioce for services that call itself again after a call. | ||
| 39 | bool fresh_call{true}; | ||
| 40 | // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep | ||
| 41 | bool must_delay{}; | ||
| 42 | // Timeout for the delay | ||
| 43 | s64 timeout{}; | ||
| 44 | // NV Event Id | ||
| 45 | s32 event_id{-1}; | ||
| 46 | }; | ||
| 47 | |||
| 48 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 6e4b8f2c6..2011a226a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -4,7 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <utility> | 5 | #include <utility> |
| 6 | 6 | ||
| 7 | #include <fmt/format.h> | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/readable_event.h" | ||
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 8 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 11 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 12 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" |
| 10 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" | 13 | #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" |
| @@ -22,8 +25,9 @@ | |||
| 22 | 25 | ||
| 23 | namespace Service::Nvidia { | 26 | namespace Service::Nvidia { |
| 24 | 27 | ||
| 25 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) { | 28 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 26 | auto module_ = std::make_shared<Module>(); | 29 | Core::System& system) { |
| 30 | auto module_ = std::make_shared<Module>(system); | ||
| 27 | std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); | 31 | std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); |
| 28 | std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); | 32 | std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); |
| 29 | std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); | 33 | std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); |
| @@ -32,17 +36,25 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger | |||
| 32 | nvflinger.SetNVDrvInstance(module_); | 36 | nvflinger.SetNVDrvInstance(module_); |
| 33 | } | 37 | } |
| 34 | 38 | ||
| 35 | Module::Module() { | 39 | Module::Module(Core::System& system) { |
| 36 | auto nvmap_dev = std::make_shared<Devices::nvmap>(); | 40 | auto& kernel = system.Kernel(); |
| 37 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev); | 41 | for (u32 i = 0; i < MaxNvEvents; i++) { |
| 38 | devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(nvmap_dev); | 42 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); |
| 39 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(); | 43 | events_interface.events[i] = Kernel::WritableEvent::CreateEventPair( |
| 44 | kernel, Kernel::ResetType::Automatic, event_label); | ||
| 45 | events_interface.status[i] = EventState::Free; | ||
| 46 | events_interface.registered[i] = false; | ||
| 47 | } | ||
| 48 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); | ||
| 49 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); | ||
| 50 | devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev); | ||
| 51 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); | ||
| 40 | devices["/dev/nvmap"] = nvmap_dev; | 52 | devices["/dev/nvmap"] = nvmap_dev; |
| 41 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); | 53 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); |
| 42 | devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(); | 54 | devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); |
| 43 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(); | 55 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system); |
| 44 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(); | 56 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); |
| 45 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); | 57 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system); |
| 46 | } | 58 | } |
| 47 | 59 | ||
| 48 | Module::~Module() = default; | 60 | Module::~Module() = default; |
| @@ -59,12 +71,13 @@ u32 Module::Open(const std::string& device_name) { | |||
| 59 | return fd; | 71 | return fd; |
| 60 | } | 72 | } |
| 61 | 73 | ||
| 62 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) { | 74 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, |
| 75 | IoctlCtrl& ctrl) { | ||
| 63 | auto itr = open_files.find(fd); | 76 | auto itr = open_files.find(fd); |
| 64 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 77 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); |
| 65 | 78 | ||
| 66 | auto& device = itr->second; | 79 | auto& device = itr->second; |
| 67 | return device->ioctl({command}, input, output); | 80 | return device->ioctl({command}, input, output, ctrl); |
| 68 | } | 81 | } |
| 69 | 82 | ||
| 70 | ResultCode Module::Close(u32 fd) { | 83 | ResultCode Module::Close(u32 fd) { |
| @@ -77,4 +90,22 @@ ResultCode Module::Close(u32 fd) { | |||
| 77 | return RESULT_SUCCESS; | 90 | return RESULT_SUCCESS; |
| 78 | } | 91 | } |
| 79 | 92 | ||
| 93 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | ||
| 94 | for (u32 i = 0; i < MaxNvEvents; i++) { | ||
| 95 | if (events_interface.assigned_syncpt[i] == syncpoint_id && | ||
| 96 | events_interface.assigned_value[i] == value) { | ||
| 97 | events_interface.LiberateEvent(i); | ||
| 98 | events_interface.events[i].writable->Signal(); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | Kernel::SharedPtr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { | ||
| 104 | return events_interface.events[event_id].readable; | ||
| 105 | } | ||
| 106 | |||
| 107 | Kernel::SharedPtr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { | ||
| 108 | return events_interface.events[event_id].writable; | ||
| 109 | } | ||
| 110 | |||
| 80 | } // namespace Service::Nvidia | 111 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 53564f696..a339ab672 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -8,8 +8,14 @@ | |||
| 8 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 11 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 12 | 14 | ||
| 15 | namespace Core { | ||
| 16 | class System; | ||
| 17 | } | ||
| 18 | |||
| 13 | namespace Service::NVFlinger { | 19 | namespace Service::NVFlinger { |
| 14 | class NVFlinger; | 20 | class NVFlinger; |
| 15 | } | 21 | } |
| @@ -20,16 +26,72 @@ namespace Devices { | |||
| 20 | class nvdevice; | 26 | class nvdevice; |
| 21 | } | 27 | } |
| 22 | 28 | ||
| 23 | struct IoctlFence { | 29 | struct EventInterface { |
| 24 | u32 id; | 30 | // Mask representing currently busy events |
| 25 | u32 value; | 31 | u64 events_mask{}; |
| 32 | // Each kernel event associated to an NV event | ||
| 33 | std::array<Kernel::EventPair, MaxNvEvents> events; | ||
| 34 | // The status of the current NVEvent | ||
| 35 | std::array<EventState, MaxNvEvents> status{}; | ||
| 36 | // Tells if an NVEvent is registered or not | ||
| 37 | std::array<bool, MaxNvEvents> registered{}; | ||
| 38 | // When an NVEvent is waiting on GPU interrupt, this is the sync_point | ||
| 39 | // associated with it. | ||
| 40 | std::array<u32, MaxNvEvents> assigned_syncpt{}; | ||
| 41 | // This is the value of the GPU interrupt for which the NVEvent is waiting | ||
| 42 | // for. | ||
| 43 | std::array<u32, MaxNvEvents> assigned_value{}; | ||
| 44 | // Constant to denote an unasigned syncpoint. | ||
| 45 | static constexpr u32 unassigned_syncpt = 0xFFFFFFFF; | ||
| 46 | std::optional<u32> GetFreeEvent() const { | ||
| 47 | u64 mask = events_mask; | ||
| 48 | for (u32 i = 0; i < MaxNvEvents; i++) { | ||
| 49 | const bool is_free = (mask & 0x1) == 0; | ||
| 50 | if (is_free) { | ||
| 51 | if (status[i] == EventState::Registered || status[i] == EventState::Free) { | ||
| 52 | return {i}; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | mask = mask >> 1; | ||
| 56 | } | ||
| 57 | return {}; | ||
| 58 | } | ||
| 59 | void SetEventStatus(const u32 event_id, EventState new_status) { | ||
| 60 | EventState old_status = status[event_id]; | ||
| 61 | if (old_status == new_status) { | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | status[event_id] = new_status; | ||
| 65 | if (new_status == EventState::Registered) { | ||
| 66 | registered[event_id] = true; | ||
| 67 | } | ||
| 68 | if (new_status == EventState::Waiting || new_status == EventState::Busy) { | ||
| 69 | events_mask |= (1ULL << event_id); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | void RegisterEvent(const u32 event_id) { | ||
| 73 | registered[event_id] = true; | ||
| 74 | if (status[event_id] == EventState::Free) { | ||
| 75 | status[event_id] = EventState::Registered; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | void UnregisterEvent(const u32 event_id) { | ||
| 79 | registered[event_id] = false; | ||
| 80 | if (status[event_id] == EventState::Registered) { | ||
| 81 | status[event_id] = EventState::Free; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | void LiberateEvent(const u32 event_id) { | ||
| 85 | status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free; | ||
| 86 | events_mask &= ~(1ULL << event_id); | ||
| 87 | assigned_syncpt[event_id] = unassigned_syncpt; | ||
| 88 | assigned_value[event_id] = 0; | ||
| 89 | } | ||
| 26 | }; | 90 | }; |
| 27 | 91 | ||
| 28 | static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size"); | ||
| 29 | |||
| 30 | class Module final { | 92 | class Module final { |
| 31 | public: | 93 | public: |
| 32 | Module(); | 94 | Module(Core::System& system); |
| 33 | ~Module(); | 95 | ~Module(); |
| 34 | 96 | ||
| 35 | /// Returns a pointer to one of the available devices, identified by its name. | 97 | /// Returns a pointer to one of the available devices, identified by its name. |
| @@ -44,10 +106,17 @@ public: | |||
| 44 | /// Opens a device node and returns a file descriptor to it. | 106 | /// Opens a device node and returns a file descriptor to it. |
| 45 | u32 Open(const std::string& device_name); | 107 | u32 Open(const std::string& device_name); |
| 46 | /// Sends an ioctl command to the specified file descriptor. | 108 | /// Sends an ioctl command to the specified file descriptor. |
| 47 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output); | 109 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, |
| 110 | IoctlCtrl& ctrl); | ||
| 48 | /// Closes a device file descriptor and returns operation success. | 111 | /// Closes a device file descriptor and returns operation success. |
| 49 | ResultCode Close(u32 fd); | 112 | ResultCode Close(u32 fd); |
| 50 | 113 | ||
| 114 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); | ||
| 115 | |||
| 116 | Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(u32 event_id) const; | ||
| 117 | |||
| 118 | Kernel::SharedPtr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; | ||
| 119 | |||
| 51 | private: | 120 | private: |
| 52 | /// Id to use for the next open file descriptor. | 121 | /// Id to use for the next open file descriptor. |
| 53 | u32 next_fd = 1; | 122 | u32 next_fd = 1; |
| @@ -57,9 +126,12 @@ private: | |||
| 57 | 126 | ||
| 58 | /// Mapping of device node names to their implementation. | 127 | /// Mapping of device node names to their implementation. |
| 59 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 128 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; |
| 129 | |||
| 130 | EventInterface events_interface; | ||
| 60 | }; | 131 | }; |
| 61 | 132 | ||
| 62 | /// Registers all NVDRV services with the specified service manager. | 133 | /// Registers all NVDRV services with the specified service manager. |
| 63 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger); | 134 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 135 | Core::System& system); | ||
| 64 | 136 | ||
| 65 | } // namespace Service::Nvidia | 137 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 5731e815f..e1a07d3ee 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -34,7 +34,8 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) | |||
| 34 | buffer_wait_event.writable->Signal(); | 34 | buffer_wait_event.writable->Signal(); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { | 37 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, |
| 38 | u32 height) { | ||
| 38 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | 39 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { |
| 39 | // Only consider free buffers. Buffers become free once again after they've been Acquired | 40 | // Only consider free buffers. Buffers become free once again after they've been Acquired |
| 40 | // and Released by the compositor, see the NVFlinger::Compose method. | 41 | // and Released by the compositor, see the NVFlinger::Compose method. |
| @@ -51,7 +52,7 @@ std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { | |||
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | itr->status = Buffer::Status::Dequeued; | 54 | itr->status = Buffer::Status::Dequeued; |
| 54 | return itr->slot; | 55 | return {{itr->slot, &itr->multi_fence}}; |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | 58 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { |
| @@ -63,7 +64,8 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | |||
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, | 66 | void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, |
| 66 | const Common::Rectangle<int>& crop_rect) { | 67 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, |
| 68 | Service::Nvidia::MultiFence& multi_fence) { | ||
| 67 | auto itr = std::find_if(queue.begin(), queue.end(), | 69 | auto itr = std::find_if(queue.begin(), queue.end(), |
| 68 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | 70 | [&](const Buffer& buffer) { return buffer.slot == slot; }); |
| 69 | ASSERT(itr != queue.end()); | 71 | ASSERT(itr != queue.end()); |
| @@ -71,12 +73,21 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, | |||
| 71 | itr->status = Buffer::Status::Queued; | 73 | itr->status = Buffer::Status::Queued; |
| 72 | itr->transform = transform; | 74 | itr->transform = transform; |
| 73 | itr->crop_rect = crop_rect; | 75 | itr->crop_rect = crop_rect; |
| 76 | itr->swap_interval = swap_interval; | ||
| 77 | itr->multi_fence = multi_fence; | ||
| 78 | queue_sequence.push_back(slot); | ||
| 74 | } | 79 | } |
| 75 | 80 | ||
| 76 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { | 81 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { |
| 77 | auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { | 82 | auto itr = queue.end(); |
| 78 | return buffer.status == Buffer::Status::Queued; | 83 | // Iterate to find a queued buffer matching the requested slot. |
| 79 | }); | 84 | while (itr == queue.end() && !queue_sequence.empty()) { |
| 85 | u32 slot = queue_sequence.front(); | ||
| 86 | itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) { | ||
| 87 | return buffer.status == Buffer::Status::Queued && buffer.slot == slot; | ||
| 88 | }); | ||
| 89 | queue_sequence.pop_front(); | ||
| 90 | } | ||
| 80 | if (itr == queue.end()) | 91 | if (itr == queue.end()) |
| 81 | return {}; | 92 | return {}; |
| 82 | itr->status = Buffer::Status::Acquired; | 93 | itr->status = Buffer::Status::Acquired; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index e1ccb6171..356bedb81 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <list> | ||
| 7 | #include <optional> | 8 | #include <optional> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| @@ -12,6 +13,7 @@ | |||
| 12 | #include "common/swap.h" | 13 | #include "common/swap.h" |
| 13 | #include "core/hle/kernel/object.h" | 14 | #include "core/hle/kernel/object.h" |
| 14 | #include "core/hle/kernel/writable_event.h" | 15 | #include "core/hle/kernel/writable_event.h" |
| 16 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 15 | 17 | ||
| 16 | namespace Service::NVFlinger { | 18 | namespace Service::NVFlinger { |
| 17 | 19 | ||
| @@ -68,13 +70,17 @@ public: | |||
| 68 | IGBPBuffer igbp_buffer; | 70 | IGBPBuffer igbp_buffer; |
| 69 | BufferTransformFlags transform; | 71 | BufferTransformFlags transform; |
| 70 | Common::Rectangle<int> crop_rect; | 72 | Common::Rectangle<int> crop_rect; |
| 73 | u32 swap_interval; | ||
| 74 | Service::Nvidia::MultiFence multi_fence; | ||
| 71 | }; | 75 | }; |
| 72 | 76 | ||
| 73 | void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); | 77 | void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); |
| 74 | std::optional<u32> DequeueBuffer(u32 width, u32 height); | 78 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> DequeueBuffer(u32 width, |
| 79 | u32 height); | ||
| 75 | const IGBPBuffer& RequestBuffer(u32 slot) const; | 80 | const IGBPBuffer& RequestBuffer(u32 slot) const; |
| 76 | void QueueBuffer(u32 slot, BufferTransformFlags transform, | 81 | void QueueBuffer(u32 slot, BufferTransformFlags transform, |
| 77 | const Common::Rectangle<int>& crop_rect); | 82 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, |
| 83 | Service::Nvidia::MultiFence& multi_fence); | ||
| 78 | std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); | 84 | std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); |
| 79 | void ReleaseBuffer(u32 slot); | 85 | void ReleaseBuffer(u32 slot); |
| 80 | u32 Query(QueryType type); | 86 | u32 Query(QueryType type); |
| @@ -92,6 +98,7 @@ private: | |||
| 92 | u64 layer_id; | 98 | u64 layer_id; |
| 93 | 99 | ||
| 94 | std::vector<Buffer> queue; | 100 | std::vector<Buffer> queue; |
| 101 | std::list<u32> queue_sequence; | ||
| 95 | Kernel::EventPair buffer_wait_event; | 102 | Kernel::EventPair buffer_wait_event; |
| 96 | }; | 103 | }; |
| 97 | 104 | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 3c5c53e24..f9db79370 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -37,15 +37,14 @@ NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_t | |||
| 37 | displays.emplace_back(4, "Null"); | 37 | displays.emplace_back(4, "Null"); |
| 38 | 38 | ||
| 39 | // Schedule the screen composition events | 39 | // Schedule the screen composition events |
| 40 | const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks; | 40 | composition_event = core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, |
| 41 | 41 | s64 cycles_late) { | |
| 42 | composition_event = core_timing.RegisterEvent( | 42 | Compose(); |
| 43 | "ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) { | 43 | const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); |
| 44 | Compose(); | 44 | this->core_timing.ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), composition_event); |
| 45 | this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event); | 45 | }); |
| 46 | }); | 46 | |
| 47 | 47 | core_timing.ScheduleEvent(frame_ticks, composition_event); | |
| 48 | core_timing.ScheduleEvent(ticks, composition_event); | ||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | NVFlinger::~NVFlinger() { | 50 | NVFlinger::~NVFlinger() { |
| @@ -206,8 +205,14 @@ void NVFlinger::Compose() { | |||
| 206 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, | 205 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, |
| 207 | buffer->get().transform, buffer->get().crop_rect); | 206 | buffer->get().transform, buffer->get().crop_rect); |
| 208 | 207 | ||
| 208 | swap_interval = buffer->get().swap_interval; | ||
| 209 | buffer_queue.ReleaseBuffer(buffer->get().slot); | 209 | buffer_queue.ReleaseBuffer(buffer->get().slot); |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | s64 NVFlinger::GetNextTicks() const { | ||
| 214 | constexpr s64 max_hertz = 120LL; | ||
| 215 | return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; | ||
| 216 | } | ||
| 217 | |||
| 213 | } // namespace Service::NVFlinger | 218 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index c0a83fffb..988be8726 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -74,6 +74,8 @@ public: | |||
| 74 | /// finished. | 74 | /// finished. |
| 75 | void Compose(); | 75 | void Compose(); |
| 76 | 76 | ||
| 77 | s64 GetNextTicks() const; | ||
| 78 | |||
| 77 | private: | 79 | private: |
| 78 | /// Finds the display identified by the specified ID. | 80 | /// Finds the display identified by the specified ID. |
| 79 | VI::Display* FindDisplay(u64 display_id); | 81 | VI::Display* FindDisplay(u64 display_id); |
| @@ -98,6 +100,8 @@ private: | |||
| 98 | /// layers. | 100 | /// layers. |
| 99 | u32 next_buffer_queue_id = 1; | 101 | u32 next_buffer_queue_id = 1; |
| 100 | 102 | ||
| 103 | u32 swap_interval = 1; | ||
| 104 | |||
| 101 | /// Event that handles screen composition. | 105 | /// Event that handles screen composition. |
| 102 | Core::Timing::EventType* composition_event; | 106 | Core::Timing::EventType* composition_event; |
| 103 | 107 | ||
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 952c03e27..3a0f8c3f6 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -206,7 +206,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 206 | AM::InstallInterfaces(*sm, nv_flinger, system); | 206 | AM::InstallInterfaces(*sm, nv_flinger, system); |
| 207 | AOC::InstallInterfaces(*sm); | 207 | AOC::InstallInterfaces(*sm); |
| 208 | APM::InstallInterfaces(system); | 208 | APM::InstallInterfaces(system); |
| 209 | Audio::InstallInterfaces(*sm); | 209 | Audio::InstallInterfaces(*sm, system); |
| 210 | BCAT::InstallInterfaces(*sm); | 210 | BCAT::InstallInterfaces(*sm); |
| 211 | BPC::InstallInterfaces(*sm); | 211 | BPC::InstallInterfaces(*sm); |
| 212 | BtDrv::InstallInterfaces(*sm); | 212 | BtDrv::InstallInterfaces(*sm); |
| @@ -236,12 +236,12 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 236 | NIM::InstallInterfaces(*sm); | 236 | NIM::InstallInterfaces(*sm); |
| 237 | NPNS::InstallInterfaces(*sm); | 237 | NPNS::InstallInterfaces(*sm); |
| 238 | NS::InstallInterfaces(*sm); | 238 | NS::InstallInterfaces(*sm); |
| 239 | Nvidia::InstallInterfaces(*sm, *nv_flinger); | 239 | Nvidia::InstallInterfaces(*sm, *nv_flinger, system); |
| 240 | PCIe::InstallInterfaces(*sm); | 240 | PCIe::InstallInterfaces(*sm); |
| 241 | PCTL::InstallInterfaces(*sm); | 241 | PCTL::InstallInterfaces(*sm); |
| 242 | PCV::InstallInterfaces(*sm); | 242 | PCV::InstallInterfaces(*sm); |
| 243 | PlayReport::InstallInterfaces(*sm); | 243 | PlayReport::InstallInterfaces(*sm); |
| 244 | PM::InstallInterfaces(*sm); | 244 | PM::InstallInterfaces(system); |
| 245 | PSC::InstallInterfaces(*sm); | 245 | PSC::InstallInterfaces(*sm); |
| 246 | PSM::InstallInterfaces(*sm); | 246 | PSM::InstallInterfaces(*sm); |
| 247 | Set::InstallInterfaces(*sm); | 247 | Set::InstallInterfaces(*sm); |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index f1fa6ccd1..199b30635 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "core/hle/kernel/readable_event.h" | 21 | #include "core/hle/kernel/readable_event.h" |
| 22 | #include "core/hle/kernel/thread.h" | 22 | #include "core/hle/kernel/thread.h" |
| 23 | #include "core/hle/kernel/writable_event.h" | 23 | #include "core/hle/kernel/writable_event.h" |
| 24 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 24 | #include "core/hle/service/nvdrv/nvdrv.h" | 25 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 25 | #include "core/hle/service/nvflinger/buffer_queue.h" | 26 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 26 | #include "core/hle/service/nvflinger/nvflinger.h" | 27 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -328,32 +329,22 @@ public: | |||
| 328 | Data data; | 329 | Data data; |
| 329 | }; | 330 | }; |
| 330 | 331 | ||
| 331 | struct BufferProducerFence { | ||
| 332 | u32 is_valid; | ||
| 333 | std::array<Nvidia::IoctlFence, 4> fences; | ||
| 334 | }; | ||
| 335 | static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size"); | ||
| 336 | |||
| 337 | class IGBPDequeueBufferResponseParcel : public Parcel { | 332 | class IGBPDequeueBufferResponseParcel : public Parcel { |
| 338 | public: | 333 | public: |
| 339 | explicit IGBPDequeueBufferResponseParcel(u32 slot) : slot(slot) {} | 334 | explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) |
| 335 | : slot(slot), multi_fence(multi_fence) {} | ||
| 340 | ~IGBPDequeueBufferResponseParcel() override = default; | 336 | ~IGBPDequeueBufferResponseParcel() override = default; |
| 341 | 337 | ||
| 342 | protected: | 338 | protected: |
| 343 | void SerializeData() override { | 339 | void SerializeData() override { |
| 344 | // TODO(Subv): Find out how this Fence is used. | ||
| 345 | BufferProducerFence fence = {}; | ||
| 346 | fence.is_valid = 1; | ||
| 347 | for (auto& fence_ : fence.fences) | ||
| 348 | fence_.id = -1; | ||
| 349 | |||
| 350 | Write(slot); | 340 | Write(slot); |
| 351 | Write<u32_le>(1); | 341 | Write<u32_le>(1); |
| 352 | WriteObject(fence); | 342 | WriteObject(multi_fence); |
| 353 | Write<u32_le>(0); | 343 | Write<u32_le>(0); |
| 354 | } | 344 | } |
| 355 | 345 | ||
| 356 | u32_le slot; | 346 | u32_le slot; |
| 347 | Service::Nvidia::MultiFence multi_fence; | ||
| 357 | }; | 348 | }; |
| 358 | 349 | ||
| 359 | class IGBPRequestBufferRequestParcel : public Parcel { | 350 | class IGBPRequestBufferRequestParcel : public Parcel { |
| @@ -400,12 +391,6 @@ public: | |||
| 400 | data = Read<Data>(); | 391 | data = Read<Data>(); |
| 401 | } | 392 | } |
| 402 | 393 | ||
| 403 | struct Fence { | ||
| 404 | u32_le id; | ||
| 405 | u32_le value; | ||
| 406 | }; | ||
| 407 | static_assert(sizeof(Fence) == 8, "Fence has wrong size"); | ||
| 408 | |||
| 409 | struct Data { | 394 | struct Data { |
| 410 | u32_le slot; | 395 | u32_le slot; |
| 411 | INSERT_PADDING_WORDS(3); | 396 | INSERT_PADDING_WORDS(3); |
| @@ -418,15 +403,15 @@ public: | |||
| 418 | s32_le scaling_mode; | 403 | s32_le scaling_mode; |
| 419 | NVFlinger::BufferQueue::BufferTransformFlags transform; | 404 | NVFlinger::BufferQueue::BufferTransformFlags transform; |
| 420 | u32_le sticky_transform; | 405 | u32_le sticky_transform; |
| 421 | INSERT_PADDING_WORDS(2); | 406 | INSERT_PADDING_WORDS(1); |
| 422 | u32_le fence_is_valid; | 407 | u32_le swap_interval; |
| 423 | std::array<Fence, 2> fences; | 408 | Service::Nvidia::MultiFence multi_fence; |
| 424 | 409 | ||
| 425 | Common::Rectangle<int> GetCropRect() const { | 410 | Common::Rectangle<int> GetCropRect() const { |
| 426 | return {crop_left, crop_top, crop_right, crop_bottom}; | 411 | return {crop_left, crop_top, crop_right, crop_bottom}; |
| 427 | } | 412 | } |
| 428 | }; | 413 | }; |
| 429 | static_assert(sizeof(Data) == 80, "ParcelData has wrong size"); | 414 | static_assert(sizeof(Data) == 96, "ParcelData has wrong size"); |
| 430 | 415 | ||
| 431 | Data data; | 416 | Data data; |
| 432 | }; | 417 | }; |
| @@ -547,11 +532,11 @@ private: | |||
| 547 | IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; | 532 | IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; |
| 548 | const u32 width{request.data.width}; | 533 | const u32 width{request.data.width}; |
| 549 | const u32 height{request.data.height}; | 534 | const u32 height{request.data.height}; |
| 550 | std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height); | 535 | auto result = buffer_queue.DequeueBuffer(width, height); |
| 551 | 536 | ||
| 552 | if (slot) { | 537 | if (result) { |
| 553 | // Buffer is available | 538 | // Buffer is available |
| 554 | IGBPDequeueBufferResponseParcel response{*slot}; | 539 | IGBPDequeueBufferResponseParcel response{result->first, *result->second}; |
| 555 | ctx.WriteBuffer(response.Serialize()); | 540 | ctx.WriteBuffer(response.Serialize()); |
| 556 | } else { | 541 | } else { |
| 557 | // Wait the current thread until a buffer becomes available | 542 | // Wait the current thread until a buffer becomes available |
| @@ -561,10 +546,10 @@ private: | |||
| 561 | Kernel::ThreadWakeupReason reason) { | 546 | Kernel::ThreadWakeupReason reason) { |
| 562 | // Repeat TransactParcel DequeueBuffer when a buffer is available | 547 | // Repeat TransactParcel DequeueBuffer when a buffer is available |
| 563 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); | 548 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); |
| 564 | std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height); | 549 | auto result = buffer_queue.DequeueBuffer(width, height); |
| 565 | ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer."); | 550 | ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); |
| 566 | 551 | ||
| 567 | IGBPDequeueBufferResponseParcel response{*slot}; | 552 | IGBPDequeueBufferResponseParcel response{result->first, *result->second}; |
| 568 | ctx.WriteBuffer(response.Serialize()); | 553 | ctx.WriteBuffer(response.Serialize()); |
| 569 | IPC::ResponseBuilder rb{ctx, 2}; | 554 | IPC::ResponseBuilder rb{ctx, 2}; |
| 570 | rb.Push(RESULT_SUCCESS); | 555 | rb.Push(RESULT_SUCCESS); |
| @@ -582,7 +567,8 @@ private: | |||
| 582 | IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; | 567 | IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; |
| 583 | 568 | ||
| 584 | buffer_queue.QueueBuffer(request.data.slot, request.data.transform, | 569 | buffer_queue.QueueBuffer(request.data.slot, request.data.transform, |
| 585 | request.data.GetCropRect()); | 570 | request.data.GetCropRect(), request.data.swap_interval, |
| 571 | request.data.multi_fence); | ||
| 586 | 572 | ||
| 587 | IGBPQueueBufferResponseParcel response{1280, 720}; | 573 | IGBPQueueBufferResponseParcel response{1280, 720}; |
| 588 | ctx.WriteBuffer(response.Serialize()); | 574 | ctx.WriteBuffer(response.Serialize()); |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 6d4b02375..f1795fdd6 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -295,7 +295,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 295 | } | 295 | } |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | std::vector<u8> program_image(total_image_size); | 298 | Kernel::PhysicalMemory program_image(total_image_size); |
| 299 | std::size_t current_image_position = 0; | 299 | std::size_t current_image_position = 0; |
| 300 | 300 | ||
| 301 | Kernel::CodeSet codeset; | 301 | Kernel::CodeSet codeset; |
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 70051c13a..474b55cb1 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp | |||
| @@ -69,7 +69,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) { | |||
| 69 | 69 | ||
| 70 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 70 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 71 | Kernel::CodeSet codeset; | 71 | Kernel::CodeSet codeset; |
| 72 | std::vector<u8> program_image; | 72 | Kernel::PhysicalMemory program_image; |
| 73 | 73 | ||
| 74 | const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment, | 74 | const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment, |
| 75 | const std::vector<u8>& data, u32 offset) { | 75 | const std::vector<u8>& data, u32 offset) { |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 6a0ca389b..e92e2e06e 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -143,7 +143,7 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | // Build program image | 145 | // Build program image |
| 146 | std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); | 146 | Kernel::PhysicalMemory program_image(PageAlignSize(nro_header.file_size)); |
| 147 | std::memcpy(program_image.data(), data.data(), program_image.size()); | 147 | std::memcpy(program_image.data(), data.data(), program_image.size()); |
| 148 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { | 148 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { |
| 149 | return {}; | 149 | return {}; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 29311404a..70c90109f 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -89,7 +89,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 89 | 89 | ||
| 90 | // Build program image | 90 | // Build program image |
| 91 | Kernel::CodeSet codeset; | 91 | Kernel::CodeSet codeset; |
| 92 | std::vector<u8> program_image; | 92 | Kernel::PhysicalMemory program_image; |
| 93 | for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { | 93 | for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { |
| 94 | std::vector<u8> data = | 94 | std::vector<u8> data = |
| 95 | file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); | 95 | file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); |
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", |