diff options
Diffstat (limited to 'src/core')
148 files changed, 5625 insertions, 1793 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2d61e2f2c..882c9ab59 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -12,6 +12,8 @@ add_library(core STATIC | |||
| 12 | core_timing.h | 12 | core_timing.h |
| 13 | core_timing_util.cpp | 13 | core_timing_util.cpp |
| 14 | core_timing_util.h | 14 | core_timing_util.h |
| 15 | cpu_core_manager.cpp | ||
| 16 | cpu_core_manager.h | ||
| 15 | crypto/aes_util.cpp | 17 | crypto/aes_util.cpp |
| 16 | crypto/aes_util.h | 18 | crypto/aes_util.h |
| 17 | crypto/encryption_layer.cpp | 19 | crypto/encryption_layer.cpp |
| @@ -81,6 +83,8 @@ add_library(core STATIC | |||
| 81 | file_sys/vfs_vector.h | 83 | file_sys/vfs_vector.h |
| 82 | file_sys/xts_archive.cpp | 84 | file_sys/xts_archive.cpp |
| 83 | file_sys/xts_archive.h | 85 | file_sys/xts_archive.h |
| 86 | frontend/applets/software_keyboard.cpp | ||
| 87 | frontend/applets/software_keyboard.h | ||
| 84 | frontend/emu_window.cpp | 88 | frontend/emu_window.cpp |
| 85 | frontend/emu_window.h | 89 | frontend/emu_window.h |
| 86 | frontend/framebuffer_layout.cpp | 90 | frontend/framebuffer_layout.cpp |
| @@ -97,8 +101,6 @@ add_library(core STATIC | |||
| 97 | hle/kernel/client_session.cpp | 101 | hle/kernel/client_session.cpp |
| 98 | hle/kernel/client_session.h | 102 | hle/kernel/client_session.h |
| 99 | hle/kernel/errors.h | 103 | hle/kernel/errors.h |
| 100 | hle/kernel/event.cpp | ||
| 101 | hle/kernel/event.h | ||
| 102 | hle/kernel/handle_table.cpp | 104 | hle/kernel/handle_table.cpp |
| 103 | hle/kernel/handle_table.h | 105 | hle/kernel/handle_table.h |
| 104 | hle/kernel/hle_ipc.cpp | 106 | hle/kernel/hle_ipc.cpp |
| @@ -111,6 +113,8 @@ add_library(core STATIC | |||
| 111 | hle/kernel/object.h | 113 | hle/kernel/object.h |
| 112 | hle/kernel/process.cpp | 114 | hle/kernel/process.cpp |
| 113 | hle/kernel/process.h | 115 | hle/kernel/process.h |
| 116 | hle/kernel/readable_event.cpp | ||
| 117 | hle/kernel/readable_event.h | ||
| 114 | hle/kernel/resource_limit.cpp | 118 | hle/kernel/resource_limit.cpp |
| 115 | hle/kernel/resource_limit.h | 119 | hle/kernel/resource_limit.h |
| 116 | hle/kernel/scheduler.cpp | 120 | hle/kernel/scheduler.cpp |
| @@ -133,6 +137,8 @@ add_library(core STATIC | |||
| 133 | hle/kernel/vm_manager.h | 137 | hle/kernel/vm_manager.h |
| 134 | hle/kernel/wait_object.cpp | 138 | hle/kernel/wait_object.cpp |
| 135 | hle/kernel/wait_object.h | 139 | hle/kernel/wait_object.h |
| 140 | hle/kernel/writable_event.cpp | ||
| 141 | hle/kernel/writable_event.h | ||
| 136 | hle/lock.cpp | 142 | hle/lock.cpp |
| 137 | hle/lock.h | 143 | hle/lock.h |
| 138 | hle/result.h | 144 | hle/result.h |
| @@ -154,6 +160,12 @@ add_library(core STATIC | |||
| 154 | hle/service/am/applet_ae.h | 160 | hle/service/am/applet_ae.h |
| 155 | hle/service/am/applet_oe.cpp | 161 | hle/service/am/applet_oe.cpp |
| 156 | hle/service/am/applet_oe.h | 162 | hle/service/am/applet_oe.h |
| 163 | hle/service/am/applets/applets.cpp | ||
| 164 | hle/service/am/applets/applets.h | ||
| 165 | hle/service/am/applets/software_keyboard.cpp | ||
| 166 | hle/service/am/applets/software_keyboard.h | ||
| 167 | hle/service/am/applets/stub_applet.cpp | ||
| 168 | hle/service/am/applets/stub_applet.h | ||
| 157 | hle/service/am/idle.cpp | 169 | hle/service/am/idle.cpp |
| 158 | hle/service/am/idle.h | 170 | hle/service/am/idle.h |
| 159 | hle/service/am/omm.cpp | 171 | hle/service/am/omm.cpp |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 6d5b5a2d0..795fabc65 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/core_cpu.h" | 15 | #include "core/core_cpu.h" |
| 16 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 17 | #include "core/cpu_core_manager.h" | ||
| 17 | #include "core/file_sys/mode.h" | 18 | #include "core/file_sys/mode.h" |
| 18 | #include "core/file_sys/vfs_concat.h" | 19 | #include "core/file_sys/vfs_concat.h" |
| 19 | #include "core/file_sys/vfs_real.h" | 20 | #include "core/file_sys/vfs_real.h" |
| @@ -23,12 +24,13 @@ | |||
| 23 | #include "core/hle/kernel/process.h" | 24 | #include "core/hle/kernel/process.h" |
| 24 | #include "core/hle/kernel/scheduler.h" | 25 | #include "core/hle/kernel/scheduler.h" |
| 25 | #include "core/hle/kernel/thread.h" | 26 | #include "core/hle/kernel/thread.h" |
| 27 | #include "core/hle/service/am/applets/software_keyboard.h" | ||
| 26 | #include "core/hle/service/service.h" | 28 | #include "core/hle/service/service.h" |
| 27 | #include "core/hle/service/sm/sm.h" | 29 | #include "core/hle/service/sm/sm.h" |
| 28 | #include "core/loader/loader.h" | 30 | #include "core/loader/loader.h" |
| 29 | #include "core/perf_stats.h" | 31 | #include "core/perf_stats.h" |
| 30 | #include "core/settings.h" | ||
| 31 | #include "core/telemetry_session.h" | 32 | #include "core/telemetry_session.h" |
| 33 | #include "frontend/applets/software_keyboard.h" | ||
| 32 | #include "video_core/debug_utils/debug_utils.h" | 34 | #include "video_core/debug_utils/debug_utils.h" |
| 33 | #include "video_core/gpu.h" | 35 | #include "video_core/gpu.h" |
| 34 | #include "video_core/renderer_base.h" | 36 | #include "video_core/renderer_base.h" |
| @@ -69,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 69 | 71 | ||
| 70 | return vfs->OpenFile(path, FileSys::Mode::Read); | 72 | return vfs->OpenFile(path, FileSys::Mode::Read); |
| 71 | } | 73 | } |
| 72 | |||
| 73 | /// Runs a CPU core while the system is powered on | ||
| 74 | void RunCpuCore(Cpu& cpu_state) { | ||
| 75 | while (Core::System::GetInstance().IsPoweredOn()) { | ||
| 76 | cpu_state.RunLoop(true); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } // Anonymous namespace | 74 | } // Anonymous namespace |
| 80 | 75 | ||
| 81 | struct System::Impl { | 76 | struct System::Impl { |
| 82 | Cpu& CurrentCpuCore() { | 77 | Cpu& CurrentCpuCore() { |
| 83 | if (Settings::values.use_multi_core) { | 78 | return cpu_core_manager.GetCurrentCore(); |
| 84 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 85 | ASSERT(search != thread_to_cpu.end()); | ||
| 86 | ASSERT(search->second); | ||
| 87 | return *search->second; | ||
| 88 | } | ||
| 89 | |||
| 90 | // Otherwise, use single-threaded mode active_core variable | ||
| 91 | return *cpu_cores[active_core]; | ||
| 92 | } | 79 | } |
| 93 | 80 | ||
| 94 | ResultStatus RunLoop(bool tight_loop) { | 81 | ResultStatus RunLoop(bool tight_loop) { |
| 95 | status = ResultStatus::Success; | 82 | status = ResultStatus::Success; |
| 96 | 83 | ||
| 97 | // Update thread_to_cpu in case Core 0 is run from a different host thread | 84 | cpu_core_manager.RunLoop(tight_loop); |
| 98 | thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get(); | ||
| 99 | |||
| 100 | if (GDBStub::IsServerEnabled()) { | ||
| 101 | GDBStub::HandlePacket(); | ||
| 102 | |||
| 103 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 104 | // execute. Otherwise, get out of the loop function. | ||
| 105 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 106 | if (GDBStub::GetCpuStepFlag()) { | ||
| 107 | tight_loop = false; | ||
| 108 | } else { | ||
| 109 | return ResultStatus::Success; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 115 | cpu_cores[active_core]->RunLoop(tight_loop); | ||
| 116 | if (Settings::values.use_multi_core) { | ||
| 117 | // Cores 1-3 are run on other threads in this mode | ||
| 118 | break; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | if (GDBStub::IsServerEnabled()) { | ||
| 123 | GDBStub::SetCpuStepFlag(false); | ||
| 124 | } | ||
| 125 | 85 | ||
| 126 | return status; | 86 | return status; |
| 127 | } | 87 | } |
| 128 | 88 | ||
| 129 | ResultStatus Init(Frontend::EmuWindow& emu_window) { | 89 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 130 | LOG_DEBUG(HW_Memory, "initialized OK"); | 90 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 131 | 91 | ||
| 132 | CoreTiming::Init(); | 92 | CoreTiming::Init(); |
| @@ -136,15 +96,13 @@ struct System::Impl { | |||
| 136 | if (virtual_filesystem == nullptr) | 96 | if (virtual_filesystem == nullptr) |
| 137 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); | 97 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); |
| 138 | 98 | ||
| 99 | /// Create default implementations of applets if one is not provided. | ||
| 100 | if (software_keyboard == nullptr) | ||
| 101 | software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); | ||
| 102 | |||
| 139 | auto main_process = Kernel::Process::Create(kernel, "main"); | 103 | auto main_process = Kernel::Process::Create(kernel, "main"); |
| 140 | kernel.MakeCurrentProcess(main_process.get()); | 104 | kernel.MakeCurrentProcess(main_process.get()); |
| 141 | 105 | ||
| 142 | cpu_barrier = std::make_unique<CpuBarrier>(); | ||
| 143 | cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); | ||
| 144 | for (std::size_t index = 0; index < cpu_cores.size(); ++index) { | ||
| 145 | cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index); | ||
| 146 | } | ||
| 147 | |||
| 148 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 106 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 149 | service_manager = std::make_shared<Service::SM::ServiceManager>(); | 107 | service_manager = std::make_shared<Service::SM::ServiceManager>(); |
| 150 | 108 | ||
| @@ -158,17 +116,8 @@ struct System::Impl { | |||
| 158 | 116 | ||
| 159 | gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); | 117 | gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); |
| 160 | 118 | ||
| 161 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | 119 | cpu_core_manager.Initialize(system); |
| 162 | // CPU core 0 is run on the main thread | 120 | is_powered_on = true; |
| 163 | thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get(); | ||
| 164 | if (Settings::values.use_multi_core) { | ||
| 165 | for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) { | ||
| 166 | cpu_core_threads[index] = | ||
| 167 | std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1])); | ||
| 168 | thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | LOG_DEBUG(Core, "Initialized OK"); | 121 | LOG_DEBUG(Core, "Initialized OK"); |
| 173 | 122 | ||
| 174 | // Reset counters and set time origin to current frame | 123 | // Reset counters and set time origin to current frame |
| @@ -178,7 +127,8 @@ struct System::Impl { | |||
| 178 | return ResultStatus::Success; | 127 | return ResultStatus::Success; |
| 179 | } | 128 | } |
| 180 | 129 | ||
| 181 | ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 130 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, |
| 131 | const std::string& filepath) { | ||
| 182 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); | 132 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); |
| 183 | 133 | ||
| 184 | if (!app_loader) { | 134 | if (!app_loader) { |
| @@ -195,7 +145,7 @@ struct System::Impl { | |||
| 195 | return ResultStatus::ErrorSystemMode; | 145 | return ResultStatus::ErrorSystemMode; |
| 196 | } | 146 | } |
| 197 | 147 | ||
| 198 | ResultStatus init_result{Init(emu_window)}; | 148 | ResultStatus init_result{Init(system, emu_window)}; |
| 199 | if (init_result != ResultStatus::Success) { | 149 | if (init_result != ResultStatus::Success) { |
| 200 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | 150 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", |
| 201 | static_cast<int>(init_result)); | 151 | static_cast<int>(init_result)); |
| @@ -225,6 +175,8 @@ struct System::Impl { | |||
| 225 | Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", | 175 | Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", |
| 226 | perf_results.frametime * 1000.0); | 176 | perf_results.frametime * 1000.0); |
| 227 | 177 | ||
| 178 | is_powered_on = false; | ||
| 179 | |||
| 228 | // Shutdown emulation session | 180 | // Shutdown emulation session |
| 229 | renderer.reset(); | 181 | renderer.reset(); |
| 230 | GDBStub::Shutdown(); | 182 | GDBStub::Shutdown(); |
| @@ -234,19 +186,7 @@ struct System::Impl { | |||
| 234 | gpu_core.reset(); | 186 | gpu_core.reset(); |
| 235 | 187 | ||
| 236 | // Close all CPU/threading state | 188 | // Close all CPU/threading state |
| 237 | cpu_barrier->NotifyEnd(); | 189 | cpu_core_manager.Shutdown(); |
| 238 | if (Settings::values.use_multi_core) { | ||
| 239 | for (auto& thread : cpu_core_threads) { | ||
| 240 | thread->join(); | ||
| 241 | thread.reset(); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | thread_to_cpu.clear(); | ||
| 245 | for (auto& cpu_core : cpu_cores) { | ||
| 246 | cpu_core.reset(); | ||
| 247 | } | ||
| 248 | cpu_exclusive_monitor.reset(); | ||
| 249 | cpu_barrier.reset(); | ||
| 250 | 190 | ||
| 251 | // Shutdown kernel and core timing | 191 | // Shutdown kernel and core timing |
| 252 | kernel.Shutdown(); | 192 | kernel.Shutdown(); |
| @@ -283,11 +223,11 @@ struct System::Impl { | |||
| 283 | std::unique_ptr<VideoCore::RendererBase> renderer; | 223 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 284 | std::unique_ptr<Tegra::GPU> gpu_core; | 224 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 285 | std::shared_ptr<Tegra::DebugContext> debug_context; | 225 | std::shared_ptr<Tegra::DebugContext> debug_context; |
| 286 | std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor; | 226 | CpuCoreManager cpu_core_manager; |
| 287 | std::unique_ptr<CpuBarrier> cpu_barrier; | 227 | bool is_powered_on = false; |
| 288 | std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; | 228 | |
| 289 | std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; | 229 | /// Frontend applets |
| 290 | std::size_t active_core{}; ///< Active core, only used in single thread mode | 230 | std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; |
| 291 | 231 | ||
| 292 | /// Service manager | 232 | /// Service manager |
| 293 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 233 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| @@ -298,9 +238,6 @@ struct System::Impl { | |||
| 298 | ResultStatus status = ResultStatus::Success; | 238 | ResultStatus status = ResultStatus::Success; |
| 299 | std::string status_details = ""; | 239 | std::string status_details = ""; |
| 300 | 240 | ||
| 301 | /// Map of guest threads to CPU cores | ||
| 302 | std::map<std::thread::id, Cpu*> thread_to_cpu; | ||
| 303 | |||
| 304 | Core::PerfStats perf_stats; | 241 | Core::PerfStats perf_stats; |
| 305 | Core::FrameLimiter frame_limiter; | 242 | Core::FrameLimiter frame_limiter; |
| 306 | }; | 243 | }; |
| @@ -325,17 +262,15 @@ System::ResultStatus System::SingleStep() { | |||
| 325 | } | 262 | } |
| 326 | 263 | ||
| 327 | void System::InvalidateCpuInstructionCaches() { | 264 | void System::InvalidateCpuInstructionCaches() { |
| 328 | for (auto& cpu : impl->cpu_cores) { | 265 | impl->cpu_core_manager.InvalidateAllInstructionCaches(); |
| 329 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 330 | } | ||
| 331 | } | 266 | } |
| 332 | 267 | ||
| 333 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 268 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { |
| 334 | return impl->Load(emu_window, filepath); | 269 | return impl->Load(*this, emu_window, filepath); |
| 335 | } | 270 | } |
| 336 | 271 | ||
| 337 | bool System::IsPoweredOn() const { | 272 | bool System::IsPoweredOn() const { |
| 338 | return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); | 273 | return impl->is_powered_on; |
| 339 | } | 274 | } |
| 340 | 275 | ||
| 341 | void System::PrepareReschedule() { | 276 | void System::PrepareReschedule() { |
| @@ -399,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const { | |||
| 399 | } | 334 | } |
| 400 | 335 | ||
| 401 | Cpu& System::CpuCore(std::size_t core_index) { | 336 | Cpu& System::CpuCore(std::size_t core_index) { |
| 402 | ASSERT(core_index < NUM_CPU_CORES); | 337 | return impl->cpu_core_manager.GetCore(core_index); |
| 403 | return *impl->cpu_cores[core_index]; | ||
| 404 | } | 338 | } |
| 405 | 339 | ||
| 406 | const Cpu& System::CpuCore(std::size_t core_index) const { | 340 | const Cpu& System::CpuCore(std::size_t core_index) const { |
| 407 | ASSERT(core_index < NUM_CPU_CORES); | 341 | ASSERT(core_index < NUM_CPU_CORES); |
| 408 | return *impl->cpu_cores[core_index]; | 342 | return impl->cpu_core_manager.GetCore(core_index); |
| 409 | } | 343 | } |
| 410 | 344 | ||
| 411 | ExclusiveMonitor& System::Monitor() { | 345 | ExclusiveMonitor& System::Monitor() { |
| 412 | return *impl->cpu_exclusive_monitor; | 346 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 413 | } | 347 | } |
| 414 | 348 | ||
| 415 | const ExclusiveMonitor& System::Monitor() const { | 349 | const ExclusiveMonitor& System::Monitor() const { |
| 416 | return *impl->cpu_exclusive_monitor; | 350 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 417 | } | 351 | } |
| 418 | 352 | ||
| 419 | Tegra::GPU& System::GPU() { | 353 | Tegra::GPU& System::GPU() { |
| @@ -488,8 +422,16 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const { | |||
| 488 | return impl->virtual_filesystem; | 422 | return impl->virtual_filesystem; |
| 489 | } | 423 | } |
| 490 | 424 | ||
| 425 | void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) { | ||
| 426 | impl->software_keyboard = std::move(applet); | ||
| 427 | } | ||
| 428 | |||
| 429 | const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const { | ||
| 430 | return *impl->software_keyboard; | ||
| 431 | } | ||
| 432 | |||
| 491 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 433 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 492 | return impl->Init(emu_window); | 434 | return impl->Init(*this, emu_window); |
| 493 | } | 435 | } |
| 494 | 436 | ||
| 495 | void System::Shutdown() { | 437 | void System::Shutdown() { |
diff --git a/src/core/core.h b/src/core/core.h index cfacceb81..be71bd437 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Core::Frontend { | 14 | namespace Core::Frontend { |
| 15 | class EmuWindow; | 15 | class EmuWindow; |
| 16 | class SoftwareKeyboardApplet; | ||
| 16 | } // namespace Core::Frontend | 17 | } // namespace Core::Frontend |
| 17 | 18 | ||
| 18 | namespace FileSys { | 19 | namespace FileSys { |
| @@ -236,6 +237,10 @@ public: | |||
| 236 | 237 | ||
| 237 | std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; | 238 | std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; |
| 238 | 239 | ||
| 240 | void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet); | ||
| 241 | |||
| 242 | const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; | ||
| 243 | |||
| 239 | private: | 244 | private: |
| 240 | System(); | 245 | System(); |
| 241 | 246 | ||
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp new file mode 100644 index 000000000..769a6fefa --- /dev/null +++ b/src/core/cpu_core_manager.cpp | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/arm/exclusive_monitor.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/core_cpu.h" | ||
| 9 | #include "core/cpu_core_manager.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | namespace { | ||
| 15 | void RunCpuCore(const System& system, Cpu& cpu_state) { | ||
| 16 | while (system.IsPoweredOn()) { | ||
| 17 | cpu_state.RunLoop(true); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | CpuCoreManager::CpuCoreManager() = default; | ||
| 23 | CpuCoreManager::~CpuCoreManager() = default; | ||
| 24 | |||
| 25 | void CpuCoreManager::Initialize(System& system) { | ||
| 26 | barrier = std::make_unique<CpuBarrier>(); | ||
| 27 | exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); | ||
| 28 | |||
| 29 | for (std::size_t index = 0; index < cores.size(); ++index) { | ||
| 30 | cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index); | ||
| 31 | } | ||
| 32 | |||
| 33 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | ||
| 34 | // CPU core 0 is run on the main thread | ||
| 35 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 36 | if (!Settings::values.use_multi_core) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | for (std::size_t index = 0; index < core_threads.size(); ++index) { | ||
| 41 | core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system), | ||
| 42 | std::ref(*cores[index + 1])); | ||
| 43 | thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get(); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | void CpuCoreManager::Shutdown() { | ||
| 48 | barrier->NotifyEnd(); | ||
| 49 | if (Settings::values.use_multi_core) { | ||
| 50 | for (auto& thread : core_threads) { | ||
| 51 | thread->join(); | ||
| 52 | thread.reset(); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | thread_to_cpu.clear(); | ||
| 57 | for (auto& cpu_core : cores) { | ||
| 58 | cpu_core.reset(); | ||
| 59 | } | ||
| 60 | |||
| 61 | exclusive_monitor.reset(); | ||
| 62 | barrier.reset(); | ||
| 63 | } | ||
| 64 | |||
| 65 | Cpu& CpuCoreManager::GetCore(std::size_t index) { | ||
| 66 | return *cores.at(index); | ||
| 67 | } | ||
| 68 | |||
| 69 | const Cpu& CpuCoreManager::GetCore(std::size_t index) const { | ||
| 70 | return *cores.at(index); | ||
| 71 | } | ||
| 72 | |||
| 73 | ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { | ||
| 74 | return *exclusive_monitor; | ||
| 75 | } | ||
| 76 | |||
| 77 | const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { | ||
| 78 | return *exclusive_monitor; | ||
| 79 | } | ||
| 80 | |||
| 81 | Cpu& CpuCoreManager::GetCurrentCore() { | ||
| 82 | if (Settings::values.use_multi_core) { | ||
| 83 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 84 | ASSERT(search != thread_to_cpu.end()); | ||
| 85 | ASSERT(search->second); | ||
| 86 | return *search->second; | ||
| 87 | } | ||
| 88 | |||
| 89 | // Otherwise, use single-threaded mode active_core variable | ||
| 90 | return *cores[active_core]; | ||
| 91 | } | ||
| 92 | |||
| 93 | const Cpu& CpuCoreManager::GetCurrentCore() const { | ||
| 94 | if (Settings::values.use_multi_core) { | ||
| 95 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 96 | ASSERT(search != thread_to_cpu.end()); | ||
| 97 | ASSERT(search->second); | ||
| 98 | return *search->second; | ||
| 99 | } | ||
| 100 | |||
| 101 | // Otherwise, use single-threaded mode active_core variable | ||
| 102 | return *cores[active_core]; | ||
| 103 | } | ||
| 104 | |||
| 105 | void CpuCoreManager::RunLoop(bool tight_loop) { | ||
| 106 | // Update thread_to_cpu in case Core 0 is run from a different host thread | ||
| 107 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 108 | |||
| 109 | if (GDBStub::IsServerEnabled()) { | ||
| 110 | GDBStub::HandlePacket(); | ||
| 111 | |||
| 112 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 113 | // execute. Otherwise, get out of the loop function. | ||
| 114 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 115 | if (GDBStub::GetCpuStepFlag()) { | ||
| 116 | tight_loop = false; | ||
| 117 | } else { | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 124 | cores[active_core]->RunLoop(tight_loop); | ||
| 125 | if (Settings::values.use_multi_core) { | ||
| 126 | // Cores 1-3 are run on other threads in this mode | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | if (GDBStub::IsServerEnabled()) { | ||
| 132 | GDBStub::SetCpuStepFlag(false); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | void CpuCoreManager::InvalidateAllInstructionCaches() { | ||
| 137 | for (auto& cpu : cores) { | ||
| 138 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | } // namespace Core | ||
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h new file mode 100644 index 000000000..a4d70ec56 --- /dev/null +++ b/src/core/cpu_core_manager.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <map> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | class Cpu; | ||
| 15 | class CpuBarrier; | ||
| 16 | class ExclusiveMonitor; | ||
| 17 | class System; | ||
| 18 | |||
| 19 | class CpuCoreManager { | ||
| 20 | public: | ||
| 21 | CpuCoreManager(); | ||
| 22 | CpuCoreManager(const CpuCoreManager&) = delete; | ||
| 23 | CpuCoreManager(CpuCoreManager&&) = delete; | ||
| 24 | |||
| 25 | ~CpuCoreManager(); | ||
| 26 | |||
| 27 | CpuCoreManager& operator=(const CpuCoreManager&) = delete; | ||
| 28 | CpuCoreManager& operator=(CpuCoreManager&&) = delete; | ||
| 29 | |||
| 30 | void Initialize(System& system); | ||
| 31 | void Shutdown(); | ||
| 32 | |||
| 33 | Cpu& GetCore(std::size_t index); | ||
| 34 | const Cpu& GetCore(std::size_t index) const; | ||
| 35 | |||
| 36 | Cpu& GetCurrentCore(); | ||
| 37 | const Cpu& GetCurrentCore() const; | ||
| 38 | |||
| 39 | ExclusiveMonitor& GetExclusiveMonitor(); | ||
| 40 | const ExclusiveMonitor& GetExclusiveMonitor() const; | ||
| 41 | |||
| 42 | void RunLoop(bool tight_loop); | ||
| 43 | |||
| 44 | void InvalidateAllInstructionCaches(); | ||
| 45 | |||
| 46 | private: | ||
| 47 | static constexpr std::size_t NUM_CPU_CORES = 4; | ||
| 48 | |||
| 49 | std::unique_ptr<ExclusiveMonitor> exclusive_monitor; | ||
| 50 | std::unique_ptr<CpuBarrier> barrier; | ||
| 51 | std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores; | ||
| 52 | std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads; | ||
| 53 | std::size_t active_core{}; ///< Active core, only used in single thread mode | ||
| 54 | |||
| 55 | /// Map of guest threads to CPU cores | ||
| 56 | std::map<std::thread::id, Cpu*> thread_to_cpu; | ||
| 57 | }; | ||
| 58 | |||
| 59 | } // namespace Core | ||
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 904afa039..ca12fb4ab 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { | |||
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | std::vector<TicketRaw> out; | 248 | std::vector<TicketRaw> out; |
| 249 | u32 magic{}; | ||
| 250 | for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { | 249 | for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { |
| 251 | if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && | 250 | if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && |
| 252 | buffer[offset + 3] == 0x0) { | 251 | buffer[offset + 3] == 0x0) { |
| @@ -794,7 +793,7 @@ void KeyManager::DeriveBase() { | |||
| 794 | 793 | ||
| 795 | void KeyManager::DeriveETicket(PartitionDataManager& data) { | 794 | void KeyManager::DeriveETicket(PartitionDataManager& data) { |
| 796 | // ETicket keys | 795 | // ETicket keys |
| 797 | const auto es = Service::FileSystem::GetUnionContents()->GetEntry( | 796 | const auto es = Service::FileSystem::GetUnionContents().GetEntry( |
| 798 | 0x0100000000000033, FileSys::ContentRecordType::Program); | 797 | 0x0100000000000033, FileSys::ContentRecordType::Program); |
| 799 | 798 | ||
| 800 | if (es == nullptr) | 799 | if (es == nullptr) |
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 76a2b7e86..e29f70b3a 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -8,8 +8,9 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_) | 11 | BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) |
| 12 | : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), | 12 | : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), |
| 13 | dump_root(std::move(dump_root_)), | ||
| 13 | sysnand_cache(std::make_unique<RegisteredCache>( | 14 | sysnand_cache(std::make_unique<RegisteredCache>( |
| 14 | GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), | 15 | GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), |
| 15 | usrnand_cache(std::make_unique<RegisteredCache>( | 16 | usrnand_cache(std::make_unique<RegisteredCache>( |
| @@ -32,4 +33,10 @@ VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const { | |||
| 32 | return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); | 33 | return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 36 | VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const { | ||
| 37 | if (title_id == 0) | ||
| 38 | return nullptr; | ||
| 39 | return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id)); | ||
| 40 | } | ||
| 41 | |||
| 35 | } // namespace FileSys | 42 | } // namespace FileSys |
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index 364d309bd..453c11ad2 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h | |||
| @@ -17,17 +17,19 @@ class RegisteredCache; | |||
| 17 | /// registered caches. | 17 | /// registered caches. |
| 18 | class BISFactory { | 18 | class BISFactory { |
| 19 | public: | 19 | public: |
| 20 | explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); | 20 | explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root); |
| 21 | ~BISFactory(); | 21 | ~BISFactory(); |
| 22 | 22 | ||
| 23 | RegisteredCache* GetSystemNANDContents() const; | 23 | RegisteredCache* GetSystemNANDContents() const; |
| 24 | RegisteredCache* GetUserNANDContents() const; | 24 | RegisteredCache* GetUserNANDContents() const; |
| 25 | 25 | ||
| 26 | VirtualDir GetModificationLoadRoot(u64 title_id) const; | 26 | VirtualDir GetModificationLoadRoot(u64 title_id) const; |
| 27 | VirtualDir GetModificationDumpRoot(u64 title_id) const; | ||
| 27 | 28 | ||
| 28 | private: | 29 | private: |
| 29 | VirtualDir nand_root; | 30 | VirtualDir nand_root; |
| 30 | VirtualDir load_root; | 31 | VirtualDir load_root; |
| 32 | VirtualDir dump_root; | ||
| 31 | 33 | ||
| 32 | std::unique_ptr<RegisteredCache> sysnand_cache; | 34 | std::unique_ptr<RegisteredCache> sysnand_cache; |
| 33 | std::unique_ptr<RegisteredCache> usrnand_cache; | 35 | std::unique_ptr<RegisteredCache> usrnand_cache; |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 1ece55731..2c145bd09 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | |||
| 176 | for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { | 176 | for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { |
| 177 | if (file->GetExtension() != "nca") | 177 | if (file->GetExtension() != "nca") |
| 178 | continue; | 178 | continue; |
| 179 | auto nca = std::make_shared<NCA>(file); | 179 | auto nca = std::make_shared<NCA>(file, nullptr, 0, keys); |
| 180 | // TODO(DarkLordZach): Add proper Rev1+ Support | 180 | // TODO(DarkLordZach): Add proper Rev1+ Support |
| 181 | if (nca->IsUpdate()) | 181 | if (nca->IsUpdate()) |
| 182 | continue; | 182 | continue; |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 8f62571cf..a350496f7 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 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/crypto/key_manager.h" | ||
| 12 | #include "core/file_sys/vfs.h" | 13 | #include "core/file_sys/vfs.h" |
| 13 | 14 | ||
| 14 | namespace Loader { | 15 | namespace Loader { |
| @@ -31,7 +32,18 @@ enum class GamecardSize : u8 { | |||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | struct GamecardInfo { | 34 | struct GamecardInfo { |
| 34 | std::array<u8, 0x70> data; | 35 | u64_le firmware_version; |
| 36 | u32_le access_control_flags; | ||
| 37 | u32_le read_wait_time1; | ||
| 38 | u32_le read_wait_time2; | ||
| 39 | u32_le write_wait_time1; | ||
| 40 | u32_le write_wait_time2; | ||
| 41 | u32_le firmware_mode; | ||
| 42 | u32_le cup_version; | ||
| 43 | std::array<u8, 4> reserved1; | ||
| 44 | u64_le update_partition_hash; | ||
| 45 | u64_le cup_id; | ||
| 46 | std::array<u8, 0x38> reserved2; | ||
| 35 | }; | 47 | }; |
| 36 | static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size."); | 48 | static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size."); |
| 37 | 49 | ||
| @@ -107,5 +119,7 @@ private: | |||
| 107 | std::shared_ptr<NSP> secure_partition; | 119 | std::shared_ptr<NSP> secure_partition; |
| 108 | std::shared_ptr<NCA> program; | 120 | std::shared_ptr<NCA> program; |
| 109 | std::vector<std::shared_ptr<NCA>> ncas; | 121 | std::vector<std::shared_ptr<NCA>> ncas; |
| 122 | |||
| 123 | Core::Crypto::KeyManager keys; | ||
| 110 | }; | 124 | }; |
| 111 | } // namespace FileSys | 125 | } // namespace FileSys |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index b46fe893c..19b6f8600 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) { | |||
| 101 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); | 101 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) | 104 | NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset, |
| 105 | : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { | 105 | Core::Crypto::KeyManager keys_) |
| 106 | : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) { | ||
| 106 | if (file == nullptr) { | 107 | if (file == nullptr) { |
| 107 | status = Loader::ResultStatus::ErrorNullFile; | 108 | status = Loader::ResultStatus::ErrorNullFile; |
| 108 | return; | 109 | return; |
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 4bba55607..99294cbb4 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) { | |||
| 79 | class NCA : public ReadOnlyVfsDirectory { | 79 | class NCA : public ReadOnlyVfsDirectory { |
| 80 | public: | 80 | public: |
| 81 | explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, | 81 | explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, |
| 82 | u64 bktr_base_ivfc_offset = 0); | 82 | u64 bktr_base_ivfc_offset = 0, |
| 83 | Core::Crypto::KeyManager keys = Core::Crypto::KeyManager()); | ||
| 83 | ~NCA() override; | 84 | ~NCA() override; |
| 84 | 85 | ||
| 85 | Loader::ResultStatus GetStatus() const; | 86 | Loader::ResultStatus GetStatus() const; |
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index a012c2be9..e065e592f 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp | |||
| @@ -8,13 +8,23 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | const std::array<const char*, 15> LANGUAGE_NAMES = { | 11 | const std::array<const char*, 15> LANGUAGE_NAMES{{ |
| 12 | "AmericanEnglish", "BritishEnglish", "Japanese", | 12 | "AmericanEnglish", |
| 13 | "French", "German", "LatinAmericanSpanish", | 13 | "BritishEnglish", |
| 14 | "Spanish", "Italian", "Dutch", | 14 | "Japanese", |
| 15 | "CanadianFrench", "Portugese", "Russian", | 15 | "French", |
| 16 | "Korean", "Taiwanese", "Chinese", | 16 | "German", |
| 17 | }; | 17 | "LatinAmericanSpanish", |
| 18 | "Spanish", | ||
| 19 | "Italian", | ||
| 20 | "Dutch", | ||
| 21 | "CanadianFrench", | ||
| 22 | "Portuguese", | ||
| 23 | "Russian", | ||
| 24 | "Korean", | ||
| 25 | "Taiwanese", | ||
| 26 | "Chinese", | ||
| 27 | }}; | ||
| 18 | 28 | ||
| 19 | std::string LanguageEntry::GetApplicationName() const { | 29 | std::string LanguageEntry::GetApplicationName() const { |
| 20 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), | 30 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), |
| @@ -66,4 +76,10 @@ std::string NACP::GetVersionString() const { | |||
| 66 | return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), | 76 | return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), |
| 67 | raw->version_string.size()); | 77 | raw->version_string.size()); |
| 68 | } | 78 | } |
| 79 | |||
| 80 | std::vector<u8> NACP::GetRawBytes() const { | ||
| 81 | std::vector<u8> out(sizeof(RawNACP)); | ||
| 82 | std::memcpy(out.data(), raw.get(), sizeof(RawNACP)); | ||
| 83 | return out; | ||
| 84 | } | ||
| 69 | } // namespace FileSys | 85 | } // namespace FileSys |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 141f7e056..bfaad46b4 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -81,6 +81,7 @@ public: | |||
| 81 | u64 GetTitleId() const; | 81 | u64 GetTitleId() const; |
| 82 | u64 GetDLCBaseTitleId() const; | 82 | u64 GetDLCBaseTitleId() const; |
| 83 | std::string GetVersionString() const; | 83 | std::string GetVersionString() const; |
| 84 | std::vector<u8> GetRawBytes() const; | ||
| 84 | 85 | ||
| 85 | private: | 86 | private: |
| 86 | std::unique_ptr<RawNACP> raw; | 87 | std::unique_ptr<RawNACP> raw; |
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index fea0593c7..e4a4ee4ab 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h | |||
| @@ -8,25 +8,10 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | namespace ErrCodes { | 11 | constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1}; |
| 12 | enum { | 12 | constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002}; |
| 13 | NotFound = 1, | 13 | constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001}; |
| 14 | TitleNotFound = 1002, | 14 | constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061}; |
| 15 | SdCardNotFound = 2001, | 15 | constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062}; |
| 16 | RomFSNotFound = 2520, | ||
| 17 | }; | ||
| 18 | } | ||
| 19 | |||
| 20 | constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound); | ||
| 21 | |||
| 22 | // TODO(bunnei): Replace these with correct errors for Switch OS | ||
| 23 | constexpr ResultCode ERROR_INVALID_PATH(-1); | ||
| 24 | constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1); | ||
| 25 | constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1); | ||
| 26 | constexpr ResultCode ERROR_FILE_NOT_FOUND(-1); | ||
| 27 | constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1); | ||
| 28 | constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1); | ||
| 29 | constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1); | ||
| 30 | constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1); | ||
| 31 | 16 | ||
| 32 | } // namespace FileSys | 17 | } // namespace FileSys |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 0c1156989..6b14e08be 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -19,12 +19,18 @@ | |||
| 19 | #include "core/file_sys/vfs_vector.h" | 19 | #include "core/file_sys/vfs_vector.h" |
| 20 | #include "core/hle/service/filesystem/filesystem.h" | 20 | #include "core/hle/service/filesystem/filesystem.h" |
| 21 | #include "core/loader/loader.h" | 21 | #include "core/loader/loader.h" |
| 22 | #include "core/settings.h" | ||
| 22 | 23 | ||
| 23 | namespace FileSys { | 24 | namespace FileSys { |
| 24 | 25 | ||
| 25 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; | 26 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; |
| 26 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | 27 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; |
| 27 | 28 | ||
| 29 | constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ | ||
| 30 | "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", | ||
| 31 | "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", | ||
| 32 | }; | ||
| 33 | |||
| 28 | struct NSOBuildHeader { | 34 | struct NSOBuildHeader { |
| 29 | u32_le magic; | 35 | u32_le magic; |
| 30 | INSERT_PADDING_BYTES(0x3C); | 36 | INSERT_PADDING_BYTES(0x3C); |
| @@ -56,19 +62,52 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 56 | if (exefs == nullptr) | 62 | if (exefs == nullptr) |
| 57 | return exefs; | 63 | return exefs; |
| 58 | 64 | ||
| 65 | if (Settings::values.dump_exefs) { | ||
| 66 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); | ||
| 67 | const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); | ||
| 68 | if (dump_dir != nullptr) { | ||
| 69 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); | ||
| 70 | VfsRawCopyD(exefs, exefs_dir); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 59 | const auto installed = Service::FileSystem::GetUnionContents(); | 74 | const auto installed = Service::FileSystem::GetUnionContents(); |
| 60 | 75 | ||
| 61 | // Game Updates | 76 | // Game Updates |
| 62 | const auto update_tid = GetUpdateTitleID(title_id); | 77 | const auto update_tid = GetUpdateTitleID(title_id); |
| 63 | const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); | 78 | const auto update = installed.GetEntry(update_tid, ContentRecordType::Program); |
| 64 | 79 | ||
| 65 | if (update != nullptr && update->GetExeFS() != nullptr && | 80 | if (update != nullptr && update->GetExeFS() != nullptr && |
| 66 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | 81 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { |
| 67 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", | 82 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", |
| 68 | FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); | 83 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); |
| 69 | exefs = update->GetExeFS(); | 84 | exefs = update->GetExeFS(); |
| 70 | } | 85 | } |
| 71 | 86 | ||
| 87 | // LayeredExeFS | ||
| 88 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | ||
| 89 | if (load_dir != nullptr && load_dir->GetSize() > 0) { | ||
| 90 | auto patch_dirs = load_dir->GetSubdirectories(); | ||
| 91 | std::sort( | ||
| 92 | patch_dirs.begin(), patch_dirs.end(), | ||
| 93 | [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); | ||
| 94 | |||
| 95 | std::vector<VirtualDir> layers; | ||
| 96 | layers.reserve(patch_dirs.size() + 1); | ||
| 97 | for (const auto& subdir : patch_dirs) { | ||
| 98 | auto exefs_dir = subdir->GetSubdirectory("exefs"); | ||
| 99 | if (exefs_dir != nullptr) | ||
| 100 | layers.push_back(std::move(exefs_dir)); | ||
| 101 | } | ||
| 102 | layers.push_back(exefs); | ||
| 103 | |||
| 104 | auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); | ||
| 105 | if (layered != nullptr) { | ||
| 106 | LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully"); | ||
| 107 | exefs = std::move(layered); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 72 | return exefs; | 111 | return exefs; |
| 73 | } | 112 | } |
| 74 | 113 | ||
| @@ -119,6 +158,18 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const { | |||
| 119 | const auto build_id_raw = Common::HexArrayToString(header.build_id); | 158 | const auto build_id_raw = Common::HexArrayToString(header.build_id); |
| 120 | const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); | 159 | const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); |
| 121 | 160 | ||
| 161 | if (Settings::values.dump_nso) { | ||
| 162 | LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id); | ||
| 163 | const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); | ||
| 164 | if (dump_dir != nullptr) { | ||
| 165 | const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); | ||
| 166 | const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id)); | ||
| 167 | |||
| 168 | file->Resize(nso.size()); | ||
| 169 | file->WriteBytes(nso); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 122 | LOG_INFO(Loader, "Patching NSO for build_id={}", build_id); | 173 | LOG_INFO(Loader, "Patching NSO for build_id={}", build_id); |
| 123 | 174 | ||
| 124 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | 175 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
| @@ -230,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 230 | 281 | ||
| 231 | // Game Updates | 282 | // Game Updates |
| 232 | const auto update_tid = GetUpdateTitleID(title_id); | 283 | const auto update_tid = GetUpdateTitleID(title_id); |
| 233 | const auto update = installed->GetEntryRaw(update_tid, type); | 284 | const auto update = installed.GetEntryRaw(update_tid, type); |
| 234 | if (update != nullptr) { | 285 | if (update != nullptr) { |
| 235 | const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); | 286 | const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); |
| 236 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && | 287 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && |
| 237 | new_nca->GetRomFS() != nullptr) { | 288 | new_nca->GetRomFS() != nullptr) { |
| 238 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", | 289 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", |
| 239 | FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); | 290 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); |
| 240 | romfs = new_nca->GetRomFS(); | 291 | romfs = new_nca->GetRomFS(); |
| 241 | } | 292 | } |
| 242 | } else if (update_raw != nullptr) { | 293 | } else if (update_raw != nullptr) { |
| @@ -278,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam | |||
| 278 | if (nacp != nullptr) { | 329 | if (nacp != nullptr) { |
| 279 | out.insert_or_assign("Update", nacp->GetVersionString()); | 330 | out.insert_or_assign("Update", nacp->GetVersionString()); |
| 280 | } else { | 331 | } else { |
| 281 | if (installed->HasEntry(update_tid, ContentRecordType::Program)) { | 332 | if (installed.HasEntry(update_tid, ContentRecordType::Program)) { |
| 282 | const auto meta_ver = installed->GetEntryVersion(update_tid); | 333 | const auto meta_ver = installed.GetEntryVersion(update_tid); |
| 283 | if (meta_ver.value_or(0) == 0) { | 334 | if (meta_ver.value_or(0) == 0) { |
| 284 | out.insert_or_assign("Update", ""); | 335 | out.insert_or_assign("Update", ""); |
| 285 | } else { | 336 | } else { |
| @@ -301,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam | |||
| 301 | if (IsDirValidAndNonEmpty(exefs_dir)) { | 352 | if (IsDirValidAndNonEmpty(exefs_dir)) { |
| 302 | bool ips = false; | 353 | bool ips = false; |
| 303 | bool ipswitch = false; | 354 | bool ipswitch = false; |
| 355 | bool layeredfs = false; | ||
| 304 | 356 | ||
| 305 | for (const auto& file : exefs_dir->GetFiles()) { | 357 | for (const auto& file : exefs_dir->GetFiles()) { |
| 306 | if (file->GetExtension() == "ips") | 358 | if (file->GetExtension() == "ips") { |
| 307 | ips = true; | 359 | ips = true; |
| 308 | else if (file->GetExtension() == "pchtxt") | 360 | } else if (file->GetExtension() == "pchtxt") { |
| 309 | ipswitch = true; | 361 | ipswitch = true; |
| 362 | } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(), | ||
| 363 | file->GetName()) != EXEFS_FILE_NAMES.end()) { | ||
| 364 | layeredfs = true; | ||
| 365 | } | ||
| 310 | } | 366 | } |
| 311 | 367 | ||
| 312 | if (ips) | 368 | if (ips) |
| 313 | AppendCommaIfNotEmpty(types, "IPS"); | 369 | AppendCommaIfNotEmpty(types, "IPS"); |
| 314 | if (ipswitch) | 370 | if (ipswitch) |
| 315 | AppendCommaIfNotEmpty(types, "IPSwitch"); | 371 | AppendCommaIfNotEmpty(types, "IPSwitch"); |
| 372 | if (layeredfs) | ||
| 373 | AppendCommaIfNotEmpty(types, "LayeredExeFS"); | ||
| 316 | } | 374 | } |
| 317 | if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) | 375 | if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) |
| 318 | AppendCommaIfNotEmpty(types, "LayeredFS"); | 376 | AppendCommaIfNotEmpty(types, "LayeredFS"); |
| @@ -325,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam | |||
| 325 | } | 383 | } |
| 326 | 384 | ||
| 327 | // DLC | 385 | // DLC |
| 328 | const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); | 386 | const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); |
| 329 | std::vector<RegisteredCacheEntry> dlc_match; | 387 | std::vector<RegisteredCacheEntry> dlc_match; |
| 330 | dlc_match.reserve(dlc_entries.size()); | 388 | dlc_match.reserve(dlc_entries.size()); |
| 331 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), | 389 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), |
| 332 | [this, &installed](const RegisteredCacheEntry& entry) { | 390 | [this, &installed](const RegisteredCacheEntry& entry) { |
| 333 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && | 391 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && |
| 334 | installed->GetEntry(entry)->GetStatus() == | 392 | installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; |
| 335 | Loader::ResultStatus::Success; | ||
| 336 | }); | 393 | }); |
| 337 | if (!dlc_match.empty()) { | 394 | if (!dlc_match.empty()) { |
| 338 | // Ensure sorted so DLC IDs show in order. | 395 | // Ensure sorted so DLC IDs show in order. |
| @@ -353,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam | |||
| 353 | std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { | 410 | std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { |
| 354 | const auto installed{Service::FileSystem::GetUnionContents()}; | 411 | const auto installed{Service::FileSystem::GetUnionContents()}; |
| 355 | 412 | ||
| 356 | const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); | 413 | const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control); |
| 357 | if (base_control_nca == nullptr) | 414 | if (base_control_nca == nullptr) |
| 358 | return {}; | 415 | return {}; |
| 359 | 416 | ||
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 96302a241..128199063 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -106,40 +106,42 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { | |||
| 106 | 106 | ||
| 107 | VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | 107 | VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, |
| 108 | std::string_view path) const { | 108 | std::string_view path) const { |
| 109 | if (dir->GetFileRelative(path) != nullptr) | 109 | const auto file = dir->GetFileRelative(path); |
| 110 | return dir->GetFileRelative(path); | 110 | if (file != nullptr) { |
| 111 | if (dir->GetDirectoryRelative(path) != nullptr) { | 111 | return file; |
| 112 | const auto nca_dir = dir->GetDirectoryRelative(path); | 112 | } |
| 113 | VirtualFile file = nullptr; | ||
| 114 | |||
| 115 | const auto files = nca_dir->GetFiles(); | ||
| 116 | if (files.size() == 1 && files[0]->GetName() == "00") { | ||
| 117 | file = files[0]; | ||
| 118 | } else { | ||
| 119 | std::vector<VirtualFile> concat; | ||
| 120 | // Since the files are a two-digit hex number, max is FF. | ||
| 121 | for (std::size_t i = 0; i < 0x100; ++i) { | ||
| 122 | auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); | ||
| 123 | if (next != nullptr) { | ||
| 124 | concat.push_back(std::move(next)); | ||
| 125 | } else { | ||
| 126 | next = nca_dir->GetFile(fmt::format("{:02x}", i)); | ||
| 127 | if (next != nullptr) | ||
| 128 | concat.push_back(std::move(next)); | ||
| 129 | else | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | 113 | ||
| 134 | if (concat.empty()) | 114 | const auto nca_dir = dir->GetDirectoryRelative(path); |
| 135 | return nullptr; | 115 | if (nca_dir == nullptr) { |
| 116 | return nullptr; | ||
| 117 | } | ||
| 118 | |||
| 119 | const auto files = nca_dir->GetFiles(); | ||
| 120 | if (files.size() == 1 && files[0]->GetName() == "00") { | ||
| 121 | return files[0]; | ||
| 122 | } | ||
| 136 | 123 | ||
| 137 | file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); | 124 | std::vector<VirtualFile> concat; |
| 125 | // Since the files are a two-digit hex number, max is FF. | ||
| 126 | for (std::size_t i = 0; i < 0x100; ++i) { | ||
| 127 | auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); | ||
| 128 | if (next != nullptr) { | ||
| 129 | concat.push_back(std::move(next)); | ||
| 130 | } else { | ||
| 131 | next = nca_dir->GetFile(fmt::format("{:02x}", i)); | ||
| 132 | if (next != nullptr) { | ||
| 133 | concat.push_back(std::move(next)); | ||
| 134 | } else { | ||
| 135 | break; | ||
| 136 | } | ||
| 138 | } | 137 | } |
| 138 | } | ||
| 139 | 139 | ||
| 140 | return file; | 140 | if (concat.empty()) { |
| 141 | return nullptr; | ||
| 141 | } | 142 | } |
| 142 | return nullptr; | 143 | |
| 144 | return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); | ||
| 143 | } | 145 | } |
| 144 | 146 | ||
| 145 | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { | 147 | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { |
| @@ -225,7 +227,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) { | |||
| 225 | 227 | ||
| 226 | if (file == nullptr) | 228 | if (file == nullptr) |
| 227 | continue; | 229 | continue; |
| 228 | const auto nca = std::make_shared<NCA>(parser(file, id)); | 230 | const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys); |
| 229 | if (nca->GetStatus() != Loader::ResultStatus::Success || | 231 | if (nca->GetStatus() != Loader::ResultStatus::Success || |
| 230 | nca->GetType() != NCAContentType::Meta) { | 232 | nca->GetType() != NCAContentType::Meta) { |
| 231 | continue; | 233 | continue; |
| @@ -315,7 +317,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t | |||
| 315 | const auto raw = GetEntryRaw(title_id, type); | 317 | const auto raw = GetEntryRaw(title_id, type); |
| 316 | if (raw == nullptr) | 318 | if (raw == nullptr) |
| 317 | return nullptr; | 319 | return nullptr; |
| 318 | return std::make_unique<NCA>(raw); | 320 | return std::make_unique<NCA>(raw, nullptr, 0, keys); |
| 319 | } | 321 | } |
| 320 | 322 | ||
| 321 | std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { | 323 | std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { |
| @@ -378,22 +380,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( | |||
| 378 | return out; | 380 | return out; |
| 379 | } | 381 | } |
| 380 | 382 | ||
| 381 | static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { | 383 | static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) { |
| 382 | const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); | 384 | const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); |
| 383 | if (file == nullptr) | 385 | if (file == nullptr) |
| 384 | return nullptr; | 386 | return nullptr; |
| 385 | return std::make_shared<NCA>(file); | 387 | return std::make_shared<NCA>(file); |
| 386 | } | 388 | } |
| 387 | 389 | ||
| 388 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, | 390 | InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists, |
| 389 | const VfsCopyFunction& copy) { | 391 | const VfsCopyFunction& copy) { |
| 390 | return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); | 392 | return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); |
| 391 | } | 393 | } |
| 392 | 394 | ||
| 393 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, | 395 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, |
| 394 | const VfsCopyFunction& copy) { | 396 | const VfsCopyFunction& copy) { |
| 395 | const auto& ncas = nsp->GetNCAsCollapsed(); | 397 | const auto ncas = nsp.GetNCAsCollapsed(); |
| 396 | const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { | 398 | const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) { |
| 397 | return nca->GetType() == NCAContentType::Meta; | 399 | return nca->GetType() == NCAContentType::Meta; |
| 398 | }); | 400 | }); |
| 399 | 401 | ||
| @@ -407,7 +409,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 407 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | 409 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |
| 408 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); | 410 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); |
| 409 | 411 | ||
| 410 | const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); | 412 | const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); |
| 411 | if (res != InstallResult::Success) | 413 | if (res != InstallResult::Success) |
| 412 | return res; | 414 | return res; |
| 413 | 415 | ||
| @@ -419,7 +421,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 419 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); | 421 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); |
| 420 | if (nca == nullptr) | 422 | if (nca == nullptr) |
| 421 | return InstallResult::ErrorCopyFailed; | 423 | return InstallResult::ErrorCopyFailed; |
| 422 | const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); | 424 | const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); |
| 423 | if (res2 != InstallResult::Success) | 425 | if (res2 != InstallResult::Success) |
| 424 | return res2; | 426 | return res2; |
| 425 | } | 427 | } |
| @@ -428,21 +430,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 428 | return InstallResult::Success; | 430 | return InstallResult::Success; |
| 429 | } | 431 | } |
| 430 | 432 | ||
| 431 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 433 | InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, |
| 432 | bool overwrite_if_exists, const VfsCopyFunction& copy) { | 434 | bool overwrite_if_exists, const VfsCopyFunction& copy) { |
| 433 | CNMTHeader header{ | 435 | CNMTHeader header{ |
| 434 | nca->GetTitleId(), ///< Title ID | 436 | nca.GetTitleId(), ///< Title ID |
| 435 | 0, ///< Ignore/Default title version | 437 | 0, ///< Ignore/Default title version |
| 436 | type, ///< Type | 438 | type, ///< Type |
| 437 | {}, ///< Padding | 439 | {}, ///< Padding |
| 438 | 0x10, ///< Default table offset | 440 | 0x10, ///< Default table offset |
| 439 | 1, ///< 1 Content Entry | 441 | 1, ///< 1 Content Entry |
| 440 | 0, ///< No Meta Entries | 442 | 0, ///< No Meta Entries |
| 441 | {}, ///< Padding | 443 | {}, ///< Padding |
| 442 | }; | 444 | }; |
| 443 | OptionalHeader opt_header{0, 0}; | 445 | OptionalHeader opt_header{0, 0}; |
| 444 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}}; | 446 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}}; |
| 445 | const auto& data = nca->GetBaseFile()->ReadBytes(0x100000); | 447 | const auto& data = nca.GetBaseFile()->ReadBytes(0x100000); |
| 446 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); | 448 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); |
| 447 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); | 449 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); |
| 448 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | 450 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |
| @@ -451,10 +453,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType | |||
| 451 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | 453 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); |
| 452 | } | 454 | } |
| 453 | 455 | ||
| 454 | InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 456 | InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 455 | bool overwrite_if_exists, | 457 | bool overwrite_if_exists, |
| 456 | std::optional<NcaID> override_id) { | 458 | std::optional<NcaID> override_id) { |
| 457 | const auto in = nca->GetBaseFile(); | 459 | const auto in = nca.GetBaseFile(); |
| 458 | Core::Crypto::SHA256Hash hash{}; | 460 | Core::Crypto::SHA256Hash hash{}; |
| 459 | 461 | ||
| 460 | // Calculate NcaID | 462 | // Calculate NcaID |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 6cfb16017..3b77af4e0 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -6,12 +6,12 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <map> | ||
| 10 | #include <memory> | 9 | #include <memory> |
| 11 | #include <string> | 10 | #include <string> |
| 12 | #include <vector> | 11 | #include <vector> |
| 13 | #include <boost/container/flat_map.hpp> | 12 | #include <boost/container/flat_map.hpp> |
| 14 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "core/crypto/key_manager.h" | ||
| 15 | #include "core/file_sys/vfs.h" | 15 | #include "core/file_sys/vfs.h" |
| 16 | 16 | ||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| @@ -103,17 +103,16 @@ public: | |||
| 103 | 103 | ||
| 104 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure | 104 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure |
| 105 | // there is a meta NCA and all of them are accessible. | 105 | // there is a meta NCA and all of them are accessible. |
| 106 | InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, | 106 | InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, |
| 107 | const VfsCopyFunction& copy = &VfsRawCopy); | 107 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 108 | InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, | 108 | InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false, |
| 109 | const VfsCopyFunction& copy = &VfsRawCopy); | 109 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 110 | 110 | ||
| 111 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this | 111 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this |
| 112 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a | 112 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a |
| 113 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. | 113 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. |
| 114 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. | 114 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. |
| 115 | InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 115 | InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false, |
| 116 | bool overwrite_if_exists = false, | ||
| 117 | const VfsCopyFunction& copy = &VfsRawCopy); | 116 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 118 | 117 | ||
| 119 | private: | 118 | private: |
| @@ -127,12 +126,14 @@ private: | |||
| 127 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; | 126 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; |
| 128 | VirtualFile GetFileAtID(NcaID id) const; | 127 | VirtualFile GetFileAtID(NcaID id) const; |
| 129 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; | 128 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; |
| 130 | InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 129 | InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 131 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); | 130 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); |
| 132 | bool RawInstallYuzuMeta(const CNMT& cnmt); | 131 | bool RawInstallYuzuMeta(const CNMT& cnmt); |
| 133 | 132 | ||
| 134 | VirtualDir dir; | 133 | VirtualDir dir; |
| 135 | RegisteredCacheParsingFunction parser; | 134 | RegisteredCacheParsingFunction parser; |
| 135 | Core::Crypto::KeyManager keys; | ||
| 136 | |||
| 136 | // maps tid -> NcaID of meta | 137 | // maps tid -> NcaID of meta |
| 137 | boost::container::flat_map<u64, NcaID> meta_id; | 138 | boost::container::flat_map<u64, NcaID> meta_id; |
| 138 | // maps tid -> meta | 139 | // maps tid -> meta |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 0b645b106..6ad1e4f86 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte | |||
| 48 | 48 | ||
| 49 | switch (storage) { | 49 | switch (storage) { |
| 50 | case StorageId::None: | 50 | case StorageId::None: |
| 51 | res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type); | 51 | res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type); |
| 52 | break; | 52 | break; |
| 53 | case StorageId::NandSystem: | 53 | case StorageId::NandSystem: |
| 54 | res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); | 54 | res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index ef1aaebbb..5434f2149 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr | |||
| 83 | return MakeResult<VirtualDir>(std::move(out)); | 83 | return MakeResult<VirtualDir>(std::move(out)); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | 86 | VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const { |
| 87 | u128 user_id, u64 save_id) { | 87 | return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space)); |
| 88 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 88 | } |
| 89 | // be interpreted as the title id of the current process. | ||
| 90 | if (type == SaveDataType::SaveData && title_id == 0) | ||
| 91 | title_id = Core::CurrentProcess()->GetTitleID(); | ||
| 92 | |||
| 93 | std::string out; | ||
| 94 | 89 | ||
| 90 | std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { | ||
| 95 | switch (space) { | 91 | switch (space) { |
| 96 | case SaveDataSpaceId::NandSystem: | 92 | case SaveDataSpaceId::NandSystem: |
| 97 | out = "/system/"; | 93 | return "/system/"; |
| 98 | break; | ||
| 99 | case SaveDataSpaceId::NandUser: | 94 | case SaveDataSpaceId::NandUser: |
| 100 | out = "/user/"; | 95 | return "/user/"; |
| 101 | break; | ||
| 102 | case SaveDataSpaceId::TemporaryStorage: | 96 | case SaveDataSpaceId::TemporaryStorage: |
| 103 | out = "/temp/"; | 97 | return "/temp/"; |
| 104 | break; | ||
| 105 | default: | 98 | default: |
| 106 | ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); | 99 | ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); |
| 100 | return "/unrecognized/"; ///< To prevent corruption when ignoring asserts. | ||
| 107 | } | 101 | } |
| 102 | } | ||
| 103 | |||
| 104 | std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | ||
| 105 | u128 user_id, u64 save_id) { | ||
| 106 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | ||
| 107 | // be interpreted as the title id of the current process. | ||
| 108 | if (type == SaveDataType::SaveData && title_id == 0) | ||
| 109 | title_id = Core::CurrentProcess()->GetTitleID(); | ||
| 110 | |||
| 111 | std::string out = GetSaveDataSpaceIdPath(space); | ||
| 108 | 112 | ||
| 109 | switch (type) { | 113 | switch (type) { |
| 110 | case SaveDataType::SystemSaveData: | 114 | case SaveDataType::SystemSaveData: |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index d69ef6741..2a0088040 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -52,6 +52,9 @@ public: | |||
| 52 | 52 | ||
| 53 | ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); | 53 | ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); |
| 54 | 54 | ||
| 55 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; | ||
| 56 | |||
| 57 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | ||
| 55 | static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | 58 | static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, |
| 56 | u128 user_id, u64 save_id); | 59 | u128 user_id, u64 save_id); |
| 57 | 60 | ||
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 2aaba4179..e1a4210db 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 252 | continue; | 252 | continue; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | auto next_nca = std::make_shared<NCA>(next_file); | 255 | auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys); |
| 256 | if (next_nca->GetType() == NCAContentType::Program) | 256 | if (next_nca->GetType() == NCAContentType::Program) |
| 257 | program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); | 257 | program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); |
| 258 | if (next_nca->GetStatus() == Loader::ResultStatus::Success || | 258 | if (next_nca->GetStatus() == Loader::ResultStatus::Success || |
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index 338080b7e..9a28ed5bb 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -70,6 +70,8 @@ private: | |||
| 70 | std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; | 70 | std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; |
| 71 | std::vector<VirtualFile> ticket_files; | 71 | std::vector<VirtualFile> ticket_files; |
| 72 | 72 | ||
| 73 | Core::Crypto::KeyManager keys; | ||
| 74 | |||
| 73 | VirtualFile romfs; | 75 | VirtualFile romfs; |
| 74 | VirtualDir exefs; | 76 | VirtualDir exefs; |
| 75 | }; | 77 | }; |
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 7b584de7f..e33327ef0 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { | |||
| 384 | return success; | 384 | return success; |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) { | ||
| 388 | auto dir = GetSubdirectory(name); | ||
| 389 | if (dir == nullptr) { | ||
| 390 | return false; | ||
| 391 | } | ||
| 392 | |||
| 393 | bool success = true; | ||
| 394 | for (const auto& file : dir->GetFiles()) { | ||
| 395 | if (!dir->DeleteFile(file->GetName())) { | ||
| 396 | success = false; | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | for (const auto& sdir : dir->GetSubdirectories()) { | ||
| 401 | if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) { | ||
| 402 | success = false; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | return success; | ||
| 407 | } | ||
| 408 | |||
| 387 | bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { | 409 | bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { |
| 388 | const auto f1 = GetFile(src); | 410 | const auto f1 = GetFile(src); |
| 389 | auto f2 = CreateFile(dest); | 411 | auto f2 = CreateFile(dest); |
| @@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) | |||
| 431 | return nullptr; | 453 | return nullptr; |
| 432 | } | 454 | } |
| 433 | 455 | ||
| 456 | std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) { | ||
| 457 | return nullptr; | ||
| 458 | } | ||
| 459 | |||
| 460 | std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) { | ||
| 461 | return nullptr; | ||
| 462 | } | ||
| 463 | |||
| 464 | std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) { | ||
| 465 | return nullptr; | ||
| 466 | } | ||
| 467 | |||
| 468 | std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) { | ||
| 469 | return nullptr; | ||
| 470 | } | ||
| 471 | |||
| 434 | bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { | 472 | bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { |
| 435 | return false; | 473 | return false; |
| 436 | } | 474 | } |
| 437 | 475 | ||
| 476 | bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { | ||
| 477 | return false; | ||
| 478 | } | ||
| 479 | |||
| 480 | bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) { | ||
| 481 | return false; | ||
| 482 | } | ||
| 483 | |||
| 438 | bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { | 484 | bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { |
| 439 | return false; | 485 | return false; |
| 440 | } | 486 | } |
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 002f99d4e..e5641b255 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -245,12 +245,18 @@ public: | |||
| 245 | // any failure. | 245 | // any failure. |
| 246 | virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); | 246 | virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); |
| 247 | 247 | ||
| 248 | // Deletes the subdirectory with name and returns true on success. | 248 | // Deletes the subdirectory with the given name and returns true on success. |
| 249 | virtual bool DeleteSubdirectory(std::string_view name) = 0; | 249 | virtual bool DeleteSubdirectory(std::string_view name) = 0; |
| 250 | // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes | 250 | |
| 251 | // the subdirectory. Returns true on success. | 251 | // Deletes all subdirectories and files within the provided directory and then deletes |
| 252 | // the directory itself. Returns true on success. | ||
| 252 | virtual bool DeleteSubdirectoryRecursive(std::string_view name); | 253 | virtual bool DeleteSubdirectoryRecursive(std::string_view name); |
| 253 | // Returnes whether or not the file with name name was deleted successfully. | 254 | |
| 255 | // Deletes all subdirectories and files within the provided directory. | ||
| 256 | // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory. | ||
| 257 | virtual bool CleanSubdirectoryRecursive(std::string_view name); | ||
| 258 | |||
| 259 | // Returns whether or not the file with name name was deleted successfully. | ||
| 254 | virtual bool DeleteFile(std::string_view name) = 0; | 260 | virtual bool DeleteFile(std::string_view name) = 0; |
| 255 | 261 | ||
| 256 | // Returns whether or not this directory was renamed to name. | 262 | // Returns whether or not this directory was renamed to name. |
| @@ -276,7 +282,13 @@ public: | |||
| 276 | bool IsReadable() const override; | 282 | bool IsReadable() const override; |
| 277 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; | 283 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; |
| 278 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; | 284 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; |
| 285 | std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override; | ||
| 286 | std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; | ||
| 287 | std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override; | ||
| 288 | std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; | ||
| 279 | bool DeleteSubdirectory(std::string_view name) override; | 289 | bool DeleteSubdirectory(std::string_view name) override; |
| 290 | bool DeleteSubdirectoryRecursive(std::string_view name) override; | ||
| 291 | bool CleanSubdirectoryRecursive(std::string_view name) override; | ||
| 280 | bool DeleteFile(std::string_view name) override; | 292 | bool DeleteFile(std::string_view name) override; |
| 281 | bool Rename(std::string_view name) override; | 293 | bool Rename(std::string_view name) override; |
| 282 | }; | 294 | }; |
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp new file mode 100644 index 000000000..856ed33da --- /dev/null +++ b/src/core/frontend/applets/software_keyboard.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/backend.h" | ||
| 6 | #include "common/string_util.h" | ||
| 7 | #include "core/frontend/applets/software_keyboard.h" | ||
| 8 | |||
| 9 | namespace Core::Frontend { | ||
| 10 | SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; | ||
| 11 | |||
| 12 | void DefaultSoftwareKeyboardApplet::RequestText( | ||
| 13 | std::function<void(std::optional<std::u16string>)> out, | ||
| 14 | SoftwareKeyboardParameters parameters) const { | ||
| 15 | if (parameters.initial_text.empty()) | ||
| 16 | out(u"yuzu"); | ||
| 17 | |||
| 18 | out(parameters.initial_text); | ||
| 19 | } | ||
| 20 | |||
| 21 | void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( | ||
| 22 | std::u16string error_message, std::function<void()> finished_check) const { | ||
| 23 | LOG_WARNING(Service_AM, | ||
| 24 | "(STUBBED) called - Default fallback software keyboard does not support text " | ||
| 25 | "check! (error_message={})", | ||
| 26 | Common::UTF16ToUTF8(error_message)); | ||
| 27 | finished_check(); | ||
| 28 | } | ||
| 29 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h new file mode 100644 index 000000000..f9b202664 --- /dev/null +++ b/src/core/frontend/applets/software_keyboard.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include <optional> | ||
| 9 | #include <string> | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | namespace Core::Frontend { | ||
| 14 | struct SoftwareKeyboardParameters { | ||
| 15 | std::u16string submit_text; | ||
| 16 | std::u16string header_text; | ||
| 17 | std::u16string sub_text; | ||
| 18 | std::u16string guide_text; | ||
| 19 | std::u16string initial_text; | ||
| 20 | std::size_t max_length; | ||
| 21 | bool password; | ||
| 22 | bool cursor_at_beginning; | ||
| 23 | |||
| 24 | union { | ||
| 25 | u8 value; | ||
| 26 | |||
| 27 | BitField<1, 1, u8> disable_space; | ||
| 28 | BitField<2, 1, u8> disable_address; | ||
| 29 | BitField<3, 1, u8> disable_percent; | ||
| 30 | BitField<4, 1, u8> disable_slash; | ||
| 31 | BitField<6, 1, u8> disable_number; | ||
| 32 | BitField<7, 1, u8> disable_download_code; | ||
| 33 | }; | ||
| 34 | }; | ||
| 35 | |||
| 36 | class SoftwareKeyboardApplet { | ||
| 37 | public: | ||
| 38 | virtual ~SoftwareKeyboardApplet(); | ||
| 39 | |||
| 40 | virtual void RequestText(std::function<void(std::optional<std::u16string>)> out, | ||
| 41 | SoftwareKeyboardParameters parameters) const = 0; | ||
| 42 | virtual void SendTextCheckDialog(std::u16string error_message, | ||
| 43 | std::function<void()> finished_check) const = 0; | ||
| 44 | }; | ||
| 45 | |||
| 46 | class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { | ||
| 47 | public: | ||
| 48 | void RequestText(std::function<void(std::optional<std::u16string>)> out, | ||
| 49 | SoftwareKeyboardParameters parameters) const override; | ||
| 50 | void SendTextCheckDialog(std::u16string error_message, | ||
| 51 | std::function<void()> finished_check) const override; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 39bdf4e21..16fdcd376 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -132,4 +132,11 @@ using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float> | |||
| 132 | */ | 132 | */ |
| 133 | using TouchDevice = InputDevice<std::tuple<float, float, bool>>; | 133 | using TouchDevice = InputDevice<std::tuple<float, float, bool>>; |
| 134 | 134 | ||
| 135 | /** | ||
| 136 | * A mouse device is an input device that returns a tuple of two floats and four ints. | ||
| 137 | * The first two floats are X and Y device coordinates of the mouse (from 0-1). | ||
| 138 | * The s32s are the mouse wheel. | ||
| 139 | */ | ||
| 140 | using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>; | ||
| 141 | |||
| 135 | } // namespace Input | 142 | } // namespace Input |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index bdcc889e0..e6b5171ee 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33; | |||
| 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; | 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; |
| 72 | constexpr u32 FPCR_REGISTER = 66; | 72 | constexpr u32 FPCR_REGISTER = 66; |
| 73 | 73 | ||
| 74 | // TODO/WiP - Used while working on support for FPU | ||
| 75 | constexpr u32 TODO_DUMMY_REG_997 = 997; | ||
| 76 | constexpr u32 TODO_DUMMY_REG_998 = 998; | ||
| 77 | |||
| 78 | // For sample XML files see the GDB source /gdb/features | 74 | // For sample XML files see the GDB source /gdb/features |
| 79 | // GDB also wants the l character at the start | 75 | // GDB also wants the l character at the start |
| 80 | // This XML defines what the registers are for this specific ARM device | 76 | // This XML defines what the registers are for this specific ARM device |
| @@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 260 | } | 256 | } |
| 261 | } | 257 | } |
| 262 | 258 | ||
| 259 | static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { | ||
| 260 | if (!thread) { | ||
| 261 | return u128{0}; | ||
| 262 | } | ||
| 263 | |||
| 264 | auto& thread_context = thread->GetContext(); | ||
| 265 | |||
| 266 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 267 | return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; | ||
| 268 | } else if (id == FPCR_REGISTER) { | ||
| 269 | return u128{thread_context.fpcr, 0}; | ||
| 270 | } else { | ||
| 271 | return u128{0}; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) { | ||
| 276 | if (!thread) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | auto& thread_context = thread->GetContext(); | ||
| 281 | |||
| 282 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 283 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; | ||
| 284 | } else if (id == FPCR_REGISTER) { | ||
| 285 | thread_context.fpcr = static_cast<u32>(val[0]); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 263 | /** | 289 | /** |
| 264 | * Turns hex string character into the equivalent byte. | 290 | * Turns hex string character into the equivalent byte. |
| 265 | * | 291 | * |
| @@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) { | |||
| 409 | return output; | 435 | return output; |
| 410 | } | 436 | } |
| 411 | 437 | ||
| 438 | /** | ||
| 439 | * Convert a gdb-formatted hex string into a u128. | ||
| 440 | * | ||
| 441 | * @param src Pointer to hex string. | ||
| 442 | */ | ||
| 443 | static u128 GdbHexToU128(const u8* src) { | ||
| 444 | u128 output; | ||
| 445 | |||
| 446 | for (int i = 0; i < 16; i += 2) { | ||
| 447 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]); | ||
| 448 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]); | ||
| 449 | } | ||
| 450 | |||
| 451 | for (int i = 0; i < 16; i += 2) { | ||
| 452 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]); | ||
| 453 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]); | ||
| 454 | } | ||
| 455 | |||
| 456 | return output; | ||
| 457 | } | ||
| 458 | |||
| 412 | /// Read a byte from the gdb client. | 459 | /// Read a byte from the gdb client. |
| 413 | static u8 ReadByte() { | 460 | static u8 ReadByte() { |
| 414 | u8 c; | 461 | u8 c; |
| @@ -599,8 +646,7 @@ static void HandleQuery() { | |||
| 599 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | 646 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { |
| 600 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); | 647 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); |
| 601 | for (const auto& thread : threads) { | 648 | for (const auto& thread : threads) { |
| 602 | val += fmt::format("{:x}", thread->GetThreadID()); | 649 | val += fmt::format("{:x},", thread->GetThreadID()); |
| 603 | val += ","; | ||
| 604 | } | 650 | } |
| 605 | } | 651 | } |
| 606 | val.pop_back(); | 652 | val.pop_back(); |
| @@ -791,11 +837,15 @@ static void ReadRegister() { | |||
| 791 | } else if (id == PSTATE_REGISTER) { | 837 | } else if (id == PSTATE_REGISTER) { |
| 792 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); | 838 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); |
| 793 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 839 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 794 | LongToGdbHex(reply, RegRead(id, current_thread)); | 840 | u128 r = FpuRead(id, current_thread); |
| 841 | LongToGdbHex(reply, r[0]); | ||
| 842 | LongToGdbHex(reply + 16, r[1]); | ||
| 795 | } else if (id == FPCR_REGISTER) { | 843 | } else if (id == FPCR_REGISTER) { |
| 796 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | 844 | u128 r = FpuRead(id, current_thread); |
| 797 | } else { | 845 | IntToGdbHex(reply, static_cast<u32>(r[0])); |
| 798 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); | 846 | } else if (id == FPCR_REGISTER + 1) { |
| 847 | u128 r = FpuRead(id, current_thread); | ||
| 848 | IntToGdbHex(reply, static_cast<u32>(r[0] >> 32)); | ||
| 799 | } | 849 | } |
| 800 | 850 | ||
| 801 | SendReply(reinterpret_cast<char*>(reply)); | 851 | SendReply(reinterpret_cast<char*>(reply)); |
| @@ -822,13 +872,18 @@ static void ReadRegisters() { | |||
| 822 | 872 | ||
| 823 | bufptr += 8; | 873 | bufptr += 8; |
| 824 | 874 | ||
| 825 | for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { | 875 | u128 r; |
| 826 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | 876 | |
| 877 | for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) { | ||
| 878 | r = FpuRead(reg, current_thread); | ||
| 879 | LongToGdbHex(bufptr + reg * 32, r[0]); | ||
| 880 | LongToGdbHex(bufptr + reg * 32 + 16, r[1]); | ||
| 827 | } | 881 | } |
| 828 | 882 | ||
| 829 | bufptr += 32 * 32; | 883 | bufptr += 32 * 32; |
| 830 | 884 | ||
| 831 | LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); | 885 | r = FpuRead(FPCR_REGISTER, current_thread); |
| 886 | IntToGdbHex(bufptr, static_cast<u32>(r[0])); | ||
| 832 | 887 | ||
| 833 | bufptr += 8; | 888 | bufptr += 8; |
| 834 | 889 | ||
| @@ -853,14 +908,12 @@ static void WriteRegister() { | |||
| 853 | } else if (id == PSTATE_REGISTER) { | 908 | } else if (id == PSTATE_REGISTER) { |
| 854 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | 909 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |
| 855 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 910 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 856 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 911 | FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread); |
| 857 | } else if (id == FPCR_REGISTER) { | 912 | } else if (id == FPCR_REGISTER) { |
| 858 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | 913 | } else if (id == FPCR_REGISTER + 1) { |
| 859 | } else { | ||
| 860 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); | ||
| 861 | } | 914 | } |
| 862 | 915 | ||
| 863 | // Update Unicorn context skipping scheduler, no running threads at this point | 916 | // Update ARM context, skipping scheduler - no running threads at this point |
| 864 | Core::System::GetInstance() | 917 | Core::System::GetInstance() |
| 865 | .ArmInterface(current_core) | 918 | .ArmInterface(current_core) |
| 866 | .LoadContext(current_thread->GetContext()); | 919 | .LoadContext(current_thread->GetContext()); |
| @@ -885,13 +938,13 @@ static void WriteRegisters() { | |||
| 885 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { | 938 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { |
| 886 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 939 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 887 | } else if (reg == FPCR_REGISTER) { | 940 | } else if (reg == FPCR_REGISTER) { |
| 888 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 941 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 889 | } else { | 942 | } else if (reg == FPCR_REGISTER + 1) { |
| 890 | UNIMPLEMENTED(); | 943 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 891 | } | 944 | } |
| 892 | } | 945 | } |
| 893 | 946 | ||
| 894 | // Update Unicorn context skipping scheduler, no running threads at this point | 947 | // Update ARM context, skipping scheduler - no running threads at this point |
| 895 | Core::System::GetInstance() | 948 | Core::System::GetInstance() |
| 896 | .ArmInterface(current_core) | 949 | .ArmInterface(current_core) |
| 897 | .LoadContext(current_thread->GetContext()); | 950 | .LoadContext(current_thread->GetContext()); |
| @@ -917,12 +970,6 @@ static void ReadMemory() { | |||
| 917 | SendReply("E01"); | 970 | SendReply("E01"); |
| 918 | } | 971 | } |
| 919 | 972 | ||
| 920 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); | ||
| 921 | if (addr < vm_manager.GetCodeRegionBaseAddress() || | ||
| 922 | addr >= vm_manager.GetMapRegionEndAddress()) { | ||
| 923 | return SendReply("E00"); | ||
| 924 | } | ||
| 925 | |||
| 926 | if (!Memory::IsValidVirtualAddress(addr)) { | 973 | if (!Memory::IsValidVirtualAddress(addr)) { |
| 927 | return SendReply("E00"); | 974 | return SendReply("E00"); |
| 928 | } | 975 | } |
| @@ -967,7 +1014,7 @@ void Break(bool is_memory_break) { | |||
| 967 | static void Step() { | 1014 | static void Step() { |
| 968 | if (command_length > 1) { | 1015 | if (command_length > 1) { |
| 969 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | 1016 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); |
| 970 | // Update Unicorn context skipping scheduler, no running threads at this point | 1017 | // Update ARM context, skipping scheduler - no running threads at this point |
| 971 | Core::System::GetInstance() | 1018 | Core::System::GetInstance() |
| 972 | .ArmInterface(current_core) | 1019 | .ArmInterface(current_core) |
| 973 | .LoadContext(current_thread->GetContext()); | 1020 | .LoadContext(current_thread->GetContext()); |
| @@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { | |||
| 1010 | breakpoint.addr = addr; | 1057 | breakpoint.addr = addr; |
| 1011 | breakpoint.len = len; | 1058 | breakpoint.len = len; |
| 1012 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); | 1059 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); |
| 1013 | static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; | 1060 | static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; |
| 1014 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); | 1061 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); |
| 1015 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | 1062 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); |
| 1016 | p.insert({addr, breakpoint}); | 1063 | p.insert({addr, breakpoint}); |
| @@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) { | |||
| 1321 | } | 1368 | } |
| 1322 | 1369 | ||
| 1323 | void SendTrap(Kernel::Thread* thread, int trap) { | 1370 | void SendTrap(Kernel::Thread* thread, int trap) { |
| 1324 | if (send_trap) { | 1371 | if (!send_trap) { |
| 1325 | if (!halt_loop || current_thread == thread) { | 1372 | return; |
| 1326 | current_thread = thread; | ||
| 1327 | SendSignal(thread, trap); | ||
| 1328 | } | ||
| 1329 | halt_loop = true; | ||
| 1330 | send_trap = false; | ||
| 1331 | } | 1373 | } |
| 1374 | |||
| 1375 | if (!halt_loop || current_thread == thread) { | ||
| 1376 | current_thread = thread; | ||
| 1377 | SendSignal(thread, trap); | ||
| 1378 | } | ||
| 1379 | halt_loop = true; | ||
| 1380 | send_trap = false; | ||
| 1332 | } | 1381 | } |
| 1333 | }; // namespace GDBStub | 1382 | }; // namespace GDBStub |
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index ee698c8a7..8b58d701d 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -8,58 +8,28 @@ | |||
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Kernel { |
| 10 | 10 | ||
| 11 | namespace ErrCodes { | 11 | // Confirmed Switch kernel error codes |
| 12 | enum { | ||
| 13 | // Confirmed Switch OS error codes | ||
| 14 | MaxConnectionsReached = 7, | ||
| 15 | InvalidSize = 101, | ||
| 16 | InvalidAddress = 102, | ||
| 17 | HandleTableFull = 105, | ||
| 18 | InvalidMemoryState = 106, | ||
| 19 | InvalidMemoryPermissions = 108, | ||
| 20 | InvalidMemoryRange = 110, | ||
| 21 | InvalidThreadPriority = 112, | ||
| 22 | InvalidProcessorId = 113, | ||
| 23 | InvalidHandle = 114, | ||
| 24 | InvalidPointer = 115, | ||
| 25 | InvalidCombination = 116, | ||
| 26 | Timeout = 117, | ||
| 27 | SynchronizationCanceled = 118, | ||
| 28 | TooLarge = 119, | ||
| 29 | InvalidEnumValue = 120, | ||
| 30 | NoSuchEntry = 121, | ||
| 31 | AlreadyRegistered = 122, | ||
| 32 | SessionClosed = 123, | ||
| 33 | InvalidState = 125, | ||
| 34 | ResourceLimitExceeded = 132, | ||
| 35 | }; | ||
| 36 | } | ||
| 37 | 12 | ||
| 38 | // WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always | 13 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; |
| 39 | // double check that the code matches before re-using the constant. | 14 | constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; |
| 40 | 15 | constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; | |
| 41 | constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); | 16 | constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; |
| 42 | constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed); | 17 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; |
| 43 | constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); | 18 | constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; |
| 44 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel, | 19 | constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110}; |
| 45 | ErrCodes::MaxConnectionsReached); | 20 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113}; |
| 46 | constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); | 21 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112}; |
| 47 | constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel, | 22 | constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114}; |
| 48 | ErrCodes::InvalidCombination); | 23 | constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115}; |
| 49 | constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); | 24 | constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116}; |
| 50 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); | 25 | constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117}; |
| 51 | constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, | 26 | constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118}; |
| 52 | ErrCodes::InvalidMemoryPermissions); | 27 | constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119}; |
| 53 | constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); | 28 | constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120}; |
| 54 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | 29 | constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121}; |
| 55 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | 30 | constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122}; |
| 56 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); | 31 | constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123}; |
| 57 | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); | 32 | constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125}; |
| 58 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); | 33 | constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132}; |
| 59 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, | ||
| 60 | ErrCodes::InvalidThreadPriority); | ||
| 61 | constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer); | ||
| 62 | constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry); | ||
| 63 | constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); | ||
| 64 | 34 | ||
| 65 | } // namespace Kernel | 35 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 5ee5c05e3..c8acde5b1 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -12,12 +12,23 @@ | |||
| 12 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | namespace { | ||
| 16 | constexpr u16 GetSlot(Handle handle) { | ||
| 17 | return handle >> 15; | ||
| 18 | } | ||
| 19 | |||
| 20 | constexpr u16 GetGeneration(Handle handle) { | ||
| 21 | return handle & 0x7FFF; | ||
| 22 | } | ||
| 23 | } // Anonymous namespace | ||
| 15 | 24 | ||
| 16 | HandleTable::HandleTable() { | 25 | HandleTable::HandleTable() { |
| 17 | next_generation = 1; | 26 | next_generation = 1; |
| 18 | Clear(); | 27 | Clear(); |
| 19 | } | 28 | } |
| 20 | 29 | ||
| 30 | HandleTable::~HandleTable() = default; | ||
| 31 | |||
| 21 | ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | 32 | ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { |
| 22 | DEBUG_ASSERT(obj != nullptr); | 33 | DEBUG_ASSERT(obj != nullptr); |
| 23 | 34 | ||
| @@ -31,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | |||
| 31 | u16 generation = next_generation++; | 42 | u16 generation = next_generation++; |
| 32 | 43 | ||
| 33 | // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. | 44 | // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. |
| 34 | // CTR-OS doesn't use generation 0, so skip straight to 1. | 45 | // Horizon OS uses zero to represent an invalid handle, so skip to 1. |
| 35 | if (next_generation >= (1 << 15)) | 46 | if (next_generation >= (1 << 15)) { |
| 36 | next_generation = 1; | 47 | next_generation = 1; |
| 48 | } | ||
| 37 | 49 | ||
| 38 | generations[slot] = generation; | 50 | generations[slot] = generation; |
| 39 | objects[slot] = std::move(obj); | 51 | objects[slot] = std::move(obj); |
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 9e2f33e8a..6b7927fd8 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | enum KernelHandle : Handle { | 15 | enum KernelHandle : Handle { |
| 16 | InvalidHandle = 0, | ||
| 16 | CurrentThread = 0xFFFF8000, | 17 | CurrentThread = 0xFFFF8000, |
| 17 | CurrentProcess = 0xFFFF8001, | 18 | CurrentProcess = 0xFFFF8001, |
| 18 | }; | 19 | }; |
| @@ -43,6 +44,7 @@ enum KernelHandle : Handle { | |||
| 43 | class HandleTable final : NonCopyable { | 44 | class HandleTable final : NonCopyable { |
| 44 | public: | 45 | public: |
| 45 | HandleTable(); | 46 | HandleTable(); |
| 47 | ~HandleTable(); | ||
| 46 | 48 | ||
| 47 | /** | 49 | /** |
| 48 | * Allocates a handle for the given object. | 50 | * Allocates a handle for the given object. |
| @@ -89,18 +91,8 @@ public: | |||
| 89 | void Clear(); | 91 | void Clear(); |
| 90 | 92 | ||
| 91 | private: | 93 | private: |
| 92 | /** | 94 | /// This is the maximum limit of handles allowed per process in Horizon |
| 93 | * This is the maximum limit of handles allowed per process in CTR-OS. It can be further | 95 | static constexpr std::size_t MAX_COUNT = 1024; |
| 94 | * reduced by ExHeader values, but this is not emulated here. | ||
| 95 | */ | ||
| 96 | static const std::size_t MAX_COUNT = 4096; | ||
| 97 | |||
| 98 | static u16 GetSlot(Handle handle) { | ||
| 99 | return handle >> 15; | ||
| 100 | } | ||
| 101 | static u16 GetGeneration(Handle handle) { | ||
| 102 | return handle & 0x7FFF; | ||
| 103 | } | ||
| 104 | 96 | ||
| 105 | /// Stores the Object referenced by the handle or null if the slot is empty. | 97 | /// Stores the Object referenced by the handle or null if the slot is empty. |
| 106 | std::array<SharedPtr<Object>, MAX_COUNT> objects; | 98 | std::array<SharedPtr<Object>, MAX_COUNT> objects; |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 68d5376cb..61ce7d7e4 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -15,13 +15,14 @@ | |||
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/hle/ipc_helpers.h" | 17 | #include "core/hle/ipc_helpers.h" |
| 18 | #include "core/hle/kernel/event.h" | ||
| 19 | #include "core/hle/kernel/handle_table.h" | 18 | #include "core/hle/kernel/handle_table.h" |
| 20 | #include "core/hle/kernel/hle_ipc.h" | 19 | #include "core/hle/kernel/hle_ipc.h" |
| 21 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 22 | #include "core/hle/kernel/object.h" | 21 | #include "core/hle/kernel/object.h" |
| 23 | #include "core/hle/kernel/process.h" | 22 | #include "core/hle/kernel/process.h" |
| 23 | #include "core/hle/kernel/readable_event.h" | ||
| 24 | #include "core/hle/kernel/server_session.h" | 24 | #include "core/hle/kernel/server_session.h" |
| 25 | #include "core/hle/kernel/writable_event.h" | ||
| 25 | #include "core/memory.h" | 26 | #include "core/memory.h" |
| 26 | 27 | ||
| 27 | namespace Kernel { | 28 | namespace Kernel { |
| @@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s | |||
| 36 | boost::range::remove_erase(connected_sessions, server_session); | 37 | boost::range::remove_erase(connected_sessions, server_session); |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, | 40 | SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( |
| 40 | const std::string& reason, u64 timeout, | 41 | SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback, |
| 41 | WakeupCallback&& callback, | 42 | SharedPtr<WritableEvent> writable_event) { |
| 42 | Kernel::SharedPtr<Kernel::Event> event) { | ||
| 43 | |||
| 44 | // Put the client thread to sleep until the wait event is signaled or the timeout expires. | 43 | // Put the client thread to sleep until the wait event is signaled or the timeout expires. |
| 45 | thread->SetWakeupCallback([context = *this, callback]( | 44 | thread->SetWakeupCallback([context = *this, callback]( |
| 46 | ThreadWakeupReason reason, SharedPtr<Thread> thread, | 45 | ThreadWakeupReason reason, SharedPtr<Thread> thread, |
| @@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, | |||
| 51 | return true; | 50 | return true; |
| 52 | }); | 51 | }); |
| 53 | 52 | ||
| 54 | if (!event) { | 53 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 54 | if (!writable_event) { | ||
| 55 | // Create event if not provided | 55 | // Create event if not provided |
| 56 | auto& kernel = Core::System::GetInstance().Kernel(); | 56 | const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, |
| 57 | event = | 57 | "HLE Pause Event: " + reason); |
| 58 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); | 58 | writable_event = pair.writable; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | event->Clear(); | 61 | const auto readable_event{writable_event->GetReadableEvent()}; |
| 62 | writable_event->Clear(); | ||
| 62 | thread->SetStatus(ThreadStatus::WaitHLEEvent); | 63 | thread->SetStatus(ThreadStatus::WaitHLEEvent); |
| 63 | thread->SetWaitObjects({event}); | 64 | thread->SetWaitObjects({readable_event}); |
| 64 | event->AddWaitingThread(thread); | 65 | readable_event->AddWaitingThread(thread); |
| 65 | 66 | ||
| 66 | if (timeout > 0) { | 67 | if (timeout > 0) { |
| 67 | thread->WakeAfterDelay(timeout); | 68 | thread->WakeAfterDelay(timeout); |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | return event; | 71 | return writable_event; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) | 74 | HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index a38e34b74..e5c0610cd 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -24,10 +24,11 @@ class ServiceFrameworkBase; | |||
| 24 | namespace Kernel { | 24 | namespace Kernel { |
| 25 | 25 | ||
| 26 | class Domain; | 26 | class Domain; |
| 27 | class Event; | ||
| 28 | class HandleTable; | 27 | class HandleTable; |
| 29 | class HLERequestContext; | 28 | class HLERequestContext; |
| 30 | class Process; | 29 | class Process; |
| 30 | class ReadableEvent; | ||
| 31 | class WritableEvent; | ||
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 33 | * Interface implemented by HLE Session handlers. | 34 | * Interface implemented by HLE Session handlers. |
| @@ -119,12 +120,13 @@ public: | |||
| 119 | * @param callback Callback to be invoked when the thread is resumed. This callback must write | 120 | * @param callback Callback to be invoked when the thread is resumed. This callback must write |
| 120 | * the entire command response once again, regardless of the state of it before this function | 121 | * the entire command response once again, regardless of the state of it before this function |
| 121 | * was called. | 122 | * was called. |
| 122 | * @param event Event to use to wake up the thread. If unspecified, an event will be created. | 123 | * @param writable_event Event to use to wake up the thread. If unspecified, an event will be |
| 124 | * created. | ||
| 123 | * @returns Event that when signaled will resume the thread and call the callback function. | 125 | * @returns Event that when signaled will resume the thread and call the callback function. |
| 124 | */ | 126 | */ |
| 125 | SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, | 127 | SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, |
| 126 | u64 timeout, WakeupCallback&& callback, | 128 | u64 timeout, WakeupCallback&& callback, |
| 127 | Kernel::SharedPtr<Kernel::Event> event = nullptr); | 129 | SharedPtr<WritableEvent> writable_event = nullptr); |
| 128 | 130 | ||
| 129 | /// Populates this context with data from the requesting process/thread. | 131 | /// Populates this context with data from the requesting process/thread. |
| 130 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, | 132 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1fd4ba5d2..e441c5bc6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -105,7 +105,7 @@ struct KernelCore::Impl { | |||
| 105 | void Initialize(KernelCore& kernel) { | 105 | void Initialize(KernelCore& kernel) { |
| 106 | Shutdown(); | 106 | Shutdown(); |
| 107 | 107 | ||
| 108 | InitializeResourceLimits(kernel); | 108 | InitializeSystemResourceLimit(kernel); |
| 109 | InitializeThreads(); | 109 | InitializeThreads(); |
| 110 | InitializeTimers(); | 110 | InitializeTimers(); |
| 111 | } | 111 | } |
| @@ -118,7 +118,7 @@ struct KernelCore::Impl { | |||
| 118 | process_list.clear(); | 118 | process_list.clear(); |
| 119 | current_process = nullptr; | 119 | current_process = nullptr; |
| 120 | 120 | ||
| 121 | resource_limits.fill(nullptr); | 121 | system_resource_limit = nullptr; |
| 122 | 122 | ||
| 123 | thread_wakeup_callback_handle_table.Clear(); | 123 | thread_wakeup_callback_handle_table.Clear(); |
| 124 | thread_wakeup_event_type = nullptr; | 124 | thread_wakeup_event_type = nullptr; |
| @@ -129,63 +129,17 @@ struct KernelCore::Impl { | |||
| 129 | named_ports.clear(); | 129 | named_ports.clear(); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void InitializeResourceLimits(KernelCore& kernel) { | 132 | // Creates the default system resource limit |
| 133 | // Create the four resource limits that the system uses | 133 | void InitializeSystemResourceLimit(KernelCore& kernel) { |
| 134 | // Create the APPLICATION resource limit | 134 | system_resource_limit = ResourceLimit::Create(kernel, "System"); |
| 135 | SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications"); | 135 | |
| 136 | resource_limit->max_priority = 0x18; | 136 | // If setting the default system values fails, then something seriously wrong has occurred. |
| 137 | resource_limit->max_commit = 0x4000000; | 137 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000) |
| 138 | resource_limit->max_threads = 0x20; | 138 | .IsSuccess()); |
| 139 | resource_limit->max_events = 0x20; | 139 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess()); |
| 140 | resource_limit->max_mutexes = 0x20; | 140 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess()); |
| 141 | resource_limit->max_semaphores = 0x8; | 141 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess()); |
| 142 | resource_limit->max_timers = 0x8; | 142 | ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess()); |
| 143 | resource_limit->max_shared_mems = 0x10; | ||
| 144 | resource_limit->max_address_arbiters = 0x2; | ||
| 145 | resource_limit->max_cpu_time = 0x1E; | ||
| 146 | resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit; | ||
| 147 | |||
| 148 | // Create the SYS_APPLET resource limit | ||
| 149 | resource_limit = ResourceLimit::Create(kernel, "System Applets"); | ||
| 150 | resource_limit->max_priority = 0x4; | ||
| 151 | resource_limit->max_commit = 0x5E00000; | ||
| 152 | resource_limit->max_threads = 0x1D; | ||
| 153 | resource_limit->max_events = 0xB; | ||
| 154 | resource_limit->max_mutexes = 0x8; | ||
| 155 | resource_limit->max_semaphores = 0x4; | ||
| 156 | resource_limit->max_timers = 0x4; | ||
| 157 | resource_limit->max_shared_mems = 0x8; | ||
| 158 | resource_limit->max_address_arbiters = 0x3; | ||
| 159 | resource_limit->max_cpu_time = 0x2710; | ||
| 160 | resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit; | ||
| 161 | |||
| 162 | // Create the LIB_APPLET resource limit | ||
| 163 | resource_limit = ResourceLimit::Create(kernel, "Library Applets"); | ||
| 164 | resource_limit->max_priority = 0x4; | ||
| 165 | resource_limit->max_commit = 0x600000; | ||
| 166 | resource_limit->max_threads = 0xE; | ||
| 167 | resource_limit->max_events = 0x8; | ||
| 168 | resource_limit->max_mutexes = 0x8; | ||
| 169 | resource_limit->max_semaphores = 0x4; | ||
| 170 | resource_limit->max_timers = 0x4; | ||
| 171 | resource_limit->max_shared_mems = 0x8; | ||
| 172 | resource_limit->max_address_arbiters = 0x1; | ||
| 173 | resource_limit->max_cpu_time = 0x2710; | ||
| 174 | resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit; | ||
| 175 | |||
| 176 | // Create the OTHER resource limit | ||
| 177 | resource_limit = ResourceLimit::Create(kernel, "Others"); | ||
| 178 | resource_limit->max_priority = 0x4; | ||
| 179 | resource_limit->max_commit = 0x2180000; | ||
| 180 | resource_limit->max_threads = 0xE1; | ||
| 181 | resource_limit->max_events = 0x108; | ||
| 182 | resource_limit->max_mutexes = 0x25; | ||
| 183 | resource_limit->max_semaphores = 0x43; | ||
| 184 | resource_limit->max_timers = 0x2C; | ||
| 185 | resource_limit->max_shared_mems = 0x1F; | ||
| 186 | resource_limit->max_address_arbiters = 0x2D; | ||
| 187 | resource_limit->max_cpu_time = 0x3E8; | ||
| 188 | resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit; | ||
| 189 | } | 143 | } |
| 190 | 144 | ||
| 191 | void InitializeThreads() { | 145 | void InitializeThreads() { |
| @@ -208,7 +162,7 @@ struct KernelCore::Impl { | |||
| 208 | std::vector<SharedPtr<Process>> process_list; | 162 | std::vector<SharedPtr<Process>> process_list; |
| 209 | Process* current_process = nullptr; | 163 | Process* current_process = nullptr; |
| 210 | 164 | ||
| 211 | std::array<SharedPtr<ResourceLimit>, 4> resource_limits; | 165 | SharedPtr<ResourceLimit> system_resource_limit; |
| 212 | 166 | ||
| 213 | /// The event type of the generic timer callback event | 167 | /// The event type of the generic timer callback event |
| 214 | CoreTiming::EventType* timer_callback_event_type = nullptr; | 168 | CoreTiming::EventType* timer_callback_event_type = nullptr; |
| @@ -239,9 +193,8 @@ void KernelCore::Shutdown() { | |||
| 239 | impl->Shutdown(); | 193 | impl->Shutdown(); |
| 240 | } | 194 | } |
| 241 | 195 | ||
| 242 | SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( | 196 | SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { |
| 243 | ResourceLimitCategory category) const { | 197 | return impl->system_resource_limit; |
| 244 | return impl->resource_limits.at(static_cast<std::size_t>(category)); | ||
| 245 | } | 198 | } |
| 246 | 199 | ||
| 247 | SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { | 200 | SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7f822d524..ea00c89f5 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -24,8 +24,6 @@ class ResourceLimit; | |||
| 24 | class Thread; | 24 | class Thread; |
| 25 | class Timer; | 25 | class Timer; |
| 26 | 26 | ||
| 27 | enum class ResourceLimitCategory : u8; | ||
| 28 | |||
| 29 | /// Represents a single instance of the kernel. | 27 | /// Represents a single instance of the kernel. |
| 30 | class KernelCore { | 28 | class KernelCore { |
| 31 | private: | 29 | private: |
| @@ -47,8 +45,8 @@ public: | |||
| 47 | /// Clears all resources in use by the kernel instance. | 45 | /// Clears all resources in use by the kernel instance. |
| 48 | void Shutdown(); | 46 | void Shutdown(); |
| 49 | 47 | ||
| 50 | /// Retrieves a shared pointer to a ResourceLimit identified by the given category. | 48 | /// Retrieves a shared pointer to the system resource limit instance. |
| 51 | SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; | 49 | SharedPtr<ResourceLimit> GetSystemResourceLimit() const; |
| 52 | 50 | ||
| 53 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | 51 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. |
| 54 | SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; | 52 | SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; |
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index d87a62bb9..bb1b68778 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp | |||
| @@ -13,7 +13,7 @@ Object::~Object() = default; | |||
| 13 | 13 | ||
| 14 | bool Object::IsWaitable() const { | 14 | bool Object::IsWaitable() const { |
| 15 | switch (GetHandleType()) { | 15 | switch (GetHandleType()) { |
| 16 | case HandleType::Event: | 16 | case HandleType::ReadableEvent: |
| 17 | case HandleType::Thread: | 17 | case HandleType::Thread: |
| 18 | case HandleType::Timer: | 18 | case HandleType::Timer: |
| 19 | case HandleType::ServerPort: | 19 | case HandleType::ServerPort: |
| @@ -21,6 +21,7 @@ bool Object::IsWaitable() const { | |||
| 21 | return true; | 21 | return true; |
| 22 | 22 | ||
| 23 | case HandleType::Unknown: | 23 | case HandleType::Unknown: |
| 24 | case HandleType::WritableEvent: | ||
| 24 | case HandleType::SharedMemory: | 25 | case HandleType::SharedMemory: |
| 25 | case HandleType::Process: | 26 | case HandleType::Process: |
| 26 | case HandleType::AddressArbiter: | 27 | case HandleType::AddressArbiter: |
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index c9f4d0bb3..f1606a204 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h | |||
| @@ -19,7 +19,8 @@ using Handle = u32; | |||
| 19 | 19 | ||
| 20 | enum class HandleType : u32 { | 20 | enum class HandleType : u32 { |
| 21 | Unknown, | 21 | Unknown, |
| 22 | Event, | 22 | WritableEvent, |
| 23 | ReadableEvent, | ||
| 23 | SharedMemory, | 24 | SharedMemory, |
| 24 | Thread, | 25 | Thread, |
| 25 | Process, | 26 | Process, |
| @@ -33,9 +34,9 @@ enum class HandleType : u32 { | |||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | enum class ResetType { | 36 | enum class ResetType { |
| 36 | OneShot, | 37 | OneShot, ///< Reset automatically on object acquisition |
| 37 | Sticky, | 38 | Sticky, ///< Never reset automatically |
| 38 | Pulse, | 39 | Pulse, ///< Reset automatically on wakeup |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 41 | class Object : NonCopyable { | 42 | class Object : NonCopyable { |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 420218d59..4ecb8c926 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -4,12 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <random> | ||
| 7 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/file_sys/program_metadata.h" | 11 | #include "core/file_sys/program_metadata.h" |
| 12 | #include "core/hle/kernel/errors.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/resource_limit.h" | 14 | #include "core/hle/kernel/resource_limit.h" |
| @@ -17,6 +16,7 @@ | |||
| 17 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 18 | #include "core/hle/kernel/vm_manager.h" | 17 | #include "core/hle/kernel/vm_manager.h" |
| 19 | #include "core/memory.h" | 18 | #include "core/memory.h" |
| 19 | #include "core/settings.h" | ||
| 20 | 20 | ||
| 21 | namespace Kernel { | 21 | namespace Kernel { |
| 22 | 22 | ||
| @@ -29,16 +29,25 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | |||
| 29 | process->name = std::move(name); | 29 | process->name = std::move(name); |
| 30 | process->flags.raw = 0; | 30 | process->flags.raw = 0; |
| 31 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | 31 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); |
| 32 | process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); | 32 | process->resource_limit = kernel.GetSystemResourceLimit(); |
| 33 | process->status = ProcessStatus::Created; | 33 | process->status = ProcessStatus::Created; |
| 34 | process->program_id = 0; | 34 | process->program_id = 0; |
| 35 | process->process_id = kernel.CreateNewProcessID(); | 35 | process->process_id = kernel.CreateNewProcessID(); |
| 36 | process->svc_access_mask.set(); | 36 | process->svc_access_mask.set(); |
| 37 | 37 | ||
| 38 | std::mt19937 rng(Settings::values.rng_seed.value_or(0)); | ||
| 39 | std::uniform_int_distribution<u64> distribution; | ||
| 40 | std::generate(process->random_entropy.begin(), process->random_entropy.end(), | ||
| 41 | [&] { return distribution(rng); }); | ||
| 42 | |||
| 38 | kernel.AppendNewProcess(process); | 43 | kernel.AppendNewProcess(process); |
| 39 | return process; | 44 | return process; |
| 40 | } | 45 | } |
| 41 | 46 | ||
| 47 | SharedPtr<ResourceLimit> Process::GetResourceLimit() const { | ||
| 48 | return resource_limit; | ||
| 49 | } | ||
| 50 | |||
| 42 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | 51 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { |
| 43 | program_id = metadata.GetTitleID(); | 52 | program_id = metadata.GetTitleID(); |
| 44 | is_64bit_process = metadata.Is64BitProgram(); | 53 | is_64bit_process = metadata.Is64BitProgram(); |
| @@ -241,83 +250,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||
| 241 | } | 250 | } |
| 242 | 251 | ||
| 243 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { | 252 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { |
| 244 | if (target < vm_manager.GetHeapRegionBaseAddress() || | 253 | return vm_manager.HeapAllocate(target, size, perms); |
| 245 | target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { | ||
| 246 | return ERR_INVALID_ADDRESS; | ||
| 247 | } | ||
| 248 | |||
| 249 | if (heap_memory == nullptr) { | ||
| 250 | // Initialize heap | ||
| 251 | heap_memory = std::make_shared<std::vector<u8>>(); | ||
| 252 | heap_start = heap_end = target; | ||
| 253 | } else { | ||
| 254 | vm_manager.UnmapRange(heap_start, heap_end - heap_start); | ||
| 255 | } | ||
| 256 | |||
| 257 | // If necessary, expand backing vector to cover new heap extents. | ||
| 258 | if (target < heap_start) { | ||
| 259 | heap_memory->insert(begin(*heap_memory), heap_start - target, 0); | ||
| 260 | heap_start = target; | ||
| 261 | vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 262 | } | ||
| 263 | if (target + size > heap_end) { | ||
| 264 | heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); | ||
| 265 | heap_end = target + size; | ||
| 266 | vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 267 | } | ||
| 268 | ASSERT(heap_end - heap_start == heap_memory->size()); | ||
| 269 | |||
| 270 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, | ||
| 271 | size, MemoryState::Heap)); | ||
| 272 | vm_manager.Reprotect(vma, perms); | ||
| 273 | |||
| 274 | heap_used = size; | ||
| 275 | |||
| 276 | return MakeResult<VAddr>(heap_end - size); | ||
| 277 | } | 254 | } |
| 278 | 255 | ||
| 279 | ResultCode Process::HeapFree(VAddr target, u32 size) { | 256 | ResultCode Process::HeapFree(VAddr target, u32 size) { |
| 280 | if (target < vm_manager.GetHeapRegionBaseAddress() || | 257 | return vm_manager.HeapFree(target, size); |
| 281 | target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { | ||
| 282 | return ERR_INVALID_ADDRESS; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (size == 0) { | ||
| 286 | return RESULT_SUCCESS; | ||
| 287 | } | ||
| 288 | |||
| 289 | ResultCode result = vm_manager.UnmapRange(target, size); | ||
| 290 | if (result.IsError()) | ||
| 291 | return result; | ||
| 292 | |||
| 293 | heap_used -= size; | ||
| 294 | |||
| 295 | return RESULT_SUCCESS; | ||
| 296 | } | 258 | } |
| 297 | 259 | ||
| 298 | ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 260 | ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) { |
| 299 | auto vma = vm_manager.FindVMA(src_addr); | 261 | return vm_manager.MirrorMemory(dst_addr, src_addr, size, state); |
| 300 | |||
| 301 | ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); | ||
| 302 | ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); | ||
| 303 | |||
| 304 | // The returned VMA might be a bigger one encompassing the desired address. | ||
| 305 | auto vma_offset = src_addr - vma->first; | ||
| 306 | ASSERT_MSG(vma_offset + size <= vma->second.size, | ||
| 307 | "Shared memory exceeds bounds of mapped block"); | ||
| 308 | |||
| 309 | const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; | ||
| 310 | std::size_t backing_block_offset = vma->second.offset + vma_offset; | ||
| 311 | |||
| 312 | CASCADE_RESULT(auto new_vma, | ||
| 313 | vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, | ||
| 314 | MemoryState::Mapped)); | ||
| 315 | // Protect mirror with permissions from old region | ||
| 316 | vm_manager.Reprotect(new_vma, vma->second.permissions); | ||
| 317 | // Remove permissions from old region | ||
| 318 | vm_manager.Reprotect(vma, VMAPermission::None); | ||
| 319 | |||
| 320 | return RESULT_SUCCESS; | ||
| 321 | } | 262 | } |
| 322 | 263 | ||
| 323 | ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { | 264 | ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 8d2616c79..49345aa66 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -119,6 +119,8 @@ struct CodeSet final { | |||
| 119 | 119 | ||
| 120 | class Process final : public Object { | 120 | class Process final : public Object { |
| 121 | public: | 121 | public: |
| 122 | static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; | ||
| 123 | |||
| 122 | static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); | 124 | static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); |
| 123 | 125 | ||
| 124 | std::string GetTypeName() const override { | 126 | std::string GetTypeName() const override { |
| @@ -169,14 +171,7 @@ public: | |||
| 169 | } | 171 | } |
| 170 | 172 | ||
| 171 | /// Gets the resource limit descriptor for this process | 173 | /// Gets the resource limit descriptor for this process |
| 172 | ResourceLimit& GetResourceLimit() { | 174 | SharedPtr<ResourceLimit> GetResourceLimit() const; |
| 173 | return *resource_limit; | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Gets the resource limit descriptor for this process | ||
| 177 | const ResourceLimit& GetResourceLimit() const { | ||
| 178 | return *resource_limit; | ||
| 179 | } | ||
| 180 | 175 | ||
| 181 | /// Gets the default CPU ID for this process | 176 | /// Gets the default CPU ID for this process |
| 182 | u8 GetDefaultProcessorID() const { | 177 | u8 GetDefaultProcessorID() const { |
| @@ -212,6 +207,11 @@ public: | |||
| 212 | total_process_running_time_ticks += ticks; | 207 | total_process_running_time_ticks += ticks; |
| 213 | } | 208 | } |
| 214 | 209 | ||
| 210 | /// Gets 8 bytes of random data for svcGetInfo RandomEntropy | ||
| 211 | u64 GetRandomEntropy(std::size_t index) const { | ||
| 212 | return random_entropy.at(index); | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | 215 | /** |
| 216 | * Loads process-specifics configuration info with metadata provided | 216 | * Loads process-specifics configuration info with metadata provided |
| 217 | * by an executable. | 217 | * by an executable. |
| @@ -251,7 +251,8 @@ public: | |||
| 251 | ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); | 251 | ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); |
| 252 | ResultCode HeapFree(VAddr target, u32 size); | 252 | ResultCode HeapFree(VAddr target, u32 size); |
| 253 | 253 | ||
| 254 | ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); | 254 | ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, |
| 255 | MemoryState state = MemoryState::Mapped); | ||
| 255 | 256 | ||
| 256 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); | 257 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); |
| 257 | 258 | ||
| @@ -292,17 +293,6 @@ private: | |||
| 292 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; | 293 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; |
| 293 | u32 is_virtual_address_memory_enabled = 0; | 294 | u32 is_virtual_address_memory_enabled = 0; |
| 294 | 295 | ||
| 295 | // Memory used to back the allocations in the regular heap. A single vector is used to cover | ||
| 296 | // the entire virtual address space extents that bound the allocations, including any holes. | ||
| 297 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous | ||
| 298 | // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. | ||
| 299 | std::shared_ptr<std::vector<u8>> heap_memory; | ||
| 300 | |||
| 301 | // The left/right bounds of the address space covered by heap_memory. | ||
| 302 | VAddr heap_start = 0; | ||
| 303 | VAddr heap_end = 0; | ||
| 304 | u64 heap_used = 0; | ||
| 305 | |||
| 306 | /// The Thread Local Storage area is allocated as processes create threads, | 296 | /// The Thread Local Storage area is allocated as processes create threads, |
| 307 | /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part | 297 | /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part |
| 308 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each | 298 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each |
| @@ -321,6 +311,9 @@ private: | |||
| 321 | /// Per-process handle table for storing created object handles in. | 311 | /// Per-process handle table for storing created object handles in. |
| 322 | HandleTable handle_table; | 312 | HandleTable handle_table; |
| 323 | 313 | ||
| 314 | /// Random values for svcGetInfo RandomEntropy | ||
| 315 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; | ||
| 316 | |||
| 324 | std::string name; | 317 | std::string name; |
| 325 | }; | 318 | }; |
| 326 | 319 | ||
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/readable_event.cpp index 8967e602e..92e16b4e6 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/readable_event.cpp | |||
| @@ -4,46 +4,37 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/hle/kernel/event.h" | ||
| 8 | #include "core/hle/kernel/object.h" | 7 | #include "core/hle/kernel/object.h" |
| 8 | #include "core/hle/kernel/readable_event.h" | ||
| 9 | #include "core/hle/kernel/thread.h" | 9 | #include "core/hle/kernel/thread.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | 11 | ||
| 11 | namespace Kernel { | 12 | namespace Kernel { |
| 12 | 13 | ||
| 13 | Event::Event(KernelCore& kernel) : WaitObject{kernel} {} | 14 | ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} |
| 14 | Event::~Event() = default; | 15 | ReadableEvent::~ReadableEvent() = default; |
| 15 | 16 | ||
| 16 | SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { | 17 | bool ReadableEvent::ShouldWait(Thread* thread) const { |
| 17 | SharedPtr<Event> evt(new Event(kernel)); | ||
| 18 | |||
| 19 | evt->signaled = false; | ||
| 20 | evt->reset_type = reset_type; | ||
| 21 | evt->name = std::move(name); | ||
| 22 | |||
| 23 | return evt; | ||
| 24 | } | ||
| 25 | |||
| 26 | bool Event::ShouldWait(Thread* thread) const { | ||
| 27 | return !signaled; | 18 | return !signaled; |
| 28 | } | 19 | } |
| 29 | 20 | ||
| 30 | void Event::Acquire(Thread* thread) { | 21 | void ReadableEvent::Acquire(Thread* thread) { |
| 31 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | 22 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); |
| 32 | 23 | ||
| 33 | if (reset_type == ResetType::OneShot) | 24 | if (reset_type == ResetType::OneShot) |
| 34 | signaled = false; | 25 | signaled = false; |
| 35 | } | 26 | } |
| 36 | 27 | ||
| 37 | void Event::Signal() { | 28 | void ReadableEvent::Signal() { |
| 38 | signaled = true; | 29 | signaled = true; |
| 39 | WakeupAllWaitingThreads(); | 30 | WakeupAllWaitingThreads(); |
| 40 | } | 31 | } |
| 41 | 32 | ||
| 42 | void Event::Clear() { | 33 | void ReadableEvent::Clear() { |
| 43 | signaled = false; | 34 | signaled = false; |
| 44 | } | 35 | } |
| 45 | 36 | ||
| 46 | void Event::WakeupAllWaitingThreads() { | 37 | void ReadableEvent::WakeupAllWaitingThreads() { |
| 47 | WaitObject::WakeupAllWaitingThreads(); | 38 | WaitObject::WakeupAllWaitingThreads(); |
| 48 | 39 | ||
| 49 | if (reset_type == ResetType::Pulse) | 40 | if (reset_type == ResetType::Pulse) |
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h new file mode 100644 index 000000000..867ff3051 --- /dev/null +++ b/src/core/hle/kernel/readable_event.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/object.h" | ||
| 8 | #include "core/hle/kernel/wait_object.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KernelCore; | ||
| 13 | class WritableEvent; | ||
| 14 | |||
| 15 | class ReadableEvent final : public WaitObject { | ||
| 16 | friend class WritableEvent; | ||
| 17 | |||
| 18 | public: | ||
| 19 | ~ReadableEvent() override; | ||
| 20 | |||
| 21 | std::string GetTypeName() const override { | ||
| 22 | return "ReadableEvent"; | ||
| 23 | } | ||
| 24 | std::string GetName() const override { | ||
| 25 | return name; | ||
| 26 | } | ||
| 27 | |||
| 28 | ResetType GetResetType() const { | ||
| 29 | return reset_type; | ||
| 30 | } | ||
| 31 | |||
| 32 | static const HandleType HANDLE_TYPE = HandleType::ReadableEvent; | ||
| 33 | HandleType GetHandleType() const override { | ||
| 34 | return HANDLE_TYPE; | ||
| 35 | } | ||
| 36 | |||
| 37 | bool ShouldWait(Thread* thread) const override; | ||
| 38 | void Acquire(Thread* thread) override; | ||
| 39 | |||
| 40 | void WakeupAllWaitingThreads() override; | ||
| 41 | |||
| 42 | void Clear(); | ||
| 43 | |||
| 44 | private: | ||
| 45 | explicit ReadableEvent(KernelCore& kernel); | ||
| 46 | |||
| 47 | void Signal(); | ||
| 48 | |||
| 49 | ResetType reset_type; | ||
| 50 | bool signaled; | ||
| 51 | |||
| 52 | std::string name; ///< Name of event (optional) | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index b253a680f..2f9695005 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp | |||
| @@ -2,12 +2,16 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include "core/hle/kernel/errors.h" |
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/hle/kernel/resource_limit.h" | 6 | #include "core/hle/kernel/resource_limit.h" |
| 7 | #include "core/hle/result.h" | ||
| 9 | 8 | ||
| 10 | namespace Kernel { | 9 | namespace Kernel { |
| 10 | namespace { | ||
| 11 | constexpr std::size_t ResourceTypeToIndex(ResourceType type) { | ||
| 12 | return static_cast<std::size_t>(type); | ||
| 13 | } | ||
| 14 | } // Anonymous namespace | ||
| 11 | 15 | ||
| 12 | ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} | 16 | ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} |
| 13 | ResourceLimit::~ResourceLimit() = default; | 17 | ResourceLimit::~ResourceLimit() = default; |
| @@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n | |||
| 19 | return resource_limit; | 23 | return resource_limit; |
| 20 | } | 24 | } |
| 21 | 25 | ||
| 22 | s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { | 26 | s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { |
| 23 | switch (resource) { | 27 | return values.at(ResourceTypeToIndex(resource)); |
| 24 | case ResourceType::Commit: | 28 | } |
| 25 | return current_commit; | 29 | |
| 26 | case ResourceType::Thread: | 30 | s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { |
| 27 | return current_threads; | 31 | return limits.at(ResourceTypeToIndex(resource)); |
| 28 | case ResourceType::Event: | ||
| 29 | return current_events; | ||
| 30 | case ResourceType::Mutex: | ||
| 31 | return current_mutexes; | ||
| 32 | case ResourceType::Semaphore: | ||
| 33 | return current_semaphores; | ||
| 34 | case ResourceType::Timer: | ||
| 35 | return current_timers; | ||
| 36 | case ResourceType::SharedMemory: | ||
| 37 | return current_shared_mems; | ||
| 38 | case ResourceType::AddressArbiter: | ||
| 39 | return current_address_arbiters; | ||
| 40 | case ResourceType::CPUTime: | ||
| 41 | return current_cpu_time; | ||
| 42 | default: | ||
| 43 | LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | ||
| 44 | UNIMPLEMENTED(); | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | } | 32 | } |
| 48 | 33 | ||
| 49 | u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { | 34 | ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) { |
| 50 | switch (resource) { | 35 | const auto index = ResourceTypeToIndex(resource); |
| 51 | case ResourceType::Priority: | 36 | |
| 52 | return max_priority; | 37 | if (value < values[index]) { |
| 53 | case ResourceType::Commit: | 38 | return ERR_INVALID_STATE; |
| 54 | return max_commit; | ||
| 55 | case ResourceType::Thread: | ||
| 56 | return max_threads; | ||
| 57 | case ResourceType::Event: | ||
| 58 | return max_events; | ||
| 59 | case ResourceType::Mutex: | ||
| 60 | return max_mutexes; | ||
| 61 | case ResourceType::Semaphore: | ||
| 62 | return max_semaphores; | ||
| 63 | case ResourceType::Timer: | ||
| 64 | return max_timers; | ||
| 65 | case ResourceType::SharedMemory: | ||
| 66 | return max_shared_mems; | ||
| 67 | case ResourceType::AddressArbiter: | ||
| 68 | return max_address_arbiters; | ||
| 69 | case ResourceType::CPUTime: | ||
| 70 | return max_cpu_time; | ||
| 71 | default: | ||
| 72 | LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource)); | ||
| 73 | UNIMPLEMENTED(); | ||
| 74 | return 0; | ||
| 75 | } | 39 | } |
| 40 | |||
| 41 | values[index] = value; | ||
| 42 | return RESULT_SUCCESS; | ||
| 76 | } | 43 | } |
| 77 | } // namespace Kernel | 44 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 219e49562..59dc11c22 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h | |||
| @@ -4,33 +4,31 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "core/hle/kernel/object.h" | 9 | #include "core/hle/kernel/object.h" |
| 9 | 10 | ||
| 11 | union ResultCode; | ||
| 12 | |||
| 10 | namespace Kernel { | 13 | namespace Kernel { |
| 11 | 14 | ||
| 12 | class KernelCore; | 15 | class KernelCore; |
| 13 | 16 | ||
| 14 | enum class ResourceLimitCategory : u8 { | 17 | enum class ResourceType : u32 { |
| 15 | APPLICATION = 0, | 18 | PhysicalMemory, |
| 16 | SYS_APPLET = 1, | 19 | Threads, |
| 17 | LIB_APPLET = 2, | 20 | Events, |
| 18 | OTHER = 3 | 21 | TransferMemory, |
| 19 | }; | 22 | Sessions, |
| 20 | 23 | ||
| 21 | enum class ResourceType { | 24 | // Used as a count, not an actual type. |
| 22 | Priority = 0, | 25 | ResourceTypeCount |
| 23 | Commit = 1, | ||
| 24 | Thread = 2, | ||
| 25 | Event = 3, | ||
| 26 | Mutex = 4, | ||
| 27 | Semaphore = 5, | ||
| 28 | Timer = 6, | ||
| 29 | SharedMemory = 7, | ||
| 30 | AddressArbiter = 8, | ||
| 31 | CPUTime = 9, | ||
| 32 | }; | 26 | }; |
| 33 | 27 | ||
| 28 | constexpr bool IsValidResourceType(ResourceType type) { | ||
| 29 | return type < ResourceType::ResourceTypeCount; | ||
| 30 | } | ||
| 31 | |||
| 34 | class ResourceLimit final : public Object { | 32 | class ResourceLimit final : public Object { |
| 35 | public: | 33 | public: |
| 36 | /** | 34 | /** |
| @@ -55,61 +53,51 @@ public: | |||
| 55 | * @param resource Requested resource type | 53 | * @param resource Requested resource type |
| 56 | * @returns The current value of the resource type | 54 | * @returns The current value of the resource type |
| 57 | */ | 55 | */ |
| 58 | s32 GetCurrentResourceValue(ResourceType resource) const; | 56 | s64 GetCurrentResourceValue(ResourceType resource) const; |
| 59 | 57 | ||
| 60 | /** | 58 | /** |
| 61 | * Gets the max value for the specified resource. | 59 | * Gets the max value for the specified resource. |
| 62 | * @param resource Requested resource type | 60 | * @param resource Requested resource type |
| 63 | * @returns The max value of the resource type | 61 | * @returns The max value of the resource type |
| 64 | */ | 62 | */ |
| 65 | u32 GetMaxResourceValue(ResourceType resource) const; | 63 | s64 GetMaxResourceValue(ResourceType resource) const; |
| 66 | |||
| 67 | /// Name of resource limit object. | ||
| 68 | std::string name; | ||
| 69 | |||
| 70 | /// Max thread priority that a process in this category can create | ||
| 71 | s32 max_priority = 0; | ||
| 72 | |||
| 73 | /// Max memory that processes in this category can use | ||
| 74 | s32 max_commit = 0; | ||
| 75 | 64 | ||
| 76 | ///< Max number of objects that can be collectively created by the processes in this category | 65 | /** |
| 77 | s32 max_threads = 0; | 66 | * Sets the limit value for a given resource type. |
| 78 | s32 max_events = 0; | 67 | * |
| 79 | s32 max_mutexes = 0; | 68 | * @param resource The resource type to apply the limit to. |
| 80 | s32 max_semaphores = 0; | 69 | * @param value The limit to apply to the given resource type. |
| 81 | s32 max_timers = 0; | 70 | * |
| 82 | s32 max_shared_mems = 0; | 71 | * @return A result code indicating if setting the limit value |
| 83 | s32 max_address_arbiters = 0; | 72 | * was successful or not. |
| 73 | * | ||
| 74 | * @note The supplied limit value *must* be greater than or equal to | ||
| 75 | * the current resource value for the given resource type, | ||
| 76 | * otherwise ERR_INVALID_STATE will be returned. | ||
| 77 | */ | ||
| 78 | ResultCode SetLimitValue(ResourceType resource, s64 value); | ||
| 84 | 79 | ||
| 85 | /// Max CPU time that the processes in this category can utilize | 80 | private: |
| 86 | s32 max_cpu_time = 0; | 81 | explicit ResourceLimit(KernelCore& kernel); |
| 82 | ~ResourceLimit() override; | ||
| 87 | 83 | ||
| 88 | // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind | 84 | // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create |
| 89 | // that APPLICATION resource limits should not be affected by the objects created by service | 85 | // functions |
| 90 | // modules. | 86 | // |
| 91 | // Currently we have no way of distinguishing if a Create was called by the running application, | 87 | // Currently we have no way of distinguishing if a Create was called by the running application, |
| 92 | // or by a service module. Approach this once we have separated the service modules into their | 88 | // or by a service module. Approach this once we have separated the service modules into their |
| 93 | // own processes | 89 | // own processes |
| 94 | 90 | ||
| 95 | /// Current memory that the processes in this category are using | 91 | using ResourceArray = |
| 96 | s32 current_commit = 0; | 92 | std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>; |
| 97 | 93 | ||
| 98 | ///< Current number of objects among all processes in this category | 94 | /// Maximum values a resource type may reach. |
| 99 | s32 current_threads = 0; | 95 | ResourceArray limits{}; |
| 100 | s32 current_events = 0; | 96 | /// Current resource limit values. |
| 101 | s32 current_mutexes = 0; | 97 | ResourceArray values{}; |
| 102 | s32 current_semaphores = 0; | ||
| 103 | s32 current_timers = 0; | ||
| 104 | s32 current_shared_mems = 0; | ||
| 105 | s32 current_address_arbiters = 0; | ||
| 106 | 98 | ||
| 107 | /// Current CPU time that the processes in this category are utilizing | 99 | /// Name of resource limit object. |
| 108 | s32 current_cpu_time = 0; | 100 | std::string name; |
| 109 | |||
| 110 | private: | ||
| 111 | explicit ResourceLimit(KernelCore& kernel); | ||
| 112 | ~ResourceLimit() override; | ||
| 113 | }; | 101 | }; |
| 114 | 102 | ||
| 115 | } // namespace Kernel | 103 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index a016a86b6..0494581f5 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -61,7 +61,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | 63 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet( |
| 64 | KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, | 64 | KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, std::size_t offset, u64 size, |
| 65 | MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { | 65 | MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { |
| 66 | SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); | 66 | SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); |
| 67 | 67 | ||
| @@ -78,10 +78,10 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | |||
| 78 | return shared_memory; | 78 | return shared_memory; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, | 81 | ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermission permissions, |
| 82 | MemoryPermission other_permissions) { | 82 | MemoryPermission other_permissions) { |
| 83 | const MemoryPermission own_other_permissions = | 83 | const MemoryPermission own_other_permissions = |
| 84 | target_process == owner_process ? this->permissions : this->other_permissions; | 84 | &target_process == owner_process ? this->permissions : this->other_permissions; |
| 85 | 85 | ||
| 86 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare | 86 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare |
| 87 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { | 87 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { |
| @@ -106,7 +106,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 106 | VAddr target_address = address; | 106 | VAddr target_address = address; |
| 107 | 107 | ||
| 108 | // Map the memory block into the target process | 108 | // Map the memory block into the target process |
| 109 | auto result = target_process->VMManager().MapMemoryBlock( | 109 | auto result = target_process.VMManager().MapMemoryBlock( |
| 110 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 110 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); |
| 111 | if (result.Failed()) { | 111 | if (result.Failed()) { |
| 112 | LOG_ERROR( | 112 | LOG_ERROR( |
| @@ -116,14 +116,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 116 | return result.Code(); | 116 | return result.Code(); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | return target_process->VMManager().ReprotectRange(target_address, size, | 119 | return target_process.VMManager().ReprotectRange(target_address, size, |
| 120 | ConvertPermissions(permissions)); | 120 | ConvertPermissions(permissions)); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | 123 | ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) { |
| 124 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not | 124 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not |
| 125 | // mapped to a SharedMemory. | 125 | // mapped to a SharedMemory. |
| 126 | return target_process->VMManager().UnmapRange(address, size); | 126 | return target_process.VMManager().UnmapRange(address, size); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | 129 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { |
| @@ -132,7 +132,11 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | |||
| 132 | return static_cast<VMAPermission>(masked_permissions); | 132 | return static_cast<VMAPermission>(masked_permissions); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | u8* SharedMemory::GetPointer(u32 offset) { | 135 | u8* SharedMemory::GetPointer(std::size_t offset) { |
| 136 | return backing_block->data() + backing_block_offset + offset; | ||
| 137 | } | ||
| 138 | |||
| 139 | const u8* SharedMemory::GetPointer(std::size_t offset) const { | ||
| 136 | return backing_block->data() + backing_block_offset + offset; | 140 | return backing_block->data() + backing_block_offset + offset; |
| 137 | } | 141 | } |
| 138 | 142 | ||
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 2c06bb7ce..0b48db699 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -64,7 +64,7 @@ public: | |||
| 64 | */ | 64 | */ |
| 65 | static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel, | 65 | static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel, |
| 66 | std::shared_ptr<std::vector<u8>> heap_block, | 66 | std::shared_ptr<std::vector<u8>> heap_block, |
| 67 | u32 offset, u32 size, | 67 | std::size_t offset, u64 size, |
| 68 | MemoryPermission permissions, | 68 | MemoryPermission permissions, |
| 69 | MemoryPermission other_permissions, | 69 | MemoryPermission other_permissions, |
| 70 | std::string name = "Unknown Applet"); | 70 | std::string name = "Unknown Applet"); |
| @@ -81,6 +81,11 @@ public: | |||
| 81 | return HANDLE_TYPE; | 81 | return HANDLE_TYPE; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | /// Gets the size of the underlying memory block in bytes. | ||
| 85 | u64 GetSize() const { | ||
| 86 | return size; | ||
| 87 | } | ||
| 88 | |||
| 84 | /** | 89 | /** |
| 85 | * Converts the specified MemoryPermission into the equivalent VMAPermission. | 90 | * Converts the specified MemoryPermission into the equivalent VMAPermission. |
| 86 | * @param permission The MemoryPermission to convert. | 91 | * @param permission The MemoryPermission to convert. |
| @@ -94,44 +99,51 @@ public: | |||
| 94 | * @param permissions Memory block map permissions (specified by SVC field) | 99 | * @param permissions Memory block map permissions (specified by SVC field) |
| 95 | * @param other_permissions Memory block map other permissions (specified by SVC field) | 100 | * @param other_permissions Memory block map other permissions (specified by SVC field) |
| 96 | */ | 101 | */ |
| 97 | ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, | 102 | ResultCode Map(Process& target_process, VAddr address, MemoryPermission permissions, |
| 98 | MemoryPermission other_permissions); | 103 | MemoryPermission other_permissions); |
| 99 | 104 | ||
| 100 | /** | 105 | /** |
| 101 | * Unmaps a shared memory block from the specified address in system memory | 106 | * Unmaps a shared memory block from the specified address in system memory |
| 102 | * @param target_process Process from which to umap the memory block. | 107 | * @param target_process Process from which to unmap the memory block. |
| 103 | * @param address Address in system memory where the shared memory block is mapped | 108 | * @param address Address in system memory where the shared memory block is mapped |
| 104 | * @return Result code of the unmap operation | 109 | * @return Result code of the unmap operation |
| 105 | */ | 110 | */ |
| 106 | ResultCode Unmap(Process* target_process, VAddr address); | 111 | ResultCode Unmap(Process& target_process, VAddr address); |
| 107 | 112 | ||
| 108 | /** | 113 | /** |
| 109 | * Gets a pointer to the shared memory block | 114 | * Gets a pointer to the shared memory block |
| 110 | * @param offset Offset from the start of the shared memory block to get pointer | 115 | * @param offset Offset from the start of the shared memory block to get pointer |
| 111 | * @return Pointer to the shared memory block from the specified offset | 116 | * @return A pointer to the shared memory block from the specified offset |
| 112 | */ | 117 | */ |
| 113 | u8* GetPointer(u32 offset = 0); | 118 | u8* GetPointer(std::size_t offset = 0); |
| 119 | |||
| 120 | /** | ||
| 121 | * Gets a constant pointer to the shared memory block | ||
| 122 | * @param offset Offset from the start of the shared memory block to get pointer | ||
| 123 | * @return A constant pointer to the shared memory block from the specified offset | ||
| 124 | */ | ||
| 125 | const u8* GetPointer(std::size_t offset = 0) const; | ||
| 126 | |||
| 127 | private: | ||
| 128 | explicit SharedMemory(KernelCore& kernel); | ||
| 129 | ~SharedMemory() override; | ||
| 114 | 130 | ||
| 115 | /// Process that created this shared memory block. | ||
| 116 | SharedPtr<Process> owner_process; | ||
| 117 | /// Address of shared memory block in the owner process if specified. | ||
| 118 | VAddr base_address; | ||
| 119 | /// Backing memory for this shared memory block. | 131 | /// Backing memory for this shared memory block. |
| 120 | std::shared_ptr<std::vector<u8>> backing_block; | 132 | std::shared_ptr<std::vector<u8>> backing_block; |
| 121 | /// Offset into the backing block for this shared memory. | 133 | /// Offset into the backing block for this shared memory. |
| 122 | std::size_t backing_block_offset; | 134 | std::size_t backing_block_offset = 0; |
| 123 | /// Size of the memory block. Page-aligned. | 135 | /// Size of the memory block. Page-aligned. |
| 124 | u64 size; | 136 | u64 size = 0; |
| 125 | /// Permission restrictions applied to the process which created the block. | 137 | /// Permission restrictions applied to the process which created the block. |
| 126 | MemoryPermission permissions; | 138 | MemoryPermission permissions{}; |
| 127 | /// Permission restrictions applied to other processes mapping the block. | 139 | /// Permission restrictions applied to other processes mapping the block. |
| 128 | MemoryPermission other_permissions; | 140 | MemoryPermission other_permissions{}; |
| 141 | /// Process that created this shared memory block. | ||
| 142 | SharedPtr<Process> owner_process; | ||
| 143 | /// Address of shared memory block in the owner process if specified. | ||
| 144 | VAddr base_address = 0; | ||
| 129 | /// Name of shared memory object. | 145 | /// Name of shared memory object. |
| 130 | std::string name; | 146 | std::string name; |
| 131 | |||
| 132 | private: | ||
| 133 | explicit SharedMemory(KernelCore& kernel); | ||
| 134 | ~SharedMemory() override; | ||
| 135 | }; | 147 | }; |
| 136 | 148 | ||
| 137 | } // namespace Kernel | 149 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7e8e87c33..e6c77f9db 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -20,17 +20,18 @@ | |||
| 20 | #include "core/hle/kernel/address_arbiter.h" | 20 | #include "core/hle/kernel/address_arbiter.h" |
| 21 | #include "core/hle/kernel/client_port.h" | 21 | #include "core/hle/kernel/client_port.h" |
| 22 | #include "core/hle/kernel/client_session.h" | 22 | #include "core/hle/kernel/client_session.h" |
| 23 | #include "core/hle/kernel/event.h" | ||
| 24 | #include "core/hle/kernel/handle_table.h" | 23 | #include "core/hle/kernel/handle_table.h" |
| 25 | #include "core/hle/kernel/kernel.h" | 24 | #include "core/hle/kernel/kernel.h" |
| 26 | #include "core/hle/kernel/mutex.h" | 25 | #include "core/hle/kernel/mutex.h" |
| 27 | #include "core/hle/kernel/process.h" | 26 | #include "core/hle/kernel/process.h" |
| 27 | #include "core/hle/kernel/readable_event.h" | ||
| 28 | #include "core/hle/kernel/resource_limit.h" | 28 | #include "core/hle/kernel/resource_limit.h" |
| 29 | #include "core/hle/kernel/scheduler.h" | 29 | #include "core/hle/kernel/scheduler.h" |
| 30 | #include "core/hle/kernel/shared_memory.h" | 30 | #include "core/hle/kernel/shared_memory.h" |
| 31 | #include "core/hle/kernel/svc.h" | 31 | #include "core/hle/kernel/svc.h" |
| 32 | #include "core/hle/kernel/svc_wrap.h" | 32 | #include "core/hle/kernel/svc_wrap.h" |
| 33 | #include "core/hle/kernel/thread.h" | 33 | #include "core/hle/kernel/thread.h" |
| 34 | #include "core/hle/kernel/writable_event.h" | ||
| 34 | #include "core/hle/lock.h" | 35 | #include "core/hle/lock.h" |
| 35 | #include "core/hle/result.h" | 36 | #include "core/hle/result.h" |
| 36 | #include "core/hle/service/service.h" | 37 | #include "core/hle/service/service.h" |
| @@ -62,56 +63,129 @@ bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { | |||
| 62 | vm.GetNewMapRegionEndAddress()); | 63 | vm.GetNewMapRegionEndAddress()); |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 66 | // 8 GiB | ||
| 67 | constexpr u64 MAIN_MEMORY_SIZE = 0x200000000; | ||
| 68 | |||
| 65 | // Helper function that performs the common sanity checks for svcMapMemory | 69 | // Helper function that performs the common sanity checks for svcMapMemory |
| 66 | // and svcUnmapMemory. This is doable, as both functions perform their sanitizing | 70 | // and svcUnmapMemory. This is doable, as both functions perform their sanitizing |
| 67 | // in the same order. | 71 | // in the same order. |
| 68 | ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, | 72 | ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, |
| 69 | u64 size) { | 73 | u64 size) { |
| 70 | if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) { | 74 | if (!Common::Is4KBAligned(dst_addr)) { |
| 75 | LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr); | ||
| 71 | return ERR_INVALID_ADDRESS; | 76 | return ERR_INVALID_ADDRESS; |
| 72 | } | 77 | } |
| 73 | 78 | ||
| 74 | if (size == 0 || !Common::Is4KBAligned(size)) { | 79 | if (!Common::Is4KBAligned(src_addr)) { |
| 80 | LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr); | ||
| 81 | return ERR_INVALID_SIZE; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (size == 0) { | ||
| 85 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 86 | return ERR_INVALID_SIZE; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (!Common::Is4KBAligned(size)) { | ||
| 90 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); | ||
| 75 | return ERR_INVALID_SIZE; | 91 | return ERR_INVALID_SIZE; |
| 76 | } | 92 | } |
| 77 | 93 | ||
| 78 | if (!IsValidAddressRange(dst_addr, size)) { | 94 | if (!IsValidAddressRange(dst_addr, size)) { |
| 95 | LOG_ERROR(Kernel_SVC, | ||
| 96 | "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 97 | dst_addr, size); | ||
| 79 | return ERR_INVALID_ADDRESS_STATE; | 98 | return ERR_INVALID_ADDRESS_STATE; |
| 80 | } | 99 | } |
| 81 | 100 | ||
| 82 | if (!IsValidAddressRange(src_addr, size)) { | 101 | if (!IsValidAddressRange(src_addr, size)) { |
| 102 | LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 103 | src_addr, size); | ||
| 83 | return ERR_INVALID_ADDRESS_STATE; | 104 | return ERR_INVALID_ADDRESS_STATE; |
| 84 | } | 105 | } |
| 85 | 106 | ||
| 86 | if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { | 107 | if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { |
| 108 | LOG_ERROR(Kernel_SVC, | ||
| 109 | "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", | ||
| 110 | src_addr, size); | ||
| 87 | return ERR_INVALID_ADDRESS_STATE; | 111 | return ERR_INVALID_ADDRESS_STATE; |
| 88 | } | 112 | } |
| 89 | 113 | ||
| 90 | if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { | 114 | if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { |
| 115 | LOG_ERROR(Kernel_SVC, | ||
| 116 | "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}", | ||
| 117 | dst_addr, size); | ||
| 91 | return ERR_INVALID_MEMORY_RANGE; | 118 | return ERR_INVALID_MEMORY_RANGE; |
| 92 | } | 119 | } |
| 93 | 120 | ||
| 94 | const VAddr dst_end_address = dst_addr + size; | 121 | const VAddr dst_end_address = dst_addr + size; |
| 95 | if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && | 122 | if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && |
| 96 | vm_manager.GetHeapRegionEndAddress() > dst_addr) { | 123 | vm_manager.GetHeapRegionEndAddress() > dst_addr) { |
| 124 | LOG_ERROR(Kernel_SVC, | ||
| 125 | "Destination does not fit within the heap region, addr=0x{:016X}, " | ||
| 126 | "size=0x{:016X}, end_addr=0x{:016X}", | ||
| 127 | dst_addr, size, dst_end_address); | ||
| 97 | return ERR_INVALID_MEMORY_RANGE; | 128 | return ERR_INVALID_MEMORY_RANGE; |
| 98 | } | 129 | } |
| 99 | 130 | ||
| 100 | if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && | 131 | if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && |
| 101 | vm_manager.GetMapRegionEndAddress() > dst_addr) { | 132 | vm_manager.GetMapRegionEndAddress() > dst_addr) { |
| 133 | LOG_ERROR(Kernel_SVC, | ||
| 134 | "Destination does not fit within the map region, addr=0x{:016X}, " | ||
| 135 | "size=0x{:016X}, end_addr=0x{:016X}", | ||
| 136 | dst_addr, size, dst_end_address); | ||
| 102 | return ERR_INVALID_MEMORY_RANGE; | 137 | return ERR_INVALID_MEMORY_RANGE; |
| 103 | } | 138 | } |
| 104 | 139 | ||
| 105 | return RESULT_SUCCESS; | 140 | return RESULT_SUCCESS; |
| 106 | } | 141 | } |
| 142 | |||
| 143 | enum class ResourceLimitValueType { | ||
| 144 | CurrentValue, | ||
| 145 | LimitValue, | ||
| 146 | }; | ||
| 147 | |||
| 148 | ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type, | ||
| 149 | ResourceLimitValueType value_type) { | ||
| 150 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 151 | if (!IsValidResourceType(type)) { | ||
| 152 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 153 | return ERR_INVALID_ENUM_VALUE; | ||
| 154 | } | ||
| 155 | |||
| 156 | const auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 157 | const auto* const current_process = kernel.CurrentProcess(); | ||
| 158 | ASSERT(current_process != nullptr); | ||
| 159 | |||
| 160 | const auto resource_limit_object = | ||
| 161 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 162 | if (!resource_limit_object) { | ||
| 163 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 164 | resource_limit); | ||
| 165 | return ERR_INVALID_HANDLE; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (value_type == ResourceLimitValueType::CurrentValue) { | ||
| 169 | return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); | ||
| 170 | } | ||
| 171 | |||
| 172 | return MakeResult(resource_limit_object->GetMaxResourceValue(type)); | ||
| 173 | } | ||
| 107 | } // Anonymous namespace | 174 | } // Anonymous namespace |
| 108 | 175 | ||
| 109 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 176 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 110 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 177 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 111 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 178 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); |
| 112 | 179 | ||
| 113 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. | 180 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. |
| 114 | if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { | 181 | if ((heap_size % 0x200000) != 0) { |
| 182 | LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}", | ||
| 183 | heap_size); | ||
| 184 | return ERR_INVALID_SIZE; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (heap_size >= 0x200000000) { | ||
| 188 | LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size); | ||
| 115 | return ERR_INVALID_SIZE; | 189 | return ERR_INVALID_SIZE; |
| 116 | } | 190 | } |
| 117 | 191 | ||
| @@ -122,6 +196,63 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | |||
| 122 | return RESULT_SUCCESS; | 196 | return RESULT_SUCCESS; |
| 123 | } | 197 | } |
| 124 | 198 | ||
| 199 | static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { | ||
| 200 | LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); | ||
| 201 | |||
| 202 | if (!Common::Is4KBAligned(addr)) { | ||
| 203 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 204 | return ERR_INVALID_ADDRESS; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (size == 0) { | ||
| 208 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 209 | return ERR_INVALID_SIZE; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (!Common::Is4KBAligned(size)) { | ||
| 213 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 214 | return ERR_INVALID_SIZE; | ||
| 215 | } | ||
| 216 | |||
| 217 | if (!IsValidAddressRange(addr, size)) { | ||
| 218 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 219 | addr, size); | ||
| 220 | return ERR_INVALID_ADDRESS_STATE; | ||
| 221 | } | ||
| 222 | |||
| 223 | const auto permission = static_cast<MemoryPermission>(prot); | ||
| 224 | if (permission != MemoryPermission::None && permission != MemoryPermission::Read && | ||
| 225 | permission != MemoryPermission::ReadWrite) { | ||
| 226 | LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}", | ||
| 227 | static_cast<u32>(permission)); | ||
| 228 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 229 | } | ||
| 230 | |||
| 231 | auto* const current_process = Core::CurrentProcess(); | ||
| 232 | auto& vm_manager = current_process->VMManager(); | ||
| 233 | |||
| 234 | if (!IsInsideAddressSpace(vm_manager, addr, size)) { | ||
| 235 | LOG_ERROR(Kernel_SVC, | ||
| 236 | "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, | ||
| 237 | size); | ||
| 238 | return ERR_INVALID_ADDRESS_STATE; | ||
| 239 | } | ||
| 240 | |||
| 241 | const VMManager::VMAHandle iter = vm_manager.FindVMA(addr); | ||
| 242 | if (iter == vm_manager.vma_map.end()) { | ||
| 243 | LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr); | ||
| 244 | return ERR_INVALID_ADDRESS_STATE; | ||
| 245 | } | ||
| 246 | |||
| 247 | LOG_WARNING(Kernel_SVC, "Uniformity check on protected memory is not implemented."); | ||
| 248 | // TODO: Performs a uniformity check to make sure only protected memory is changed (it doesn't | ||
| 249 | // make sense to allow changing permissions on kernel memory itself, etc). | ||
| 250 | |||
| 251 | const auto converted_permissions = SharedMemory::ConvertPermissions(permission); | ||
| 252 | |||
| 253 | return vm_manager.ReprotectRange(addr, size, converted_permissions); | ||
| 254 | } | ||
| 255 | |||
| 125 | static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { | 256 | static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { |
| 126 | LOG_WARNING(Kernel_SVC, | 257 | LOG_WARNING(Kernel_SVC, |
| 127 | "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr, | 258 | "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr, |
| @@ -164,6 +295,9 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | |||
| 164 | /// Connect to an OS service given the port name, returns the handle to the port to out | 295 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 165 | static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { | 296 | static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { |
| 166 | if (!Memory::IsValidVirtualAddress(port_name_address)) { | 297 | if (!Memory::IsValidVirtualAddress(port_name_address)) { |
| 298 | LOG_ERROR(Kernel_SVC, | ||
| 299 | "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", | ||
| 300 | port_name_address); | ||
| 167 | return ERR_NOT_FOUND; | 301 | return ERR_NOT_FOUND; |
| 168 | } | 302 | } |
| 169 | 303 | ||
| @@ -171,7 +305,9 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address | |||
| 171 | // Read 1 char beyond the max allowed port name to detect names that are too long. | 305 | // Read 1 char beyond the max allowed port name to detect names that are too long. |
| 172 | std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); | 306 | std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); |
| 173 | if (port_name.size() > PortNameMaxLength) { | 307 | if (port_name.size() > PortNameMaxLength) { |
| 174 | return ERR_PORT_NAME_TOO_LONG; | 308 | LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, |
| 309 | port_name.size()); | ||
| 310 | return ERR_OUT_OF_RANGE; | ||
| 175 | } | 311 | } |
| 176 | 312 | ||
| 177 | LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); | 313 | LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); |
| @@ -219,6 +355,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | |||
| 219 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 355 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 220 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 356 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 221 | if (!thread) { | 357 | if (!thread) { |
| 358 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); | ||
| 222 | return ERR_INVALID_HANDLE; | 359 | return ERR_INVALID_HANDLE; |
| 223 | } | 360 | } |
| 224 | 361 | ||
| @@ -233,6 +370,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | |||
| 233 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 370 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 234 | const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); | 371 | const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); |
| 235 | if (!process) { | 372 | if (!process) { |
| 373 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 374 | process_handle); | ||
| 236 | return ERR_INVALID_HANDLE; | 375 | return ERR_INVALID_HANDLE; |
| 237 | } | 376 | } |
| 238 | 377 | ||
| @@ -262,13 +401,20 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 262 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 401 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", |
| 263 | handles_address, handle_count, nano_seconds); | 402 | handles_address, handle_count, nano_seconds); |
| 264 | 403 | ||
| 265 | if (!Memory::IsValidVirtualAddress(handles_address)) | 404 | if (!Memory::IsValidVirtualAddress(handles_address)) { |
| 405 | LOG_ERROR(Kernel_SVC, | ||
| 406 | "Handle address is not a valid virtual address, handle_address=0x{:016X}", | ||
| 407 | handles_address); | ||
| 266 | return ERR_INVALID_POINTER; | 408 | return ERR_INVALID_POINTER; |
| 409 | } | ||
| 267 | 410 | ||
| 268 | static constexpr u64 MaxHandles = 0x40; | 411 | static constexpr u64 MaxHandles = 0x40; |
| 269 | 412 | ||
| 270 | if (handle_count > MaxHandles) | 413 | if (handle_count > MaxHandles) { |
| 271 | return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge); | 414 | LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", |
| 415 | MaxHandles, handle_count); | ||
| 416 | return ERR_OUT_OF_RANGE; | ||
| 417 | } | ||
| 272 | 418 | ||
| 273 | auto* const thread = GetCurrentThread(); | 419 | auto* const thread = GetCurrentThread(); |
| 274 | 420 | ||
| @@ -281,6 +427,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 281 | const auto object = handle_table.Get<WaitObject>(handle); | 427 | const auto object = handle_table.Get<WaitObject>(handle); |
| 282 | 428 | ||
| 283 | if (object == nullptr) { | 429 | if (object == nullptr) { |
| 430 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); | ||
| 284 | return ERR_INVALID_HANDLE; | 431 | return ERR_INVALID_HANDLE; |
| 285 | } | 432 | } |
| 286 | 433 | ||
| @@ -304,11 +451,13 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 304 | 451 | ||
| 305 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | 452 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 306 | // suspending the thread. | 453 | // suspending the thread. |
| 307 | if (nano_seconds == 0) | 454 | if (nano_seconds == 0) { |
| 308 | return RESULT_TIMEOUT; | 455 | return RESULT_TIMEOUT; |
| 456 | } | ||
| 309 | 457 | ||
| 310 | for (auto& object : objects) | 458 | for (auto& object : objects) { |
| 311 | object->AddWaitingThread(thread); | 459 | object->AddWaitingThread(thread); |
| 460 | } | ||
| 312 | 461 | ||
| 313 | thread->SetWaitObjects(std::move(objects)); | 462 | thread->SetWaitObjects(std::move(objects)); |
| 314 | thread->SetStatus(ThreadStatus::WaitSynchAny); | 463 | thread->SetStatus(ThreadStatus::WaitSynchAny); |
| @@ -329,12 +478,13 @@ static ResultCode CancelSynchronization(Handle thread_handle) { | |||
| 329 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 478 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 330 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 479 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 331 | if (!thread) { | 480 | if (!thread) { |
| 481 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 482 | thread_handle); | ||
| 332 | return ERR_INVALID_HANDLE; | 483 | return ERR_INVALID_HANDLE; |
| 333 | } | 484 | } |
| 334 | 485 | ||
| 335 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); | 486 | ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); |
| 336 | thread->SetWaitSynchronizationResult( | 487 | thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); |
| 337 | ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled)); | ||
| 338 | thread->ResumeFromWait(); | 488 | thread->ResumeFromWait(); |
| 339 | return RESULT_SUCCESS; | 489 | return RESULT_SUCCESS; |
| 340 | } | 490 | } |
| @@ -348,10 +498,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 348 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 498 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 349 | 499 | ||
| 350 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | 500 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { |
| 501 | LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", | ||
| 502 | mutex_addr); | ||
| 351 | return ERR_INVALID_ADDRESS_STATE; | 503 | return ERR_INVALID_ADDRESS_STATE; |
| 352 | } | 504 | } |
| 353 | 505 | ||
| 354 | if (!Common::IsWordAligned(mutex_addr)) { | 506 | if (!Common::IsWordAligned(mutex_addr)) { |
| 507 | LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr); | ||
| 355 | return ERR_INVALID_ADDRESS; | 508 | return ERR_INVALID_ADDRESS; |
| 356 | } | 509 | } |
| 357 | 510 | ||
| @@ -365,10 +518,13 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | |||
| 365 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); | 518 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); |
| 366 | 519 | ||
| 367 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | 520 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { |
| 521 | LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", | ||
| 522 | mutex_addr); | ||
| 368 | return ERR_INVALID_ADDRESS_STATE; | 523 | return ERR_INVALID_ADDRESS_STATE; |
| 369 | } | 524 | } |
| 370 | 525 | ||
| 371 | if (!Common::IsWordAligned(mutex_addr)) { | 526 | if (!Common::IsWordAligned(mutex_addr)) { |
| 527 | LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr); | ||
| 372 | return ERR_INVALID_ADDRESS; | 528 | return ERR_INVALID_ADDRESS; |
| 373 | } | 529 | } |
| 374 | 530 | ||
| @@ -506,7 +662,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 506 | TotalMemoryUsage = 6, | 662 | TotalMemoryUsage = 6, |
| 507 | TotalHeapUsage = 7, | 663 | TotalHeapUsage = 7, |
| 508 | IsCurrentProcessBeingDebugged = 8, | 664 | IsCurrentProcessBeingDebugged = 8, |
| 509 | ResourceHandleLimit = 9, | 665 | RegisterResourceLimit = 9, |
| 510 | IdleTickCount = 10, | 666 | IdleTickCount = 10, |
| 511 | RandomEntropy = 11, | 667 | RandomEntropy = 11, |
| 512 | PerformanceCounter = 0xF0000002, | 668 | PerformanceCounter = 0xF0000002, |
| @@ -526,77 +682,172 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 526 | ThreadTickCount = 0xF0000002, | 682 | ThreadTickCount = 0xF0000002, |
| 527 | }; | 683 | }; |
| 528 | 684 | ||
| 529 | const auto* current_process = Core::CurrentProcess(); | 685 | const auto info_id_type = static_cast<GetInfoType>(info_id); |
| 530 | const auto& vm_manager = current_process->VMManager(); | ||
| 531 | 686 | ||
| 532 | switch (static_cast<GetInfoType>(info_id)) { | 687 | switch (info_id_type) { |
| 533 | case GetInfoType::AllowedCpuIdBitmask: | 688 | case GetInfoType::AllowedCpuIdBitmask: |
| 534 | *result = current_process->GetAllowedProcessorMask(); | ||
| 535 | break; | ||
| 536 | case GetInfoType::AllowedThreadPrioBitmask: | 689 | case GetInfoType::AllowedThreadPrioBitmask: |
| 537 | *result = current_process->GetAllowedThreadPriorityMask(); | ||
| 538 | break; | ||
| 539 | case GetInfoType::MapRegionBaseAddr: | 690 | case GetInfoType::MapRegionBaseAddr: |
| 540 | *result = vm_manager.GetMapRegionBaseAddress(); | ||
| 541 | break; | ||
| 542 | case GetInfoType::MapRegionSize: | 691 | case GetInfoType::MapRegionSize: |
| 543 | *result = vm_manager.GetMapRegionSize(); | ||
| 544 | break; | ||
| 545 | case GetInfoType::HeapRegionBaseAddr: | 692 | case GetInfoType::HeapRegionBaseAddr: |
| 546 | *result = vm_manager.GetHeapRegionBaseAddress(); | ||
| 547 | break; | ||
| 548 | case GetInfoType::HeapRegionSize: | 693 | case GetInfoType::HeapRegionSize: |
| 549 | *result = vm_manager.GetHeapRegionSize(); | ||
| 550 | break; | ||
| 551 | case GetInfoType::TotalMemoryUsage: | ||
| 552 | *result = vm_manager.GetTotalMemoryUsage(); | ||
| 553 | break; | ||
| 554 | case GetInfoType::TotalHeapUsage: | ||
| 555 | *result = vm_manager.GetTotalHeapUsage(); | ||
| 556 | break; | ||
| 557 | case GetInfoType::IsCurrentProcessBeingDebugged: | ||
| 558 | *result = 0; | ||
| 559 | break; | ||
| 560 | case GetInfoType::RandomEntropy: | ||
| 561 | *result = 0; | ||
| 562 | break; | ||
| 563 | case GetInfoType::ASLRRegionBaseAddr: | 694 | case GetInfoType::ASLRRegionBaseAddr: |
| 564 | *result = vm_manager.GetASLRRegionBaseAddress(); | ||
| 565 | break; | ||
| 566 | case GetInfoType::ASLRRegionSize: | 695 | case GetInfoType::ASLRRegionSize: |
| 567 | *result = vm_manager.GetASLRRegionSize(); | ||
| 568 | break; | ||
| 569 | case GetInfoType::NewMapRegionBaseAddr: | 696 | case GetInfoType::NewMapRegionBaseAddr: |
| 570 | *result = vm_manager.GetNewMapRegionBaseAddress(); | ||
| 571 | break; | ||
| 572 | case GetInfoType::NewMapRegionSize: | 697 | case GetInfoType::NewMapRegionSize: |
| 573 | *result = vm_manager.GetNewMapRegionSize(); | 698 | case GetInfoType::TotalMemoryUsage: |
| 574 | break; | 699 | case GetInfoType::TotalHeapUsage: |
| 575 | case GetInfoType::IsVirtualAddressMemoryEnabled: | 700 | case GetInfoType::IsVirtualAddressMemoryEnabled: |
| 576 | *result = current_process->IsVirtualMemoryEnabled(); | 701 | case GetInfoType::PersonalMmHeapUsage: |
| 577 | break; | ||
| 578 | case GetInfoType::TitleId: | 702 | case GetInfoType::TitleId: |
| 579 | *result = current_process->GetTitleID(); | 703 | case GetInfoType::UserExceptionContextAddr: { |
| 580 | break; | 704 | if (info_sub_id != 0) { |
| 705 | return ERR_INVALID_ENUM_VALUE; | ||
| 706 | } | ||
| 707 | |||
| 708 | const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable(); | ||
| 709 | const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); | ||
| 710 | if (!process) { | ||
| 711 | return ERR_INVALID_HANDLE; | ||
| 712 | } | ||
| 713 | |||
| 714 | switch (info_id_type) { | ||
| 715 | case GetInfoType::AllowedCpuIdBitmask: | ||
| 716 | *result = process->GetAllowedProcessorMask(); | ||
| 717 | return RESULT_SUCCESS; | ||
| 718 | |||
| 719 | case GetInfoType::AllowedThreadPrioBitmask: | ||
| 720 | *result = process->GetAllowedThreadPriorityMask(); | ||
| 721 | return RESULT_SUCCESS; | ||
| 722 | |||
| 723 | case GetInfoType::MapRegionBaseAddr: | ||
| 724 | *result = process->VMManager().GetMapRegionBaseAddress(); | ||
| 725 | return RESULT_SUCCESS; | ||
| 726 | |||
| 727 | case GetInfoType::MapRegionSize: | ||
| 728 | *result = process->VMManager().GetMapRegionSize(); | ||
| 729 | return RESULT_SUCCESS; | ||
| 730 | |||
| 731 | case GetInfoType::HeapRegionBaseAddr: | ||
| 732 | *result = process->VMManager().GetHeapRegionBaseAddress(); | ||
| 733 | return RESULT_SUCCESS; | ||
| 734 | |||
| 735 | case GetInfoType::HeapRegionSize: | ||
| 736 | *result = process->VMManager().GetHeapRegionSize(); | ||
| 737 | return RESULT_SUCCESS; | ||
| 738 | |||
| 739 | case GetInfoType::ASLRRegionBaseAddr: | ||
| 740 | *result = process->VMManager().GetASLRRegionBaseAddress(); | ||
| 741 | return RESULT_SUCCESS; | ||
| 742 | |||
| 743 | case GetInfoType::ASLRRegionSize: | ||
| 744 | *result = process->VMManager().GetASLRRegionSize(); | ||
| 745 | return RESULT_SUCCESS; | ||
| 746 | |||
| 747 | case GetInfoType::NewMapRegionBaseAddr: | ||
| 748 | *result = process->VMManager().GetNewMapRegionBaseAddress(); | ||
| 749 | return RESULT_SUCCESS; | ||
| 750 | |||
| 751 | case GetInfoType::NewMapRegionSize: | ||
| 752 | *result = process->VMManager().GetNewMapRegionSize(); | ||
| 753 | return RESULT_SUCCESS; | ||
| 754 | |||
| 755 | case GetInfoType::TotalMemoryUsage: | ||
| 756 | *result = process->VMManager().GetTotalMemoryUsage(); | ||
| 757 | return RESULT_SUCCESS; | ||
| 758 | |||
| 759 | case GetInfoType::TotalHeapUsage: | ||
| 760 | *result = process->VMManager().GetTotalHeapUsage(); | ||
| 761 | return RESULT_SUCCESS; | ||
| 762 | |||
| 763 | case GetInfoType::IsVirtualAddressMemoryEnabled: | ||
| 764 | *result = process->IsVirtualMemoryEnabled(); | ||
| 765 | return RESULT_SUCCESS; | ||
| 766 | |||
| 767 | case GetInfoType::TitleId: | ||
| 768 | *result = process->GetTitleID(); | ||
| 769 | return RESULT_SUCCESS; | ||
| 770 | |||
| 771 | case GetInfoType::UserExceptionContextAddr: | ||
| 772 | LOG_WARNING(Kernel_SVC, | ||
| 773 | "(STUBBED) Attempted to query user exception context address, returned 0"); | ||
| 774 | *result = 0; | ||
| 775 | return RESULT_SUCCESS; | ||
| 776 | |||
| 777 | default: | ||
| 778 | break; | ||
| 779 | } | ||
| 780 | |||
| 781 | LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); | ||
| 782 | return ERR_INVALID_ENUM_VALUE; | ||
| 783 | } | ||
| 784 | |||
| 785 | case GetInfoType::IsCurrentProcessBeingDebugged: | ||
| 786 | *result = 0; | ||
| 787 | return RESULT_SUCCESS; | ||
| 788 | |||
| 789 | case GetInfoType::RegisterResourceLimit: { | ||
| 790 | if (handle != 0) { | ||
| 791 | return ERR_INVALID_HANDLE; | ||
| 792 | } | ||
| 793 | |||
| 794 | if (info_sub_id != 0) { | ||
| 795 | return ERR_INVALID_COMBINATION; | ||
| 796 | } | ||
| 797 | |||
| 798 | Process* const current_process = Core::CurrentProcess(); | ||
| 799 | HandleTable& handle_table = current_process->GetHandleTable(); | ||
| 800 | const auto resource_limit = current_process->GetResourceLimit(); | ||
| 801 | if (!resource_limit) { | ||
| 802 | *result = KernelHandle::InvalidHandle; | ||
| 803 | // Yes, the kernel considers this a successful operation. | ||
| 804 | return RESULT_SUCCESS; | ||
| 805 | } | ||
| 806 | |||
| 807 | const auto table_result = handle_table.Create(resource_limit); | ||
| 808 | if (table_result.Failed()) { | ||
| 809 | return table_result.Code(); | ||
| 810 | } | ||
| 811 | |||
| 812 | *result = *table_result; | ||
| 813 | return RESULT_SUCCESS; | ||
| 814 | } | ||
| 815 | |||
| 816 | case GetInfoType::RandomEntropy: | ||
| 817 | if (handle != 0) { | ||
| 818 | LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", | ||
| 819 | handle); | ||
| 820 | return ERR_INVALID_HANDLE; | ||
| 821 | } | ||
| 822 | |||
| 823 | if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { | ||
| 824 | LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", | ||
| 825 | Process::RANDOM_ENTROPY_SIZE, info_sub_id); | ||
| 826 | return ERR_INVALID_COMBINATION; | ||
| 827 | } | ||
| 828 | |||
| 829 | *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id); | ||
| 830 | return RESULT_SUCCESS; | ||
| 831 | |||
| 581 | case GetInfoType::PrivilegedProcessId: | 832 | case GetInfoType::PrivilegedProcessId: |
| 582 | LOG_WARNING(Kernel_SVC, | 833 | LOG_WARNING(Kernel_SVC, |
| 583 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); | 834 | "(STUBBED) Attempted to query privileged process id bounds, returned 0"); |
| 584 | *result = 0; | 835 | *result = 0; |
| 585 | break; | 836 | return RESULT_SUCCESS; |
| 586 | case GetInfoType::UserExceptionContextAddr: | 837 | |
| 587 | LOG_WARNING(Kernel_SVC, | ||
| 588 | "(STUBBED) Attempted to query user exception context address, returned 0"); | ||
| 589 | *result = 0; | ||
| 590 | break; | ||
| 591 | case GetInfoType::ThreadTickCount: { | 838 | case GetInfoType::ThreadTickCount: { |
| 592 | constexpr u64 num_cpus = 4; | 839 | constexpr u64 num_cpus = 4; |
| 593 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { | 840 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { |
| 594 | return ERR_INVALID_COMBINATION_KERNEL; | 841 | LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, |
| 842 | info_sub_id); | ||
| 843 | return ERR_INVALID_COMBINATION; | ||
| 595 | } | 844 | } |
| 596 | 845 | ||
| 597 | const auto thread = | 846 | const auto thread = |
| 598 | current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); | 847 | Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); |
| 599 | if (!thread) { | 848 | if (!thread) { |
| 849 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | ||
| 850 | static_cast<Handle>(handle)); | ||
| 600 | return ERR_INVALID_HANDLE; | 851 | return ERR_INVALID_HANDLE; |
| 601 | } | 852 | } |
| 602 | 853 | ||
| @@ -616,13 +867,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 616 | } | 867 | } |
| 617 | 868 | ||
| 618 | *result = out_ticks; | 869 | *result = out_ticks; |
| 619 | break; | 870 | return RESULT_SUCCESS; |
| 620 | } | 871 | } |
| 872 | |||
| 621 | default: | 873 | default: |
| 622 | UNIMPLEMENTED(); | 874 | LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); |
| 875 | return ERR_INVALID_ENUM_VALUE; | ||
| 623 | } | 876 | } |
| 624 | |||
| 625 | return RESULT_SUCCESS; | ||
| 626 | } | 877 | } |
| 627 | 878 | ||
| 628 | /// Sets the thread activity | 879 | /// Sets the thread activity |
| @@ -638,14 +889,22 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { | |||
| 638 | const auto* current_process = Core::CurrentProcess(); | 889 | const auto* current_process = Core::CurrentProcess(); |
| 639 | const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 890 | const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); |
| 640 | if (!thread) { | 891 | if (!thread) { |
| 892 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 641 | return ERR_INVALID_HANDLE; | 893 | return ERR_INVALID_HANDLE; |
| 642 | } | 894 | } |
| 643 | 895 | ||
| 644 | if (thread->GetOwnerProcess() != current_process) { | 896 | if (thread->GetOwnerProcess() != current_process) { |
| 897 | LOG_ERROR(Kernel_SVC, | ||
| 898 | "The current process does not own the current thread, thread_handle={:08X} " | ||
| 899 | "thread_pid={}, " | ||
| 900 | "current_process_pid={}", | ||
| 901 | handle, thread->GetOwnerProcess()->GetProcessID(), | ||
| 902 | current_process->GetProcessID()); | ||
| 645 | return ERR_INVALID_HANDLE; | 903 | return ERR_INVALID_HANDLE; |
| 646 | } | 904 | } |
| 647 | 905 | ||
| 648 | if (thread == GetCurrentThread()) { | 906 | if (thread == GetCurrentThread()) { |
| 907 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | ||
| 649 | return ERR_ALREADY_REGISTERED; | 908 | return ERR_ALREADY_REGISTERED; |
| 650 | } | 909 | } |
| 651 | 910 | ||
| @@ -666,9 +925,12 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { | |||
| 666 | 925 | ||
| 667 | /// Gets the priority for the specified thread | 926 | /// Gets the priority for the specified thread |
| 668 | static ResultCode GetThreadPriority(u32* priority, Handle handle) { | 927 | static ResultCode GetThreadPriority(u32* priority, Handle handle) { |
| 928 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 929 | |||
| 669 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 930 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 670 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); | 931 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); |
| 671 | if (!thread) { | 932 | if (!thread) { |
| 933 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 672 | return ERR_INVALID_HANDLE; | 934 | return ERR_INVALID_HANDLE; |
| 673 | } | 935 | } |
| 674 | 936 | ||
| @@ -678,21 +940,21 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { | |||
| 678 | 940 | ||
| 679 | /// Sets the priority for the specified thread | 941 | /// Sets the priority for the specified thread |
| 680 | static ResultCode SetThreadPriority(Handle handle, u32 priority) { | 942 | static ResultCode SetThreadPriority(Handle handle, u32 priority) { |
| 943 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 944 | |||
| 681 | if (priority > THREADPRIO_LOWEST) { | 945 | if (priority > THREADPRIO_LOWEST) { |
| 946 | LOG_ERROR( | ||
| 947 | Kernel_SVC, | ||
| 948 | "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}", | ||
| 949 | THREADPRIO_LOWEST, priority, handle); | ||
| 682 | return ERR_INVALID_THREAD_PRIORITY; | 950 | return ERR_INVALID_THREAD_PRIORITY; |
| 683 | } | 951 | } |
| 684 | 952 | ||
| 685 | const auto* const current_process = Core::CurrentProcess(); | 953 | const auto* const current_process = Core::CurrentProcess(); |
| 686 | 954 | ||
| 687 | // Note: The kernel uses the current process's resource limit instead of | ||
| 688 | // the one from the thread owner's resource limit. | ||
| 689 | const ResourceLimit& resource_limit = current_process->GetResourceLimit(); | ||
| 690 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { | ||
| 691 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 692 | } | ||
| 693 | |||
| 694 | SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 955 | SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); |
| 695 | if (!thread) { | 956 | if (!thread) { |
| 957 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 696 | return ERR_INVALID_HANDLE; | 958 | return ERR_INVALID_HANDLE; |
| 697 | } | 959 | } |
| 698 | 960 | ||
| @@ -715,36 +977,50 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 715 | shared_memory_handle, addr, size, permissions); | 977 | shared_memory_handle, addr, size, permissions); |
| 716 | 978 | ||
| 717 | if (!Common::Is4KBAligned(addr)) { | 979 | if (!Common::Is4KBAligned(addr)) { |
| 980 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 718 | return ERR_INVALID_ADDRESS; | 981 | return ERR_INVALID_ADDRESS; |
| 719 | } | 982 | } |
| 720 | 983 | ||
| 721 | if (size == 0 || !Common::Is4KBAligned(size)) { | 984 | if (size == 0) { |
| 985 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 986 | return ERR_INVALID_SIZE; | ||
| 987 | } | ||
| 988 | |||
| 989 | if (!Common::Is4KBAligned(size)) { | ||
| 990 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 722 | return ERR_INVALID_SIZE; | 991 | return ERR_INVALID_SIZE; |
| 723 | } | 992 | } |
| 724 | 993 | ||
| 725 | if (!IsValidAddressRange(addr, size)) { | 994 | if (!IsValidAddressRange(addr, size)) { |
| 995 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 996 | addr, size); | ||
| 726 | return ERR_INVALID_ADDRESS_STATE; | 997 | return ERR_INVALID_ADDRESS_STATE; |
| 727 | } | 998 | } |
| 728 | 999 | ||
| 729 | const auto permissions_type = static_cast<MemoryPermission>(permissions); | 1000 | const auto permissions_type = static_cast<MemoryPermission>(permissions); |
| 730 | if (permissions_type != MemoryPermission::Read && | 1001 | if (permissions_type != MemoryPermission::Read && |
| 731 | permissions_type != MemoryPermission::ReadWrite) { | 1002 | permissions_type != MemoryPermission::ReadWrite) { |
| 732 | LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); | 1003 | LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", |
| 1004 | permissions); | ||
| 733 | return ERR_INVALID_MEMORY_PERMISSIONS; | 1005 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 734 | } | 1006 | } |
| 735 | 1007 | ||
| 736 | auto* const current_process = Core::CurrentProcess(); | 1008 | auto* const current_process = Core::CurrentProcess(); |
| 737 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); | 1009 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); |
| 738 | if (!shared_memory) { | 1010 | if (!shared_memory) { |
| 1011 | LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", | ||
| 1012 | shared_memory_handle); | ||
| 739 | return ERR_INVALID_HANDLE; | 1013 | return ERR_INVALID_HANDLE; |
| 740 | } | 1014 | } |
| 741 | 1015 | ||
| 742 | const auto& vm_manager = current_process->VMManager(); | 1016 | const auto& vm_manager = current_process->VMManager(); |
| 743 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { | 1017 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { |
| 1018 | LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", | ||
| 1019 | addr, size); | ||
| 744 | return ERR_INVALID_MEMORY_RANGE; | 1020 | return ERR_INVALID_MEMORY_RANGE; |
| 745 | } | 1021 | } |
| 746 | 1022 | ||
| 747 | return shared_memory->Map(current_process, addr, permissions_type, MemoryPermission::DontCare); | 1023 | return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare); |
| 748 | } | 1024 | } |
| 749 | 1025 | ||
| 750 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | 1026 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { |
| @@ -752,37 +1028,53 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 | |||
| 752 | shared_memory_handle, addr, size); | 1028 | shared_memory_handle, addr, size); |
| 753 | 1029 | ||
| 754 | if (!Common::Is4KBAligned(addr)) { | 1030 | if (!Common::Is4KBAligned(addr)) { |
| 1031 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 755 | return ERR_INVALID_ADDRESS; | 1032 | return ERR_INVALID_ADDRESS; |
| 756 | } | 1033 | } |
| 757 | 1034 | ||
| 758 | if (size == 0 || !Common::Is4KBAligned(size)) { | 1035 | if (size == 0) { |
| 1036 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 1037 | return ERR_INVALID_SIZE; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | if (!Common::Is4KBAligned(size)) { | ||
| 1041 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 759 | return ERR_INVALID_SIZE; | 1042 | return ERR_INVALID_SIZE; |
| 760 | } | 1043 | } |
| 761 | 1044 | ||
| 762 | if (!IsValidAddressRange(addr, size)) { | 1045 | if (!IsValidAddressRange(addr, size)) { |
| 1046 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 1047 | addr, size); | ||
| 763 | return ERR_INVALID_ADDRESS_STATE; | 1048 | return ERR_INVALID_ADDRESS_STATE; |
| 764 | } | 1049 | } |
| 765 | 1050 | ||
| 766 | auto* const current_process = Core::CurrentProcess(); | 1051 | auto* const current_process = Core::CurrentProcess(); |
| 767 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); | 1052 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); |
| 768 | if (!shared_memory) { | 1053 | if (!shared_memory) { |
| 1054 | LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", | ||
| 1055 | shared_memory_handle); | ||
| 769 | return ERR_INVALID_HANDLE; | 1056 | return ERR_INVALID_HANDLE; |
| 770 | } | 1057 | } |
| 771 | 1058 | ||
| 772 | const auto& vm_manager = current_process->VMManager(); | 1059 | const auto& vm_manager = current_process->VMManager(); |
| 773 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { | 1060 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { |
| 1061 | LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", | ||
| 1062 | addr, size); | ||
| 774 | return ERR_INVALID_MEMORY_RANGE; | 1063 | return ERR_INVALID_MEMORY_RANGE; |
| 775 | } | 1064 | } |
| 776 | 1065 | ||
| 777 | return shared_memory->Unmap(current_process, addr); | 1066 | return shared_memory->Unmap(*current_process, addr); |
| 778 | } | 1067 | } |
| 779 | 1068 | ||
| 780 | /// Query process memory | 1069 | /// Query process memory |
| 781 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, | 1070 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, |
| 782 | Handle process_handle, u64 addr) { | 1071 | Handle process_handle, u64 addr) { |
| 1072 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); | ||
| 783 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1073 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 784 | SharedPtr<Process> process = handle_table.Get<Process>(process_handle); | 1074 | SharedPtr<Process> process = handle_table.Get<Process>(process_handle); |
| 785 | if (!process) { | 1075 | if (!process) { |
| 1076 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 1077 | process_handle); | ||
| 786 | return ERR_INVALID_HANDLE; | 1078 | return ERR_INVALID_HANDLE; |
| 787 | } | 1079 | } |
| 788 | auto vma = process->VMManager().FindVMA(addr); | 1080 | auto vma = process->VMManager().FindVMA(addr); |
| @@ -798,8 +1090,6 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 798 | memory_info->size = vma->second.size; | 1090 | memory_info->size = vma->second.size; |
| 799 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); | 1091 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); |
| 800 | } | 1092 | } |
| 801 | |||
| 802 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); | ||
| 803 | return RESULT_SUCCESS; | 1093 | return RESULT_SUCCESS; |
| 804 | } | 1094 | } |
| 805 | 1095 | ||
| @@ -828,15 +1118,18 @@ static void ExitProcess() { | |||
| 828 | /// Creates a new thread | 1118 | /// Creates a new thread |
| 829 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, | 1119 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, |
| 830 | u32 priority, s32 processor_id) { | 1120 | u32 priority, s32 processor_id) { |
| 1121 | LOG_TRACE(Kernel_SVC, | ||
| 1122 | "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " | ||
| 1123 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | ||
| 1124 | entry_point, arg, stack_top, priority, processor_id, *out_handle); | ||
| 1125 | |||
| 831 | if (priority > THREADPRIO_LOWEST) { | 1126 | if (priority > THREADPRIO_LOWEST) { |
| 1127 | LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}", | ||
| 1128 | THREADPRIO_LOWEST, priority); | ||
| 832 | return ERR_INVALID_THREAD_PRIORITY; | 1129 | return ERR_INVALID_THREAD_PRIORITY; |
| 833 | } | 1130 | } |
| 834 | 1131 | ||
| 835 | auto* const current_process = Core::CurrentProcess(); | 1132 | auto* const current_process = Core::CurrentProcess(); |
| 836 | const ResourceLimit& resource_limit = current_process->GetResourceLimit(); | ||
| 837 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { | ||
| 838 | return ERR_INVALID_THREAD_PRIORITY; | ||
| 839 | } | ||
| 840 | 1133 | ||
| 841 | if (processor_id == THREADPROCESSORID_DEFAULT) { | 1134 | if (processor_id == THREADPROCESSORID_DEFAULT) { |
| 842 | // Set the target CPU to the one specified in the process' exheader. | 1135 | // Set the target CPU to the one specified in the process' exheader. |
| @@ -863,6 +1156,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 863 | 1156 | ||
| 864 | const auto new_guest_handle = current_process->GetHandleTable().Create(thread); | 1157 | const auto new_guest_handle = current_process->GetHandleTable().Create(thread); |
| 865 | if (new_guest_handle.Failed()) { | 1158 | if (new_guest_handle.Failed()) { |
| 1159 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | ||
| 1160 | new_guest_handle.Code().raw); | ||
| 866 | return new_guest_handle.Code(); | 1161 | return new_guest_handle.Code(); |
| 867 | } | 1162 | } |
| 868 | thread->SetGuestHandle(*new_guest_handle); | 1163 | thread->SetGuestHandle(*new_guest_handle); |
| @@ -870,11 +1165,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 870 | 1165 | ||
| 871 | Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1166 | Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); |
| 872 | 1167 | ||
| 873 | LOG_TRACE(Kernel_SVC, | ||
| 874 | "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " | ||
| 875 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | ||
| 876 | entry_point, name, arg, stack_top, priority, processor_id, *out_handle); | ||
| 877 | |||
| 878 | return RESULT_SUCCESS; | 1168 | return RESULT_SUCCESS; |
| 879 | } | 1169 | } |
| 880 | 1170 | ||
| @@ -885,6 +1175,8 @@ static ResultCode StartThread(Handle thread_handle) { | |||
| 885 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1175 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 886 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1176 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 887 | if (!thread) { | 1177 | if (!thread) { |
| 1178 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1179 | thread_handle); | ||
| 888 | return ERR_INVALID_HANDLE; | 1180 | return ERR_INVALID_HANDLE; |
| 889 | } | 1181 | } |
| 890 | 1182 | ||
| @@ -1064,10 +1356,12 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout | |||
| 1064 | address, type, value, timeout); | 1356 | address, type, value, timeout); |
| 1065 | // If the passed address is a kernel virtual address, return invalid memory state. | 1357 | // If the passed address is a kernel virtual address, return invalid memory state. |
| 1066 | if (Memory::IsKernelVirtualAddress(address)) { | 1358 | if (Memory::IsKernelVirtualAddress(address)) { |
| 1359 | LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); | ||
| 1067 | return ERR_INVALID_ADDRESS_STATE; | 1360 | return ERR_INVALID_ADDRESS_STATE; |
| 1068 | } | 1361 | } |
| 1069 | // If the address is not properly aligned to 4 bytes, return invalid address. | 1362 | // If the address is not properly aligned to 4 bytes, return invalid address. |
| 1070 | if (address % sizeof(u32) != 0) { | 1363 | if (!Common::IsWordAligned(address)) { |
| 1364 | LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); | ||
| 1071 | return ERR_INVALID_ADDRESS; | 1365 | return ERR_INVALID_ADDRESS; |
| 1072 | } | 1366 | } |
| 1073 | 1367 | ||
| @@ -1079,6 +1373,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout | |||
| 1079 | case AddressArbiter::ArbitrationType::WaitIfEqual: | 1373 | case AddressArbiter::ArbitrationType::WaitIfEqual: |
| 1080 | return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); | 1374 | return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); |
| 1081 | default: | 1375 | default: |
| 1376 | LOG_ERROR(Kernel_SVC, | ||
| 1377 | "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " | ||
| 1378 | "or WaitIfEqual but got {}", | ||
| 1379 | type); | ||
| 1082 | return ERR_INVALID_ENUM_VALUE; | 1380 | return ERR_INVALID_ENUM_VALUE; |
| 1083 | } | 1381 | } |
| 1084 | } | 1382 | } |
| @@ -1089,10 +1387,12 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1089 | address, type, value, num_to_wake); | 1387 | address, type, value, num_to_wake); |
| 1090 | // If the passed address is a kernel virtual address, return invalid memory state. | 1388 | // If the passed address is a kernel virtual address, return invalid memory state. |
| 1091 | if (Memory::IsKernelVirtualAddress(address)) { | 1389 | if (Memory::IsKernelVirtualAddress(address)) { |
| 1390 | LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); | ||
| 1092 | return ERR_INVALID_ADDRESS_STATE; | 1391 | return ERR_INVALID_ADDRESS_STATE; |
| 1093 | } | 1392 | } |
| 1094 | // If the address is not properly aligned to 4 bytes, return invalid address. | 1393 | // If the address is not properly aligned to 4 bytes, return invalid address. |
| 1095 | if (address % sizeof(u32) != 0) { | 1394 | if (!Common::IsWordAligned(address)) { |
| 1395 | LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); | ||
| 1096 | return ERR_INVALID_ADDRESS; | 1396 | return ERR_INVALID_ADDRESS; |
| 1097 | } | 1397 | } |
| 1098 | 1398 | ||
| @@ -1105,12 +1405,18 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1105 | return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, | 1405 | return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, |
| 1106 | num_to_wake); | 1406 | num_to_wake); |
| 1107 | default: | 1407 | default: |
| 1408 | LOG_ERROR(Kernel_SVC, | ||
| 1409 | "Invalid signal type, expected Signal, IncrementAndSignalIfEqual " | ||
| 1410 | "or ModifyByWaitingCountAndSignalIfEqual but got {}", | ||
| 1411 | type); | ||
| 1108 | return ERR_INVALID_ENUM_VALUE; | 1412 | return ERR_INVALID_ENUM_VALUE; |
| 1109 | } | 1413 | } |
| 1110 | } | 1414 | } |
| 1111 | 1415 | ||
| 1112 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 1416 | /// This returns the total CPU ticks elapsed since the CPU was powered-on |
| 1113 | static u64 GetSystemTick() { | 1417 | static u64 GetSystemTick() { |
| 1418 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 1419 | |||
| 1114 | const u64 result{CoreTiming::GetTicks()}; | 1420 | const u64 result{CoreTiming::GetTicks()}; |
| 1115 | 1421 | ||
| 1116 | // Advance time to defeat dumb games that busy-wait for the frame to end. | 1422 | // Advance time to defeat dumb games that busy-wait for the frame to end. |
| @@ -1129,10 +1435,10 @@ static ResultCode CloseHandle(Handle handle) { | |||
| 1129 | 1435 | ||
| 1130 | /// Reset an event | 1436 | /// Reset an event |
| 1131 | static ResultCode ResetSignal(Handle handle) { | 1437 | static ResultCode ResetSignal(Handle handle) { |
| 1132 | LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); | 1438 | LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); |
| 1133 | 1439 | ||
| 1134 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1440 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1135 | auto event = handle_table.Get<Event>(handle); | 1441 | auto event = handle_table.Get<ReadableEvent>(handle); |
| 1136 | 1442 | ||
| 1137 | ASSERT(event != nullptr); | 1443 | ASSERT(event != nullptr); |
| 1138 | 1444 | ||
| @@ -1142,9 +1448,39 @@ static ResultCode ResetSignal(Handle handle) { | |||
| 1142 | 1448 | ||
| 1143 | /// Creates a TransferMemory object | 1449 | /// Creates a TransferMemory object |
| 1144 | static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { | 1450 | static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { |
| 1145 | LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, | 1451 | LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, |
| 1146 | permissions); | 1452 | permissions); |
| 1147 | *handle = 0; | 1453 | |
| 1454 | if (!Common::Is4KBAligned(addr)) { | ||
| 1455 | LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr); | ||
| 1456 | return ERR_INVALID_ADDRESS; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | if (!Common::Is4KBAligned(size) || size == 0) { | ||
| 1460 | LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); | ||
| 1461 | return ERR_INVALID_ADDRESS; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | if (!IsValidAddressRange(addr, size)) { | ||
| 1465 | LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", | ||
| 1466 | addr, size); | ||
| 1467 | return ERR_INVALID_ADDRESS_STATE; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | const auto perms = static_cast<MemoryPermission>(permissions); | ||
| 1471 | if (perms != MemoryPermission::None && perms != MemoryPermission::Read && | ||
| 1472 | perms != MemoryPermission::ReadWrite) { | ||
| 1473 | LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", | ||
| 1474 | permissions); | ||
| 1475 | return ERR_INVALID_MEMORY_PERMISSIONS; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1479 | auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | ||
| 1480 | const auto shared_mem_handle = SharedMemory::Create( | ||
| 1481 | kernel, handle_table.Get<Process>(CurrentProcess), size, perms, perms, addr); | ||
| 1482 | |||
| 1483 | CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); | ||
| 1148 | return RESULT_SUCCESS; | 1484 | return RESULT_SUCCESS; |
| 1149 | } | 1485 | } |
| 1150 | 1486 | ||
| @@ -1154,6 +1490,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) | |||
| 1154 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1490 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1155 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1491 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 1156 | if (!thread) { | 1492 | if (!thread) { |
| 1493 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1494 | thread_handle); | ||
| 1157 | return ERR_INVALID_HANDLE; | 1495 | return ERR_INVALID_HANDLE; |
| 1158 | } | 1496 | } |
| 1159 | 1497 | ||
| @@ -1164,12 +1502,14 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) | |||
| 1164 | } | 1502 | } |
| 1165 | 1503 | ||
| 1166 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | 1504 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { |
| 1167 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, | 1505 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle, |
| 1168 | mask, core); | 1506 | mask, core); |
| 1169 | 1507 | ||
| 1170 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1508 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1171 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1509 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 1172 | if (!thread) { | 1510 | if (!thread) { |
| 1511 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1512 | thread_handle); | ||
| 1173 | return ERR_INVALID_HANDLE; | 1513 | return ERR_INVALID_HANDLE; |
| 1174 | } | 1514 | } |
| 1175 | 1515 | ||
| @@ -1184,7 +1524,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 1184 | } | 1524 | } |
| 1185 | 1525 | ||
| 1186 | if (mask == 0) { | 1526 | if (mask == 0) { |
| 1187 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); | 1527 | LOG_ERROR(Kernel_SVC, "Mask is 0"); |
| 1528 | return ERR_INVALID_COMBINATION; | ||
| 1188 | } | 1529 | } |
| 1189 | 1530 | ||
| 1190 | /// This value is used to only change the affinity mask without changing the current ideal core. | 1531 | /// This value is used to only change the affinity mask without changing the current ideal core. |
| @@ -1193,12 +1534,15 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 1193 | if (core == OnlyChangeMask) { | 1534 | if (core == OnlyChangeMask) { |
| 1194 | core = thread->GetIdealCore(); | 1535 | core = thread->GetIdealCore(); |
| 1195 | } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { | 1536 | } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { |
| 1196 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | 1537 | LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core); |
| 1538 | return ERR_INVALID_PROCESSOR_ID; | ||
| 1197 | } | 1539 | } |
| 1198 | 1540 | ||
| 1199 | // Error out if the input core isn't enabled in the input mask. | 1541 | // Error out if the input core isn't enabled in the input mask. |
| 1200 | if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { | 1542 | if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { |
| 1201 | return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); | 1543 | LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", |
| 1544 | core, mask); | ||
| 1545 | return ERR_INVALID_COMBINATION; | ||
| 1202 | } | 1546 | } |
| 1203 | 1547 | ||
| 1204 | thread->ChangeCore(core, mask); | 1548 | thread->ChangeCore(core, mask); |
| @@ -1210,21 +1554,36 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 1210 | u32 remote_permissions) { | 1554 | u32 remote_permissions) { |
| 1211 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | 1555 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, |
| 1212 | local_permissions, remote_permissions); | 1556 | local_permissions, remote_permissions); |
| 1557 | if (size == 0) { | ||
| 1558 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 1559 | return ERR_INVALID_SIZE; | ||
| 1560 | } | ||
| 1561 | if (!Common::Is4KBAligned(size)) { | ||
| 1562 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); | ||
| 1563 | return ERR_INVALID_SIZE; | ||
| 1564 | } | ||
| 1213 | 1565 | ||
| 1214 | // Size must be a multiple of 4KB and be less than or equal to | 1566 | if (size >= MAIN_MEMORY_SIZE) { |
| 1215 | // approx. 8 GB (actually (1GB - 512B) * 8) | 1567 | LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size); |
| 1216 | if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { | ||
| 1217 | return ERR_INVALID_SIZE; | 1568 | return ERR_INVALID_SIZE; |
| 1218 | } | 1569 | } |
| 1219 | 1570 | ||
| 1220 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); | 1571 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); |
| 1221 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { | 1572 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { |
| 1573 | LOG_ERROR(Kernel_SVC, | ||
| 1574 | "Invalid local memory permissions, expected Read or ReadWrite but got " | ||
| 1575 | "local_permissions={}", | ||
| 1576 | static_cast<u32>(local_permissions)); | ||
| 1222 | return ERR_INVALID_MEMORY_PERMISSIONS; | 1577 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 1223 | } | 1578 | } |
| 1224 | 1579 | ||
| 1225 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); | 1580 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); |
| 1226 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && | 1581 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && |
| 1227 | remote_perms != MemoryPermission::DontCare) { | 1582 | remote_perms != MemoryPermission::DontCare) { |
| 1583 | LOG_ERROR(Kernel_SVC, | ||
| 1584 | "Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got " | ||
| 1585 | "remote_permissions={}", | ||
| 1586 | static_cast<u32>(remote_permissions)); | ||
| 1228 | return ERR_INVALID_MEMORY_PERMISSIONS; | 1587 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 1229 | } | 1588 | } |
| 1230 | 1589 | ||
| @@ -1238,16 +1597,67 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 1238 | return RESULT_SUCCESS; | 1597 | return RESULT_SUCCESS; |
| 1239 | } | 1598 | } |
| 1240 | 1599 | ||
| 1600 | static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) { | ||
| 1601 | LOG_DEBUG(Kernel_SVC, "called"); | ||
| 1602 | |||
| 1603 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1604 | const auto [readable_event, writable_event] = | ||
| 1605 | WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent"); | ||
| 1606 | |||
| 1607 | HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 1608 | |||
| 1609 | const auto write_create_result = handle_table.Create(writable_event); | ||
| 1610 | if (write_create_result.Failed()) { | ||
| 1611 | return write_create_result.Code(); | ||
| 1612 | } | ||
| 1613 | *write_handle = *write_create_result; | ||
| 1614 | |||
| 1615 | const auto read_create_result = handle_table.Create(readable_event); | ||
| 1616 | if (read_create_result.Failed()) { | ||
| 1617 | handle_table.Close(*write_create_result); | ||
| 1618 | return read_create_result.Code(); | ||
| 1619 | } | ||
| 1620 | *read_handle = *read_create_result; | ||
| 1621 | |||
| 1622 | LOG_DEBUG(Kernel_SVC, | ||
| 1623 | "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}", | ||
| 1624 | *write_create_result, *read_create_result); | ||
| 1625 | return RESULT_SUCCESS; | ||
| 1626 | } | ||
| 1627 | |||
| 1241 | static ResultCode ClearEvent(Handle handle) { | 1628 | static ResultCode ClearEvent(Handle handle) { |
| 1242 | LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); | 1629 | LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); |
| 1243 | 1630 | ||
| 1244 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1631 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1245 | SharedPtr<Event> evt = handle_table.Get<Event>(handle); | 1632 | |
| 1246 | if (evt == nullptr) { | 1633 | auto writable_event = handle_table.Get<WritableEvent>(handle); |
| 1634 | if (writable_event) { | ||
| 1635 | writable_event->Clear(); | ||
| 1636 | return RESULT_SUCCESS; | ||
| 1637 | } | ||
| 1638 | |||
| 1639 | auto readable_event = handle_table.Get<ReadableEvent>(handle); | ||
| 1640 | if (readable_event) { | ||
| 1641 | readable_event->Clear(); | ||
| 1642 | return RESULT_SUCCESS; | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); | ||
| 1646 | return ERR_INVALID_HANDLE; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | static ResultCode SignalEvent(Handle handle) { | ||
| 1650 | LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); | ||
| 1651 | |||
| 1652 | HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable(); | ||
| 1653 | auto writable_event = handle_table.Get<WritableEvent>(handle); | ||
| 1654 | |||
| 1655 | if (!writable_event) { | ||
| 1656 | LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle); | ||
| 1247 | return ERR_INVALID_HANDLE; | 1657 | return ERR_INVALID_HANDLE; |
| 1248 | } | 1658 | } |
| 1249 | 1659 | ||
| 1250 | evt->Clear(); | 1660 | writable_event->Signal(); |
| 1251 | return RESULT_SUCCESS; | 1661 | return RESULT_SUCCESS; |
| 1252 | } | 1662 | } |
| 1253 | 1663 | ||
| @@ -1262,11 +1672,14 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { | |||
| 1262 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1672 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1263 | const auto process = handle_table.Get<Process>(process_handle); | 1673 | const auto process = handle_table.Get<Process>(process_handle); |
| 1264 | if (!process) { | 1674 | if (!process) { |
| 1675 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 1676 | process_handle); | ||
| 1265 | return ERR_INVALID_HANDLE; | 1677 | return ERR_INVALID_HANDLE; |
| 1266 | } | 1678 | } |
| 1267 | 1679 | ||
| 1268 | const auto info_type = static_cast<InfoType>(type); | 1680 | const auto info_type = static_cast<InfoType>(type); |
| 1269 | if (info_type != InfoType::Status) { | 1681 | if (info_type != InfoType::Status) { |
| 1682 | LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type); | ||
| 1270 | return ERR_INVALID_ENUM_VALUE; | 1683 | return ERR_INVALID_ENUM_VALUE; |
| 1271 | } | 1684 | } |
| 1272 | 1685 | ||
| @@ -1274,6 +1687,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { | |||
| 1274 | return RESULT_SUCCESS; | 1687 | return RESULT_SUCCESS; |
| 1275 | } | 1688 | } |
| 1276 | 1689 | ||
| 1690 | static ResultCode CreateResourceLimit(Handle* out_handle) { | ||
| 1691 | LOG_DEBUG(Kernel_SVC, "called"); | ||
| 1692 | |||
| 1693 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1694 | auto resource_limit = ResourceLimit::Create(kernel); | ||
| 1695 | |||
| 1696 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1697 | ASSERT(current_process != nullptr); | ||
| 1698 | |||
| 1699 | const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); | ||
| 1700 | if (handle.Failed()) { | ||
| 1701 | return handle.Code(); | ||
| 1702 | } | ||
| 1703 | |||
| 1704 | *out_handle = *handle; | ||
| 1705 | return RESULT_SUCCESS; | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit, | ||
| 1709 | u32 resource_type) { | ||
| 1710 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1711 | |||
| 1712 | const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1713 | ResourceLimitValueType::LimitValue); | ||
| 1714 | if (limit_value.Failed()) { | ||
| 1715 | return limit_value.Code(); | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | *out_value = static_cast<u64>(*limit_value); | ||
| 1719 | return RESULT_SUCCESS; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit, | ||
| 1723 | u32 resource_type) { | ||
| 1724 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1725 | |||
| 1726 | const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1727 | ResourceLimitValueType::CurrentValue); | ||
| 1728 | if (current_value.Failed()) { | ||
| 1729 | return current_value.Code(); | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | *out_value = static_cast<u64>(*current_value); | ||
| 1733 | return RESULT_SUCCESS; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) { | ||
| 1737 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | ||
| 1738 | resource_type, value); | ||
| 1739 | |||
| 1740 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 1741 | if (!IsValidResourceType(type)) { | ||
| 1742 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 1743 | return ERR_INVALID_ENUM_VALUE; | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1747 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1748 | ASSERT(current_process != nullptr); | ||
| 1749 | |||
| 1750 | auto resource_limit_object = | ||
| 1751 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 1752 | if (!resource_limit_object) { | ||
| 1753 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 1754 | resource_limit); | ||
| 1755 | return ERR_INVALID_HANDLE; | ||
| 1756 | } | ||
| 1757 | |||
| 1758 | const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); | ||
| 1759 | if (set_result.IsError()) { | ||
| 1760 | LOG_ERROR( | ||
| 1761 | Kernel_SVC, | ||
| 1762 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", | ||
| 1763 | resource_limit_object->GetMaxResourceValue(type), resource_type, | ||
| 1764 | resource_limit_object->GetCurrentResourceValue(type)); | ||
| 1765 | return set_result; | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | return RESULT_SUCCESS; | ||
| 1769 | } | ||
| 1770 | |||
| 1277 | namespace { | 1771 | namespace { |
| 1278 | struct FunctionDef { | 1772 | struct FunctionDef { |
| 1279 | using Func = void(); | 1773 | using Func = void(); |
| @@ -1287,7 +1781,7 @@ struct FunctionDef { | |||
| 1287 | static const FunctionDef SVC_Table[] = { | 1781 | static const FunctionDef SVC_Table[] = { |
| 1288 | {0x00, nullptr, "Unknown"}, | 1782 | {0x00, nullptr, "Unknown"}, |
| 1289 | {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"}, | 1783 | {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"}, |
| 1290 | {0x02, nullptr, "SetMemoryPermission"}, | 1784 | {0x02, SvcWrap<SetMemoryPermission>, "SetMemoryPermission"}, |
| 1291 | {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"}, | 1785 | {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"}, |
| 1292 | {0x04, SvcWrap<MapMemory>, "MapMemory"}, | 1786 | {0x04, SvcWrap<MapMemory>, "MapMemory"}, |
| 1293 | {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"}, | 1787 | {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"}, |
| @@ -1302,7 +1796,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 1302 | {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, | 1796 | {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, |
| 1303 | {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, | 1797 | {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, |
| 1304 | {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, | 1798 | {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, |
| 1305 | {0x11, nullptr, "SignalEvent"}, | 1799 | {0x11, SvcWrap<SignalEvent>, "SignalEvent"}, |
| 1306 | {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, | 1800 | {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, |
| 1307 | {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, | 1801 | {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, |
| 1308 | {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, | 1802 | {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, |
| @@ -1333,8 +1827,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1333 | {0x2D, nullptr, "UnmapPhysicalMemory"}, | 1827 | {0x2D, nullptr, "UnmapPhysicalMemory"}, |
| 1334 | {0x2E, nullptr, "GetFutureThreadInfo"}, | 1828 | {0x2E, nullptr, "GetFutureThreadInfo"}, |
| 1335 | {0x2F, nullptr, "GetLastThreadInfo"}, | 1829 | {0x2F, nullptr, "GetLastThreadInfo"}, |
| 1336 | {0x30, nullptr, "GetResourceLimitLimitValue"}, | 1830 | {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"}, |
| 1337 | {0x31, nullptr, "GetResourceLimitCurrentValue"}, | 1831 | {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"}, |
| 1338 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, | 1832 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, |
| 1339 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, | 1833 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, |
| 1340 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, | 1834 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, |
| @@ -1354,7 +1848,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 1354 | {0x42, nullptr, "ReplyAndReceiveLight"}, | 1848 | {0x42, nullptr, "ReplyAndReceiveLight"}, |
| 1355 | {0x43, nullptr, "ReplyAndReceive"}, | 1849 | {0x43, nullptr, "ReplyAndReceive"}, |
| 1356 | {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, | 1850 | {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, |
| 1357 | {0x45, nullptr, "CreateEvent"}, | 1851 | {0x45, SvcWrap<CreateEvent>, "CreateEvent"}, |
| 1358 | {0x46, nullptr, "Unknown"}, | 1852 | {0x46, nullptr, "Unknown"}, |
| 1359 | {0x47, nullptr, "Unknown"}, | 1853 | {0x47, nullptr, "Unknown"}, |
| 1360 | {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, | 1854 | {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, |
| @@ -1410,8 +1904,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1410 | {0x7A, nullptr, "StartProcess"}, | 1904 | {0x7A, nullptr, "StartProcess"}, |
| 1411 | {0x7B, nullptr, "TerminateProcess"}, | 1905 | {0x7B, nullptr, "TerminateProcess"}, |
| 1412 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, | 1906 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, |
| 1413 | {0x7D, nullptr, "CreateResourceLimit"}, | 1907 | {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"}, |
| 1414 | {0x7E, nullptr, "SetResourceLimitLimitValue"}, | 1908 | {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, |
| 1415 | {0x7F, nullptr, "CallSecureMonitor"}, | 1909 | {0x7F, nullptr, "CallSecureMonitor"}, |
| 1416 | }; | 1910 | }; |
| 1417 | 1911 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index b09753c80..24aef46c9 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -43,6 +43,14 @@ void SvcWrap() { | |||
| 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); | 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | template <ResultCode func(u32*)> | ||
| 47 | void SvcWrap() { | ||
| 48 | u32 param = 0; | ||
| 49 | const u32 retval = func(¶m).raw; | ||
| 50 | Core::CurrentArmInterface().SetReg(1, param); | ||
| 51 | FuncReturn(retval); | ||
| 52 | } | ||
| 53 | |||
| 46 | template <ResultCode func(u32*, u32)> | 54 | template <ResultCode func(u32*, u32)> |
| 47 | void SvcWrap() { | 55 | void SvcWrap() { |
| 48 | u32 param_1 = 0; | 56 | u32 param_1 = 0; |
| @@ -51,6 +59,19 @@ void SvcWrap() { | |||
| 51 | FuncReturn(retval); | 59 | FuncReturn(retval); |
| 52 | } | 60 | } |
| 53 | 61 | ||
| 62 | template <ResultCode func(u32*, u32*)> | ||
| 63 | void SvcWrap() { | ||
| 64 | u32 param_1 = 0; | ||
| 65 | u32 param_2 = 0; | ||
| 66 | const u32 retval = func(¶m_1, ¶m_2).raw; | ||
| 67 | |||
| 68 | auto& arm_interface = Core::CurrentArmInterface(); | ||
| 69 | arm_interface.SetReg(1, param_1); | ||
| 70 | arm_interface.SetReg(2, param_2); | ||
| 71 | |||
| 72 | FuncReturn(retval); | ||
| 73 | } | ||
| 74 | |||
| 54 | template <ResultCode func(u32*, u64)> | 75 | template <ResultCode func(u32*, u64)> |
| 55 | void SvcWrap() { | 76 | void SvcWrap() { |
| 56 | u32 param_1 = 0; | 77 | u32 param_1 = 0; |
| @@ -121,6 +142,11 @@ void SvcWrap() { | |||
| 121 | FuncReturn(func(Param(0), Param(1), Param(2)).raw); | 142 | FuncReturn(func(Param(0), Param(1), Param(2)).raw); |
| 122 | } | 143 | } |
| 123 | 144 | ||
| 145 | template <ResultCode func(u64, u64, u32)> | ||
| 146 | void SvcWrap() { | ||
| 147 | FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw); | ||
| 148 | } | ||
| 149 | |||
| 124 | template <ResultCode func(u32, u64, u64, u32)> | 150 | template <ResultCode func(u32, u64, u64, u32)> |
| 125 | void SvcWrap() { | 151 | void SvcWrap() { |
| 126 | FuncReturn( | 152 | FuncReturn( |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index dd5cd9ced..4ffb76818 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -142,36 +142,7 @@ void Thread::ResumeFromWait() { | |||
| 142 | 142 | ||
| 143 | status = ThreadStatus::Ready; | 143 | status = ThreadStatus::Ready; |
| 144 | 144 | ||
| 145 | std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); | 145 | ChangeScheduler(); |
| 146 | if (!new_processor_id) { | ||
| 147 | new_processor_id = processor_id; | ||
| 148 | } | ||
| 149 | if (ideal_core != -1 && | ||
| 150 | Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) { | ||
| 151 | new_processor_id = ideal_core; | ||
| 152 | } | ||
| 153 | |||
| 154 | ASSERT(*new_processor_id < 4); | ||
| 155 | |||
| 156 | // Add thread to new core's scheduler | ||
| 157 | auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); | ||
| 158 | |||
| 159 | if (*new_processor_id != processor_id) { | ||
| 160 | // Remove thread from previous core's scheduler | ||
| 161 | scheduler->RemoveThread(this); | ||
| 162 | next_scheduler->AddThread(this, current_priority); | ||
| 163 | } | ||
| 164 | |||
| 165 | processor_id = *new_processor_id; | ||
| 166 | |||
| 167 | // If the thread was ready, unschedule from the previous core and schedule on the new core | ||
| 168 | scheduler->UnscheduleThread(this, current_priority); | ||
| 169 | next_scheduler->ScheduleThread(this, current_priority); | ||
| 170 | |||
| 171 | // Change thread's scheduler | ||
| 172 | scheduler = next_scheduler; | ||
| 173 | |||
| 174 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | ||
| 175 | } | 146 | } |
| 176 | 147 | ||
| 177 | /** | 148 | /** |
| @@ -364,42 +335,45 @@ void Thread::UpdatePriority() { | |||
| 364 | void Thread::ChangeCore(u32 core, u64 mask) { | 335 | void Thread::ChangeCore(u32 core, u64 mask) { |
| 365 | ideal_core = core; | 336 | ideal_core = core; |
| 366 | affinity_mask = mask; | 337 | affinity_mask = mask; |
| 338 | ChangeScheduler(); | ||
| 339 | } | ||
| 367 | 340 | ||
| 341 | void Thread::ChangeScheduler() { | ||
| 368 | if (status != ThreadStatus::Ready) { | 342 | if (status != ThreadStatus::Ready) { |
| 369 | return; | 343 | return; |
| 370 | } | 344 | } |
| 371 | 345 | ||
| 346 | auto& system = Core::System::GetInstance(); | ||
| 372 | std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; | 347 | std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; |
| 373 | 348 | ||
| 374 | if (!new_processor_id) { | 349 | if (!new_processor_id) { |
| 375 | new_processor_id = processor_id; | 350 | new_processor_id = processor_id; |
| 376 | } | 351 | } |
| 377 | if (ideal_core != -1 && | 352 | if (ideal_core != -1 && system.Scheduler(ideal_core).GetCurrentThread() == nullptr) { |
| 378 | Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) { | ||
| 379 | new_processor_id = ideal_core; | 353 | new_processor_id = ideal_core; |
| 380 | } | 354 | } |
| 381 | 355 | ||
| 382 | ASSERT(*new_processor_id < 4); | 356 | ASSERT(*new_processor_id < 4); |
| 383 | 357 | ||
| 384 | // Add thread to new core's scheduler | 358 | // Add thread to new core's scheduler |
| 385 | auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); | 359 | auto& next_scheduler = system.Scheduler(*new_processor_id); |
| 386 | 360 | ||
| 387 | if (*new_processor_id != processor_id) { | 361 | if (*new_processor_id != processor_id) { |
| 388 | // Remove thread from previous core's scheduler | 362 | // Remove thread from previous core's scheduler |
| 389 | scheduler->RemoveThread(this); | 363 | scheduler->RemoveThread(this); |
| 390 | next_scheduler->AddThread(this, current_priority); | 364 | next_scheduler.AddThread(this, current_priority); |
| 391 | } | 365 | } |
| 392 | 366 | ||
| 393 | processor_id = *new_processor_id; | 367 | processor_id = *new_processor_id; |
| 394 | 368 | ||
| 395 | // If the thread was ready, unschedule from the previous core and schedule on the new core | 369 | // If the thread was ready, unschedule from the previous core and schedule on the new core |
| 396 | scheduler->UnscheduleThread(this, current_priority); | 370 | scheduler->UnscheduleThread(this, current_priority); |
| 397 | next_scheduler->ScheduleThread(this, current_priority); | 371 | next_scheduler.ScheduleThread(this, current_priority); |
| 398 | 372 | ||
| 399 | // Change thread's scheduler | 373 | // Change thread's scheduler |
| 400 | scheduler = next_scheduler; | 374 | scheduler = &next_scheduler; |
| 401 | 375 | ||
| 402 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | 376 | system.CpuCore(processor_id).PrepareReschedule(); |
| 403 | } | 377 | } |
| 404 | 378 | ||
| 405 | bool Thread::AllWaitObjectsReady() { | 379 | bool Thread::AllWaitObjectsReady() { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4a6e11239..d384d50db 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -374,6 +374,8 @@ private: | |||
| 374 | explicit Thread(KernelCore& kernel); | 374 | explicit Thread(KernelCore& kernel); |
| 375 | ~Thread() override; | 375 | ~Thread() override; |
| 376 | 376 | ||
| 377 | void ChangeScheduler(); | ||
| 378 | |||
| 377 | Core::ARM_Interface::ThreadContext context{}; | 379 | Core::ARM_Interface::ThreadContext context{}; |
| 378 | 380 | ||
| 379 | u32 thread_id = 0; | 381 | u32 thread_id = 0; |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 1a92c8f70..100f8f6bf 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p | |||
| 243 | return RESULT_SUCCESS; | 243 | return RESULT_SUCCESS; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { | ||
| 247 | if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || | ||
| 248 | target + size < target) { | ||
| 249 | return ERR_INVALID_ADDRESS; | ||
| 250 | } | ||
| 251 | |||
| 252 | if (heap_memory == nullptr) { | ||
| 253 | // Initialize heap | ||
| 254 | heap_memory = std::make_shared<std::vector<u8>>(); | ||
| 255 | heap_start = heap_end = target; | ||
| 256 | } else { | ||
| 257 | UnmapRange(heap_start, heap_end - heap_start); | ||
| 258 | } | ||
| 259 | |||
| 260 | // If necessary, expand backing vector to cover new heap extents. | ||
| 261 | if (target < heap_start) { | ||
| 262 | heap_memory->insert(begin(*heap_memory), heap_start - target, 0); | ||
| 263 | heap_start = target; | ||
| 264 | RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 265 | } | ||
| 266 | if (target + size > heap_end) { | ||
| 267 | heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); | ||
| 268 | heap_end = target + size; | ||
| 269 | RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 270 | } | ||
| 271 | ASSERT(heap_end - heap_start == heap_memory->size()); | ||
| 272 | |||
| 273 | CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size, | ||
| 274 | MemoryState::Heap)); | ||
| 275 | Reprotect(vma, perms); | ||
| 276 | |||
| 277 | heap_used = size; | ||
| 278 | |||
| 279 | return MakeResult<VAddr>(heap_end - size); | ||
| 280 | } | ||
| 281 | |||
| 282 | ResultCode VMManager::HeapFree(VAddr target, u64 size) { | ||
| 283 | if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || | ||
| 284 | target + size < target) { | ||
| 285 | return ERR_INVALID_ADDRESS; | ||
| 286 | } | ||
| 287 | |||
| 288 | if (size == 0) { | ||
| 289 | return RESULT_SUCCESS; | ||
| 290 | } | ||
| 291 | |||
| 292 | const ResultCode result = UnmapRange(target, size); | ||
| 293 | if (result.IsError()) { | ||
| 294 | return result; | ||
| 295 | } | ||
| 296 | |||
| 297 | heap_used -= size; | ||
| 298 | return RESULT_SUCCESS; | ||
| 299 | } | ||
| 300 | |||
| 301 | ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) { | ||
| 302 | const auto vma = FindVMA(src_addr); | ||
| 303 | |||
| 304 | ASSERT_MSG(vma != vma_map.end(), "Invalid memory address"); | ||
| 305 | ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); | ||
| 306 | |||
| 307 | // The returned VMA might be a bigger one encompassing the desired address. | ||
| 308 | const auto vma_offset = src_addr - vma->first; | ||
| 309 | ASSERT_MSG(vma_offset + size <= vma->second.size, | ||
| 310 | "Shared memory exceeds bounds of mapped block"); | ||
| 311 | |||
| 312 | const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block; | ||
| 313 | const std::size_t backing_block_offset = vma->second.offset + vma_offset; | ||
| 314 | |||
| 315 | CASCADE_RESULT(auto new_vma, | ||
| 316 | MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, state)); | ||
| 317 | // Protect mirror with permissions from old region | ||
| 318 | Reprotect(new_vma, vma->second.permissions); | ||
| 319 | // Remove permissions from old region | ||
| 320 | Reprotect(vma, VMAPermission::None); | ||
| 321 | |||
| 322 | return RESULT_SUCCESS; | ||
| 323 | } | ||
| 324 | |||
| 246 | void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { | 325 | void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { |
| 247 | // If this ever proves to have a noticeable performance impact, allow users of the function to | 326 | // If this ever proves to have a noticeable performance impact, allow users of the function to |
| 248 | // specify a specific range of addresses to limit the scan to. | 327 | // specify a specific range of addresses to limit the scan to. |
| @@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const { | |||
| 495 | } | 574 | } |
| 496 | 575 | ||
| 497 | u64 VMManager::GetTotalHeapUsage() const { | 576 | u64 VMManager::GetTotalHeapUsage() const { |
| 498 | LOG_WARNING(Kernel, "(STUBBED) called"); | 577 | return heap_used; |
| 499 | return 0x0; | ||
| 500 | } | 578 | } |
| 501 | 579 | ||
| 502 | VAddr VMManager::GetAddressSpaceBaseAddress() const { | 580 | VAddr VMManager::GetAddressSpaceBaseAddress() const { |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 2447cbb8f..d522404fe 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -186,6 +186,12 @@ public: | |||
| 186 | /// Changes the permissions of a range of addresses, splitting VMAs as necessary. | 186 | /// Changes the permissions of a range of addresses, splitting VMAs as necessary. |
| 187 | ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); | 187 | ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); |
| 188 | 188 | ||
| 189 | ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); | ||
| 190 | ResultCode HeapFree(VAddr target, u64 size); | ||
| 191 | |||
| 192 | ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, | ||
| 193 | MemoryState state = MemoryState::Mapped); | ||
| 194 | |||
| 189 | /** | 195 | /** |
| 190 | * Scans all VMAs and updates the page table range of any that use the given vector as backing | 196 | * Scans all VMAs and updates the page table range of any that use the given vector as backing |
| 191 | * memory. This should be called after any operation that causes reallocation of the vector. | 197 | * memory. This should be called after any operation that causes reallocation of the vector. |
| @@ -343,5 +349,15 @@ private: | |||
| 343 | 349 | ||
| 344 | VAddr tls_io_region_base = 0; | 350 | VAddr tls_io_region_base = 0; |
| 345 | VAddr tls_io_region_end = 0; | 351 | VAddr tls_io_region_end = 0; |
| 352 | |||
| 353 | // Memory used to back the allocations in the regular heap. A single vector is used to cover | ||
| 354 | // the entire virtual address space extents that bound the allocations, including any holes. | ||
| 355 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous | ||
| 356 | // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. | ||
| 357 | std::shared_ptr<std::vector<u8>> heap_memory; | ||
| 358 | // The left/right bounds of the address space covered by heap_memory. | ||
| 359 | VAddr heap_start = 0; | ||
| 360 | VAddr heap_end = 0; | ||
| 361 | u64 heap_used = 0; | ||
| 346 | }; | 362 | }; |
| 347 | } // namespace Kernel | 363 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp new file mode 100644 index 000000000..a58ea6ec8 --- /dev/null +++ b/src/core/hle/kernel/writable_event.cpp | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/kernel/object.h" | ||
| 9 | #include "core/hle/kernel/readable_event.h" | ||
| 10 | #include "core/hle/kernel/thread.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} | ||
| 16 | WritableEvent::~WritableEvent() = default; | ||
| 17 | |||
| 18 | EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type, | ||
| 19 | std::string name) { | ||
| 20 | SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel)); | ||
| 21 | SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel)); | ||
| 22 | |||
| 23 | writable_event->name = name + ":Writable"; | ||
| 24 | writable_event->readable = readable_event; | ||
| 25 | readable_event->name = name + ":Readable"; | ||
| 26 | readable_event->signaled = false; | ||
| 27 | readable_event->reset_type = reset_type; | ||
| 28 | |||
| 29 | return {std::move(readable_event), std::move(writable_event)}; | ||
| 30 | } | ||
| 31 | |||
| 32 | SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const { | ||
| 33 | return readable; | ||
| 34 | } | ||
| 35 | |||
| 36 | ResetType WritableEvent::GetResetType() const { | ||
| 37 | return readable->reset_type; | ||
| 38 | } | ||
| 39 | |||
| 40 | void WritableEvent::Signal() { | ||
| 41 | readable->Signal(); | ||
| 42 | } | ||
| 43 | |||
| 44 | void WritableEvent::Clear() { | ||
| 45 | readable->Clear(); | ||
| 46 | } | ||
| 47 | |||
| 48 | bool WritableEvent::IsSignaled() const { | ||
| 49 | return readable->signaled; | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/writable_event.h index 27d6126b0..8fa8d68ee 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/writable_event.h | |||
| @@ -11,49 +11,52 @@ | |||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | class KernelCore; | 13 | class KernelCore; |
| 14 | class ReadableEvent; | ||
| 15 | class WritableEvent; | ||
| 14 | 16 | ||
| 15 | class Event final : public WaitObject { | 17 | struct EventPair { |
| 18 | SharedPtr<ReadableEvent> readable; | ||
| 19 | SharedPtr<WritableEvent> writable; | ||
| 20 | }; | ||
| 21 | |||
| 22 | class WritableEvent final : public Object { | ||
| 16 | public: | 23 | public: |
| 24 | ~WritableEvent() override; | ||
| 25 | |||
| 17 | /** | 26 | /** |
| 18 | * Creates an event | 27 | * Creates an event |
| 19 | * @param kernel The kernel instance to create this event under. | 28 | * @param kernel The kernel instance to create this event under. |
| 20 | * @param reset_type ResetType describing how to create event | 29 | * @param reset_type ResetType describing how to create event |
| 21 | * @param name Optional name of event | 30 | * @param name Optional name of event |
| 22 | */ | 31 | */ |
| 23 | static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type, | 32 | static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type, |
| 24 | std::string name = "Unknown"); | 33 | std::string name = "Unknown"); |
| 25 | 34 | ||
| 26 | std::string GetTypeName() const override { | 35 | std::string GetTypeName() const override { |
| 27 | return "Event"; | 36 | return "WritableEvent"; |
| 28 | } | 37 | } |
| 29 | std::string GetName() const override { | 38 | std::string GetName() const override { |
| 30 | return name; | 39 | return name; |
| 31 | } | 40 | } |
| 32 | 41 | ||
| 33 | static const HandleType HANDLE_TYPE = HandleType::Event; | 42 | static const HandleType HANDLE_TYPE = HandleType::WritableEvent; |
| 34 | HandleType GetHandleType() const override { | 43 | HandleType GetHandleType() const override { |
| 35 | return HANDLE_TYPE; | 44 | return HANDLE_TYPE; |
| 36 | } | 45 | } |
| 37 | 46 | ||
| 38 | ResetType GetResetType() const { | 47 | SharedPtr<ReadableEvent> GetReadableEvent() const; |
| 39 | return reset_type; | ||
| 40 | } | ||
| 41 | |||
| 42 | bool ShouldWait(Thread* thread) const override; | ||
| 43 | void Acquire(Thread* thread) override; | ||
| 44 | 48 | ||
| 45 | void WakeupAllWaitingThreads() override; | 49 | ResetType GetResetType() const; |
| 46 | 50 | ||
| 47 | void Signal(); | 51 | void Signal(); |
| 48 | void Clear(); | 52 | void Clear(); |
| 53 | bool IsSignaled() const; | ||
| 49 | 54 | ||
| 50 | private: | 55 | private: |
| 51 | explicit Event(KernelCore& kernel); | 56 | explicit WritableEvent(KernelCore& kernel); |
| 52 | ~Event() override; | ||
| 53 | 57 | ||
| 54 | ResetType reset_type; ///< Current ResetType | 58 | SharedPtr<ReadableEvent> readable; |
| 55 | 59 | ||
| 56 | bool signaled; ///< Whether the event has already been signaled | ||
| 57 | std::string name; ///< Name of event (optional) | 60 | std::string name; ///< Name of event (optional) |
| 58 | }; | 61 | }; |
| 59 | 62 | ||
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index c6b18cfba..bfb77cc31 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -19,8 +19,6 @@ | |||
| 19 | enum class ErrorDescription : u32 { | 19 | enum class ErrorDescription : u32 { |
| 20 | Success = 0, | 20 | Success = 0, |
| 21 | RemoteProcessDead = 301, | 21 | RemoteProcessDead = 301, |
| 22 | InvalidOffset = 6061, | ||
| 23 | InvalidLength = 6062, | ||
| 24 | }; | 22 | }; |
| 25 | 23 | ||
| 26 | /** | 24 | /** |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 8318eff5f..1f8ed265e 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -21,17 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | namespace Service::Account { | 22 | namespace Service::Account { |
| 23 | 23 | ||
| 24 | // TODO: RE this structure | ||
| 25 | struct UserData { | ||
| 26 | INSERT_PADDING_WORDS(1); | ||
| 27 | u32 icon_id; | ||
| 28 | u8 bg_color_id; | ||
| 29 | INSERT_PADDING_BYTES(0x7); | ||
| 30 | INSERT_PADDING_BYTES(0x10); | ||
| 31 | INSERT_PADDING_BYTES(0x60); | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | ||
| 34 | |||
| 35 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg | 24 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg |
| 36 | // used as a backup should the one on disk not exist | 25 | // used as a backup should the one on disk not exist |
| 37 | constexpr u32 backup_jpeg_size = 107; | 26 | constexpr u32 backup_jpeg_size = 107; |
| @@ -72,9 +61,11 @@ private: | |||
| 72 | void Get(Kernel::HLERequestContext& ctx) { | 61 | void Get(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 62 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); |
| 74 | ProfileBase profile_base{}; | 63 | ProfileBase profile_base{}; |
| 75 | std::array<u8, MAX_DATA> data{}; | 64 | ProfileData data{}; |
| 76 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { | 65 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { |
| 77 | ctx.WriteBuffer(data); | 66 | std::array<u8, sizeof(ProfileData)> raw_data; |
| 67 | std::memcpy(raw_data.data(), &data, sizeof(ProfileData)); | ||
| 68 | ctx.WriteBuffer(raw_data); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 16}; | 69 | IPC::ResponseBuilder rb{ctx, 16}; |
| 79 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 80 | rb.PushRaw(profile_base); | 71 | rb.PushRaw(profile_base); |
| @@ -216,10 +207,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { | |||
| 216 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { | 207 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { |
| 217 | IPC::RequestParser rp{ctx}; | 208 | IPC::RequestParser rp{ctx}; |
| 218 | UUID user_id = rp.PopRaw<UUID>(); | 209 | UUID user_id = rp.PopRaw<UUID>(); |
| 210 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | ||
| 211 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | rb.Push(RESULT_SUCCESS); | 213 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<IProfile>(user_id, *profile_manager); | 214 | rb.PushIpcInterface<IProfile>(user_id, *profile_manager); |
| 222 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | ||
| 223 | } | 215 | } |
| 224 | 216 | ||
| 225 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { | 217 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { |
| @@ -236,10 +228,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx | |||
| 236 | } | 228 | } |
| 237 | 229 | ||
| 238 | void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { | 230 | void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { |
| 231 | LOG_DEBUG(Service_ACC, "called"); | ||
| 239 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 232 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 240 | rb.Push(RESULT_SUCCESS); | 233 | rb.Push(RESULT_SUCCESS); |
| 241 | rb.PushIpcInterface<IManagerForApplication>(); | 234 | rb.PushIpcInterface<IManagerForApplication>(); |
| 242 | LOG_DEBUG(Service_ACC, "called"); | ||
| 243 | } | 235 | } |
| 244 | 236 | ||
| 245 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { | 237 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { |
| @@ -252,8 +244,10 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex | |||
| 252 | rb.PushRaw<u128>(INVALID_UUID); | 244 | rb.PushRaw<u128>(INVALID_UUID); |
| 253 | return; | 245 | return; |
| 254 | } | 246 | } |
| 255 | auto user_list = profile_manager->GetAllUsers(); | 247 | |
| 256 | if (user_list.empty()) { | 248 | const auto user_list = profile_manager->GetAllUsers(); |
| 249 | if (std::all_of(user_list.begin(), user_list.end(), | ||
| 250 | [](const auto& user) { return user.uuid == INVALID_UUID; })) { | ||
| 257 | rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code | 251 | rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code |
| 258 | rb.PushRaw<u128>(INVALID_UUID); | 252 | rb.PushRaw<u128>(INVALID_UUID); |
| 259 | return; | 253 | return; |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index c08394e4c..1316d0b07 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -2,8 +2,11 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 5 | #include <random> | 6 | #include <random> |
| 6 | 7 | ||
| 8 | #include <fmt/format.h> | ||
| 9 | |||
| 7 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 8 | #include "core/hle/service/acc/profile_manager.h" | 11 | #include "core/hle/service/acc/profile_manager.h" |
| 9 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| @@ -15,7 +18,7 @@ struct UserRaw { | |||
| 15 | UUID uuid2; | 18 | UUID uuid2; |
| 16 | u64 timestamp; | 19 | u64 timestamp; |
| 17 | ProfileUsername username; | 20 | ProfileUsername username; |
| 18 | INSERT_PADDING_BYTES(0x80); | 21 | ProfileData extra_data; |
| 19 | }; | 22 | }; |
| 20 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); | 23 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); |
| 21 | 24 | ||
| @@ -39,6 +42,19 @@ UUID UUID::Generate() { | |||
| 39 | return UUID{distribution(gen), distribution(gen)}; | 42 | return UUID{distribution(gen), distribution(gen)}; |
| 40 | } | 43 | } |
| 41 | 44 | ||
| 45 | std::string UUID::Format() const { | ||
| 46 | return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | ||
| 47 | } | ||
| 48 | |||
| 49 | std::string UUID::FormatSwitch() const { | ||
| 50 | std::array<u8, 16> s{}; | ||
| 51 | std::memcpy(s.data(), uuid.data(), sizeof(u128)); | ||
| 52 | return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" | ||
| 53 | ":02x}{:02x}{:02x}{:02x}{:02x}", | ||
| 54 | s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], | ||
| 55 | s[12], s[13], s[14], s[15]); | ||
| 56 | } | ||
| 57 | |||
| 42 | ProfileManager::ProfileManager() { | 58 | ProfileManager::ProfileManager() { |
| 43 | ParseUserSaveFile(); | 59 | ParseUserSaveFile(); |
| 44 | 60 | ||
| @@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() { | |||
| 325 | return; | 341 | return; |
| 326 | } | 342 | } |
| 327 | 343 | ||
| 328 | for (std::size_t i = 0; i < MAX_USERS; ++i) { | 344 | for (const auto& user : data.users) { |
| 329 | const auto& user = data.users[i]; | 345 | if (user.uuid == UUID(INVALID_UUID)) { |
| 346 | continue; | ||
| 347 | } | ||
| 330 | 348 | ||
| 331 | if (user.uuid != UUID(INVALID_UUID)) | 349 | AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false}); |
| 332 | AddUser({user.uuid, user.username, user.timestamp, {}, false}); | ||
| 333 | } | 350 | } |
| 334 | 351 | ||
| 335 | std::stable_partition(profiles.begin(), profiles.end(), | 352 | std::stable_partition(profiles.begin(), profiles.end(), |
| @@ -344,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() { | |||
| 344 | raw.users[i].uuid2 = profiles[i].user_uuid; | 361 | raw.users[i].uuid2 = profiles[i].user_uuid; |
| 345 | raw.users[i].uuid = profiles[i].user_uuid; | 362 | raw.users[i].uuid = profiles[i].user_uuid; |
| 346 | raw.users[i].timestamp = profiles[i].creation_time; | 363 | raw.users[i].timestamp = profiles[i].creation_time; |
| 364 | raw.users[i].extra_data = profiles[i].data; | ||
| 347 | } | 365 | } |
| 348 | 366 | ||
| 349 | const auto raw_path = | 367 | const auto raw_path = |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 747c46c20..c4ce2e0b3 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Account { | 14 | namespace Service::Account { |
| 15 | constexpr std::size_t MAX_USERS = 8; | 15 | constexpr std::size_t MAX_USERS = 8; |
| 16 | constexpr std::size_t MAX_DATA = 128; | ||
| 17 | constexpr u128 INVALID_UUID{{0, 0}}; | 16 | constexpr u128 INVALID_UUID{{0, 0}}; |
| 18 | 17 | ||
| 19 | struct UUID { | 18 | struct UUID { |
| @@ -42,26 +41,28 @@ struct UUID { | |||
| 42 | void Invalidate() { | 41 | void Invalidate() { |
| 43 | uuid = INVALID_UUID; | 42 | uuid = INVALID_UUID; |
| 44 | } | 43 | } |
| 45 | std::string Format() const { | ||
| 46 | return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | ||
| 47 | } | ||
| 48 | 44 | ||
| 49 | std::string FormatSwitch() const { | 45 | std::string Format() const; |
| 50 | std::array<u8, 16> s{}; | 46 | std::string FormatSwitch() const; |
| 51 | std::memcpy(s.data(), uuid.data(), sizeof(u128)); | ||
| 52 | return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" | ||
| 53 | ":02x}{:02x}{:02x}{:02x}{:02x}", | ||
| 54 | s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], | ||
| 55 | s[12], s[13], s[14], s[15]); | ||
| 56 | } | ||
| 57 | }; | 47 | }; |
| 58 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | 48 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); |
| 59 | 49 | ||
| 60 | constexpr std::size_t profile_username_size = 32; | 50 | constexpr std::size_t profile_username_size = 32; |
| 61 | using ProfileUsername = std::array<u8, profile_username_size>; | 51 | using ProfileUsername = std::array<u8, profile_username_size>; |
| 62 | using ProfileData = std::array<u8, MAX_DATA>; | ||
| 63 | using UserIDArray = std::array<UUID, MAX_USERS>; | 52 | using UserIDArray = std::array<UUID, MAX_USERS>; |
| 64 | 53 | ||
| 54 | /// Contains extra data related to a user. | ||
| 55 | /// TODO: RE this structure | ||
| 56 | struct ProfileData { | ||
| 57 | INSERT_PADDING_WORDS(1); | ||
| 58 | u32 icon_id; | ||
| 59 | u8 bg_color_id; | ||
| 60 | INSERT_PADDING_BYTES(0x7); | ||
| 61 | INSERT_PADDING_BYTES(0x10); | ||
| 62 | INSERT_PADDING_BYTES(0x60); | ||
| 63 | }; | ||
| 64 | static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); | ||
| 65 | |||
| 65 | /// This holds general information about a users profile. This is where we store all the information | 66 | /// This holds general information about a users profile. This is where we store all the information |
| 66 | /// based on a specific user | 67 | /// based on a specific user |
| 67 | struct ProfileInfo { | 68 | struct ProfileInfo { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 0477ce66e..3a7b6da84 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -6,14 +6,21 @@ | |||
| 6 | #include <cinttypes> | 6 | #include <cinttypes> |
| 7 | #include <cstring> | 7 | #include <cstring> |
| 8 | #include <stack> | 8 | #include <stack> |
| 9 | #include "audio_core/audio_renderer.h" | ||
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/kernel/event.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/readable_event.h" | ||
| 15 | #include "core/hle/kernel/shared_memory.h" | ||
| 16 | #include "core/hle/kernel/writable_event.h" | ||
| 13 | #include "core/hle/service/acc/profile_manager.h" | 17 | #include "core/hle/service/acc/profile_manager.h" |
| 14 | #include "core/hle/service/am/am.h" | 18 | #include "core/hle/service/am/am.h" |
| 15 | #include "core/hle/service/am/applet_ae.h" | 19 | #include "core/hle/service/am/applet_ae.h" |
| 16 | #include "core/hle/service/am/applet_oe.h" | 20 | #include "core/hle/service/am/applet_oe.h" |
| 21 | #include "core/hle/service/am/applets/applets.h" | ||
| 22 | #include "core/hle/service/am/applets/software_keyboard.h" | ||
| 23 | #include "core/hle/service/am/applets/stub_applet.h" | ||
| 17 | #include "core/hle/service/am/idle.h" | 24 | #include "core/hle/service/am/idle.h" |
| 18 | #include "core/hle/service/am/omm.h" | 25 | #include "core/hle/service/am/omm.h" |
| 19 | #include "core/hle/service/am/spsm.h" | 26 | #include "core/hle/service/am/spsm.h" |
| @@ -28,6 +35,13 @@ | |||
| 28 | 35 | ||
| 29 | namespace Service::AM { | 36 | namespace Service::AM { |
| 30 | 37 | ||
| 38 | constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; | ||
| 39 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | ||
| 40 | |||
| 41 | enum class AppletId : u32 { | ||
| 42 | SoftwareKeyboard = 0x11, | ||
| 43 | }; | ||
| 44 | |||
| 31 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | 45 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; |
| 32 | 46 | ||
| 33 | struct LaunchParameters { | 47 | struct LaunchParameters { |
| @@ -196,15 +210,16 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 196 | RegisterHandlers(functions); | 210 | RegisterHandlers(functions); |
| 197 | 211 | ||
| 198 | auto& kernel = Core::System::GetInstance().Kernel(); | 212 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 199 | launchable_event = | 213 | launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 200 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); | 214 | "ISelfController:LaunchableEvent"); |
| 201 | } | 215 | } |
| 202 | 216 | ||
| 203 | ISelfController::~ISelfController() = default; | 217 | ISelfController::~ISelfController() = default; |
| 204 | 218 | ||
| 205 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | 219 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { |
| 206 | // Takes 3 input u8s with each field located immediately after the previous u8, these are | 220 | // Takes 3 input u8s with each field located immediately after the previous |
| 207 | // bool flags. No output. | 221 | // u8, these are bool flags. No output. |
| 222 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 208 | 223 | ||
| 209 | IPC::RequestParser rp{ctx}; | 224 | IPC::RequestParser rp{ctx}; |
| 210 | 225 | ||
| @@ -217,159 +232,156 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | |||
| 217 | 232 | ||
| 218 | IPC::ResponseBuilder rb{ctx, 2}; | 233 | IPC::ResponseBuilder rb{ctx, 2}; |
| 219 | rb.Push(RESULT_SUCCESS); | 234 | rb.Push(RESULT_SUCCESS); |
| 220 | |||
| 221 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 222 | } | 235 | } |
| 223 | 236 | ||
| 224 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { | 237 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { |
| 238 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 239 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 2}; | 240 | IPC::ResponseBuilder rb{ctx, 2}; |
| 226 | rb.Push(RESULT_SUCCESS); | 241 | rb.Push(RESULT_SUCCESS); |
| 227 | |||
| 228 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 229 | } | 242 | } |
| 230 | 243 | ||
| 231 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { | 244 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| 232 | IPC::RequestParser rp{ctx}; | 245 | IPC::RequestParser rp{ctx}; |
| 233 | 246 | ||
| 234 | bool flag = rp.Pop<bool>(); | 247 | bool flag = rp.Pop<bool>(); |
| 248 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 235 | 249 | ||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | 250 | IPC::ResponseBuilder rb{ctx, 2}; |
| 237 | rb.Push(RESULT_SUCCESS); | 251 | rb.Push(RESULT_SUCCESS); |
| 238 | |||
| 239 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 240 | } | 252 | } |
| 241 | 253 | ||
| 242 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { | 254 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { |
| 255 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 256 | |||
| 243 | IPC::ResponseBuilder rb{ctx, 2}; | 257 | IPC::ResponseBuilder rb{ctx, 2}; |
| 244 | rb.Push(RESULT_SUCCESS); | 258 | rb.Push(RESULT_SUCCESS); |
| 245 | |||
| 246 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 247 | } | 259 | } |
| 248 | 260 | ||
| 249 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { | 261 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| 250 | IPC::RequestParser rp{ctx}; | 262 | IPC::RequestParser rp{ctx}; |
| 251 | 263 | ||
| 252 | bool flag = rp.Pop<bool>(); | 264 | bool flag = rp.Pop<bool>(); |
| 265 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 253 | 266 | ||
| 254 | IPC::ResponseBuilder rb{ctx, 2}; | 267 | IPC::ResponseBuilder rb{ctx, 2}; |
| 255 | rb.Push(RESULT_SUCCESS); | 268 | rb.Push(RESULT_SUCCESS); |
| 256 | |||
| 257 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 258 | } | 269 | } |
| 259 | 270 | ||
| 260 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { | 271 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { |
| 261 | // Takes 3 input u8s with each field located immediately after the previous u8, these are | 272 | // Takes 3 input u8s with each field located immediately after the previous |
| 262 | // bool flags. No output. | 273 | // u8, these are bool flags. No output. |
| 263 | IPC::RequestParser rp{ctx}; | 274 | IPC::RequestParser rp{ctx}; |
| 264 | 275 | ||
| 265 | bool enabled = rp.Pop<bool>(); | 276 | bool enabled = rp.Pop<bool>(); |
| 277 | LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); | ||
| 266 | 278 | ||
| 267 | IPC::ResponseBuilder rb{ctx, 2}; | 279 | IPC::ResponseBuilder rb{ctx, 2}; |
| 268 | rb.Push(RESULT_SUCCESS); | 280 | rb.Push(RESULT_SUCCESS); |
| 269 | |||
| 270 | LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); | ||
| 271 | } | 281 | } |
| 272 | 282 | ||
| 273 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { | 283 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { |
| 284 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 285 | |||
| 274 | IPC::ResponseBuilder rb{ctx, 2}; | 286 | IPC::ResponseBuilder rb{ctx, 2}; |
| 275 | rb.Push(RESULT_SUCCESS); | 287 | rb.Push(RESULT_SUCCESS); |
| 276 | |||
| 277 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 278 | } | 288 | } |
| 279 | 289 | ||
| 280 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { | 290 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { |
| 291 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 292 | |||
| 281 | IPC::ResponseBuilder rb{ctx, 2}; | 293 | IPC::ResponseBuilder rb{ctx, 2}; |
| 282 | rb.Push(RESULT_SUCCESS); | 294 | rb.Push(RESULT_SUCCESS); |
| 283 | |||
| 284 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 285 | } | 295 | } |
| 286 | 296 | ||
| 287 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { | 297 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { |
| 288 | launchable_event->Signal(); | 298 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 299 | |||
| 300 | launchable_event.writable->Signal(); | ||
| 289 | 301 | ||
| 290 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 302 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 291 | rb.Push(RESULT_SUCCESS); | 303 | rb.Push(RESULT_SUCCESS); |
| 292 | rb.PushCopyObjects(launchable_event); | 304 | rb.PushCopyObjects(launchable_event.readable); |
| 293 | |||
| 294 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 295 | } | 305 | } |
| 296 | 306 | ||
| 297 | void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { | 307 | void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { |
| 308 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 309 | |||
| 298 | IPC::ResponseBuilder rb{ctx, 2}; | 310 | IPC::ResponseBuilder rb{ctx, 2}; |
| 299 | rb.Push(RESULT_SUCCESS); | 311 | rb.Push(RESULT_SUCCESS); |
| 300 | |||
| 301 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 302 | } | 312 | } |
| 303 | 313 | ||
| 304 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { | 314 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { |
| 305 | // TODO(Subv): Find out how AM determines the display to use, for now just create the layer | 315 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 306 | // in the Default display. | 316 | // TODO(Subv): Find out how AM determines the display to use, for now just |
| 317 | // create the layer in the Default display. | ||
| 307 | u64 display_id = nvflinger->OpenDisplay("Default"); | 318 | u64 display_id = nvflinger->OpenDisplay("Default"); |
| 308 | u64 layer_id = nvflinger->CreateLayer(display_id); | 319 | u64 layer_id = nvflinger->CreateLayer(display_id); |
| 309 | 320 | ||
| 310 | IPC::ResponseBuilder rb{ctx, 4}; | 321 | IPC::ResponseBuilder rb{ctx, 4}; |
| 311 | rb.Push(RESULT_SUCCESS); | 322 | rb.Push(RESULT_SUCCESS); |
| 312 | rb.Push(layer_id); | 323 | rb.Push(layer_id); |
| 313 | |||
| 314 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 315 | } | 324 | } |
| 316 | 325 | ||
| 317 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { | 326 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { |
| 327 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 328 | |||
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | 329 | IPC::ResponseBuilder rb{ctx, 2}; |
| 319 | rb.Push(RESULT_SUCCESS); | 330 | rb.Push(RESULT_SUCCESS); |
| 320 | |||
| 321 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 322 | } | 331 | } |
| 323 | 332 | ||
| 324 | void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { | 333 | void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { |
| 325 | IPC::RequestParser rp{ctx}; | 334 | IPC::RequestParser rp{ctx}; |
| 326 | idle_time_detection_extension = rp.Pop<u32>(); | 335 | idle_time_detection_extension = rp.Pop<u32>(); |
| 336 | LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}", | ||
| 337 | idle_time_detection_extension); | ||
| 338 | |||
| 327 | IPC::ResponseBuilder rb{ctx, 2}; | 339 | IPC::ResponseBuilder rb{ctx, 2}; |
| 328 | rb.Push(RESULT_SUCCESS); | 340 | rb.Push(RESULT_SUCCESS); |
| 329 | |||
| 330 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 331 | } | 341 | } |
| 332 | 342 | ||
| 333 | void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { | 343 | void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { |
| 344 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 345 | |||
| 334 | IPC::ResponseBuilder rb{ctx, 3}; | 346 | IPC::ResponseBuilder rb{ctx, 3}; |
| 335 | rb.Push(RESULT_SUCCESS); | 347 | rb.Push(RESULT_SUCCESS); |
| 336 | rb.Push<u32>(idle_time_detection_extension); | 348 | rb.Push<u32>(idle_time_detection_extension); |
| 337 | |||
| 338 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 339 | } | 349 | } |
| 340 | 350 | ||
| 341 | AppletMessageQueue::AppletMessageQueue() { | 351 | AppletMessageQueue::AppletMessageQueue() { |
| 342 | auto& kernel = Core::System::GetInstance().Kernel(); | 352 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 343 | on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, | 353 | on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 344 | "AMMessageQueue:OnMessageRecieved"); | 354 | "AMMessageQueue:OnMessageRecieved"); |
| 345 | on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | 355 | on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( |
| 346 | "AMMessageQueue:OperationModeChanged"); | 356 | kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged"); |
| 347 | } | 357 | } |
| 348 | 358 | ||
| 349 | AppletMessageQueue::~AppletMessageQueue() = default; | 359 | AppletMessageQueue::~AppletMessageQueue() = default; |
| 350 | 360 | ||
| 351 | const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { | 361 | const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() |
| 352 | return on_new_message; | 362 | const { |
| 363 | return on_new_message.readable; | ||
| 353 | } | 364 | } |
| 354 | 365 | ||
| 355 | const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { | 366 | const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() |
| 356 | return on_operation_mode_changed; | 367 | const { |
| 368 | return on_operation_mode_changed.readable; | ||
| 357 | } | 369 | } |
| 358 | 370 | ||
| 359 | void AppletMessageQueue::PushMessage(AppletMessage msg) { | 371 | void AppletMessageQueue::PushMessage(AppletMessage msg) { |
| 360 | messages.push(msg); | 372 | messages.push(msg); |
| 361 | on_new_message->Signal(); | 373 | on_new_message.writable->Signal(); |
| 362 | } | 374 | } |
| 363 | 375 | ||
| 364 | AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { | 376 | AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { |
| 365 | if (messages.empty()) { | 377 | if (messages.empty()) { |
| 366 | on_new_message->Clear(); | 378 | on_new_message.writable->Clear(); |
| 367 | return AppletMessage::NoMessage; | 379 | return AppletMessage::NoMessage; |
| 368 | } | 380 | } |
| 369 | auto msg = messages.front(); | 381 | auto msg = messages.front(); |
| 370 | messages.pop(); | 382 | messages.pop(); |
| 371 | if (messages.empty()) { | 383 | if (messages.empty()) { |
| 372 | on_new_message->Clear(); | 384 | on_new_message.writable->Clear(); |
| 373 | } | 385 | } |
| 374 | return msg; | 386 | return msg; |
| 375 | } | 387 | } |
| @@ -381,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const { | |||
| 381 | void AppletMessageQueue::OperationModeChanged() { | 393 | void AppletMessageQueue::OperationModeChanged() { |
| 382 | PushMessage(AppletMessage::OperationModeChanged); | 394 | PushMessage(AppletMessage::OperationModeChanged); |
| 383 | PushMessage(AppletMessage::PerformanceModeChanged); | 395 | PushMessage(AppletMessage::PerformanceModeChanged); |
| 384 | on_operation_mode_changed->Signal(); | 396 | on_operation_mode_changed.writable->Signal(); |
| 385 | } | 397 | } |
| 386 | 398 | ||
| 387 | ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) | 399 | ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) |
| @@ -418,97 +430,131 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q | |||
| 418 | // clang-format on | 430 | // clang-format on |
| 419 | 431 | ||
| 420 | RegisterHandlers(functions); | 432 | RegisterHandlers(functions); |
| 421 | |||
| 422 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 423 | event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); | ||
| 424 | } | 433 | } |
| 425 | 434 | ||
| 426 | ICommonStateGetter::~ICommonStateGetter() = default; | 435 | ICommonStateGetter::~ICommonStateGetter() = default; |
| 427 | 436 | ||
| 428 | void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { | 437 | void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { |
| 438 | LOG_DEBUG(Service_AM, "called"); | ||
| 439 | |||
| 429 | IPC::ResponseBuilder rb{ctx, 3}; | 440 | IPC::ResponseBuilder rb{ctx, 3}; |
| 430 | rb.Push(RESULT_SUCCESS); | 441 | rb.Push(RESULT_SUCCESS); |
| 431 | 442 | ||
| 432 | rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode | 443 | rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode |
| 433 | |||
| 434 | LOG_DEBUG(Service_AM, "called"); | ||
| 435 | } | 444 | } |
| 436 | 445 | ||
| 437 | void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { | 446 | void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { |
| 447 | LOG_DEBUG(Service_AM, "called"); | ||
| 448 | |||
| 438 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 449 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 439 | rb.Push(RESULT_SUCCESS); | 450 | rb.Push(RESULT_SUCCESS); |
| 440 | rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); | 451 | rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); |
| 441 | |||
| 442 | LOG_DEBUG(Service_AM, "called"); | ||
| 443 | } | 452 | } |
| 444 | 453 | ||
| 445 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { | 454 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { |
| 455 | LOG_DEBUG(Service_AM, "called"); | ||
| 456 | |||
| 446 | IPC::ResponseBuilder rb{ctx, 3}; | 457 | IPC::ResponseBuilder rb{ctx, 3}; |
| 447 | rb.Push(RESULT_SUCCESS); | 458 | rb.Push(RESULT_SUCCESS); |
| 448 | rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); | 459 | rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); |
| 449 | |||
| 450 | LOG_DEBUG(Service_AM, "called"); | ||
| 451 | } | 460 | } |
| 452 | 461 | ||
| 453 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { | 462 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { |
| 463 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 464 | |||
| 454 | IPC::ResponseBuilder rb{ctx, 3}; | 465 | IPC::ResponseBuilder rb{ctx, 3}; |
| 455 | rb.Push(RESULT_SUCCESS); | 466 | rb.Push(RESULT_SUCCESS); |
| 456 | rb.Push(static_cast<u8>(FocusState::InFocus)); | 467 | rb.Push(static_cast<u8>(FocusState::InFocus)); |
| 457 | |||
| 458 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 459 | } | 468 | } |
| 460 | 469 | ||
| 461 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { | 470 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { |
| 471 | LOG_DEBUG(Service_AM, "called"); | ||
| 472 | |||
| 462 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 473 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 463 | rb.Push(RESULT_SUCCESS); | 474 | rb.Push(RESULT_SUCCESS); |
| 464 | rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); | 475 | rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); |
| 465 | |||
| 466 | LOG_DEBUG(Service_AM, "called"); | ||
| 467 | } | 476 | } |
| 468 | 477 | ||
| 469 | void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { | 478 | void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { |
| 479 | LOG_DEBUG(Service_AM, "called"); | ||
| 480 | |||
| 470 | IPC::ResponseBuilder rb{ctx, 4}; | 481 | IPC::ResponseBuilder rb{ctx, 4}; |
| 471 | rb.Push(RESULT_SUCCESS); | 482 | rb.Push(RESULT_SUCCESS); |
| 472 | 483 | ||
| 473 | if (Settings::values.use_docked_mode) { | 484 | if (Settings::values.use_docked_mode) { |
| 474 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | 485 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 475 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | 486 | static_cast<u32>(Settings::values.resolution_factor)); |
| 487 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | ||
| 488 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 476 | } else { | 489 | } else { |
| 477 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | 490 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * |
| 478 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | 491 | static_cast<u32>(Settings::values.resolution_factor)); |
| 492 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * | ||
| 493 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 479 | } | 494 | } |
| 495 | } | ||
| 480 | 496 | ||
| 481 | LOG_DEBUG(Service_AM, "called"); | 497 | IStorage::IStorage(std::vector<u8> buffer) |
| 498 | : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | ||
| 499 | // clang-format off | ||
| 500 | static const FunctionInfo functions[] = { | ||
| 501 | {0, &IStorage::Open, "Open"}, | ||
| 502 | {1, nullptr, "OpenTransferStorage"}, | ||
| 503 | }; | ||
| 504 | // clang-format on | ||
| 505 | |||
| 506 | RegisterHandlers(functions); | ||
| 507 | } | ||
| 508 | |||
| 509 | IStorage::~IStorage() = default; | ||
| 510 | |||
| 511 | const std::vector<u8>& IStorage::GetData() const { | ||
| 512 | return buffer; | ||
| 482 | } | 513 | } |
| 483 | 514 | ||
| 484 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | 515 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { |
| 485 | const bool use_docked_mode{Settings::values.use_docked_mode}; | 516 | const bool use_docked_mode{Settings::values.use_docked_mode}; |
| 517 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); | ||
| 518 | |||
| 486 | IPC::ResponseBuilder rb{ctx, 3}; | 519 | IPC::ResponseBuilder rb{ctx, 3}; |
| 487 | rb.Push(RESULT_SUCCESS); | 520 | rb.Push(RESULT_SUCCESS); |
| 488 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); | 521 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); |
| 489 | |||
| 490 | LOG_DEBUG(Service_AM, "called"); | ||
| 491 | } | 522 | } |
| 492 | 523 | ||
| 493 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | 524 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { |
| 494 | const bool use_docked_mode{Settings::values.use_docked_mode}; | 525 | const bool use_docked_mode{Settings::values.use_docked_mode}; |
| 526 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); | ||
| 527 | |||
| 495 | IPC::ResponseBuilder rb{ctx, 3}; | 528 | IPC::ResponseBuilder rb{ctx, 3}; |
| 496 | rb.Push(RESULT_SUCCESS); | 529 | rb.Push(RESULT_SUCCESS); |
| 497 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked | 530 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked |
| 498 | : APM::PerformanceMode::Handheld)); | 531 | : APM::PerformanceMode::Handheld)); |
| 499 | |||
| 500 | LOG_DEBUG(Service_AM, "called"); | ||
| 501 | } | 532 | } |
| 502 | 533 | ||
| 503 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | 534 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
| 504 | public: | 535 | public: |
| 505 | explicit IStorageAccessor(std::vector<u8> buffer) | 536 | explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) |
| 506 | : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { | 537 | : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { |
| 507 | // clang-format off | 538 | // clang-format off |
| 508 | static const FunctionInfo functions[] = { | 539 | static const FunctionInfo functions[] = { |
| 509 | {0, &IStorageAccessor::GetSize, "GetSize"}, | 540 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
| 510 | {10, &IStorageAccessor::Write, "Write"}, | 541 | {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, |
| 511 | {11, &IStorageAccessor::Read, "Read"}, | 542 | {10, &ILibraryAppletAccessor::Start, "Start"}, |
| 543 | {20, nullptr, "RequestExit"}, | ||
| 544 | {25, nullptr, "Terminate"}, | ||
| 545 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, | ||
| 546 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, | ||
| 547 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, | ||
| 548 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, | ||
| 549 | {102, nullptr, "PushExtraStorage"}, | ||
| 550 | {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, | ||
| 551 | {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, | ||
| 552 | {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, | ||
| 553 | {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, | ||
| 554 | {110, nullptr, "NeedsToExitProcess"}, | ||
| 555 | {120, nullptr, "GetLibraryAppletInfo"}, | ||
| 556 | {150, nullptr, "RequestForAppletToGetForeground"}, | ||
| 557 | {160, nullptr, "GetIndirectLayerConsumerHandle"}, | ||
| 512 | }; | 558 | }; |
| 513 | // clang-format on | 559 | // clang-format on |
| 514 | 560 | ||
| @@ -516,158 +562,200 @@ public: | |||
| 516 | } | 562 | } |
| 517 | 563 | ||
| 518 | private: | 564 | private: |
| 519 | std::vector<u8> buffer; | 565 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { |
| 566 | LOG_DEBUG(Service_AM, "called"); | ||
| 520 | 567 | ||
| 521 | void GetSize(Kernel::HLERequestContext& ctx) { | 568 | applet->GetBroker().SignalStateChanged(); |
| 522 | IPC::ResponseBuilder rb{ctx, 4}; | 569 | const auto event = applet->GetBroker().GetStateChangedEvent(); |
| 523 | 570 | ||
| 571 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 524 | rb.Push(RESULT_SUCCESS); | 572 | rb.Push(RESULT_SUCCESS); |
| 525 | rb.Push(static_cast<u64>(buffer.size())); | 573 | rb.PushCopyObjects(event); |
| 574 | } | ||
| 526 | 575 | ||
| 576 | void IsCompleted(Kernel::HLERequestContext& ctx) { | ||
| 527 | LOG_DEBUG(Service_AM, "called"); | 577 | LOG_DEBUG(Service_AM, "called"); |
| 578 | |||
| 579 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 580 | rb.Push(RESULT_SUCCESS); | ||
| 581 | rb.Push<u32>(applet->TransactionComplete()); | ||
| 528 | } | 582 | } |
| 529 | 583 | ||
| 530 | void Write(Kernel::HLERequestContext& ctx) { | 584 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 531 | IPC::RequestParser rp{ctx}; | 585 | LOG_DEBUG(Service_AM, "called"); |
| 532 | 586 | ||
| 533 | const u64 offset{rp.Pop<u64>()}; | 587 | IPC::ResponseBuilder rb{ctx, 2}; |
| 534 | const std::vector<u8> data{ctx.ReadBuffer()}; | 588 | rb.Push(applet->GetStatus()); |
| 589 | } | ||
| 535 | 590 | ||
| 536 | ASSERT(offset + data.size() <= buffer.size()); | 591 | void Start(Kernel::HLERequestContext& ctx) { |
| 592 | LOG_DEBUG(Service_AM, "called"); | ||
| 537 | 593 | ||
| 538 | std::memcpy(&buffer[offset], data.data(), data.size()); | 594 | ASSERT(applet != nullptr); |
| 595 | |||
| 596 | applet->Initialize(); | ||
| 597 | applet->Execute(); | ||
| 539 | 598 | ||
| 540 | IPC::ResponseBuilder rb{ctx, 2}; | 599 | IPC::ResponseBuilder rb{ctx, 2}; |
| 541 | rb.Push(RESULT_SUCCESS); | 600 | rb.Push(RESULT_SUCCESS); |
| 542 | |||
| 543 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 544 | } | 601 | } |
| 545 | 602 | ||
| 546 | void Read(Kernel::HLERequestContext& ctx) { | 603 | void PushInData(Kernel::HLERequestContext& ctx) { |
| 604 | LOG_DEBUG(Service_AM, "called"); | ||
| 605 | |||
| 547 | IPC::RequestParser rp{ctx}; | 606 | IPC::RequestParser rp{ctx}; |
| 607 | applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); | ||
| 608 | |||
| 609 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 610 | rb.Push(RESULT_SUCCESS); | ||
| 611 | } | ||
| 612 | |||
| 613 | void PopOutData(Kernel::HLERequestContext& ctx) { | ||
| 614 | LOG_DEBUG(Service_AM, "called"); | ||
| 548 | 615 | ||
| 549 | const u64 offset{rp.Pop<u64>()}; | 616 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 550 | const std::size_t size{ctx.GetWriteBufferSize()}; | ||
| 551 | 617 | ||
| 552 | ASSERT(offset + size <= buffer.size()); | 618 | const auto storage = applet->GetBroker().PopNormalDataToGame(); |
| 619 | if (storage == nullptr) { | ||
| 620 | LOG_ERROR(Service_AM, | ||
| 621 | "storage is a nullptr. There is no data in the current normal channel"); | ||
| 553 | 622 | ||
| 554 | ctx.WriteBuffer(buffer.data() + offset, size); | 623 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| 624 | return; | ||
| 625 | } | ||
| 555 | 626 | ||
| 556 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 557 | rb.Push(RESULT_SUCCESS); | 627 | rb.Push(RESULT_SUCCESS); |
| 558 | 628 | rb.PushIpcInterface<IStorage>(std::move(*storage)); | |
| 559 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 560 | } | 629 | } |
| 561 | }; | ||
| 562 | 630 | ||
| 563 | class IStorage final : public ServiceFramework<IStorage> { | 631 | void PushInteractiveInData(Kernel::HLERequestContext& ctx) { |
| 564 | public: | 632 | LOG_DEBUG(Service_AM, "called"); |
| 565 | explicit IStorage(std::vector<u8> buffer) | ||
| 566 | : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | ||
| 567 | // clang-format off | ||
| 568 | static const FunctionInfo functions[] = { | ||
| 569 | {0, &IStorage::Open, "Open"}, | ||
| 570 | {1, nullptr, "OpenTransferStorage"}, | ||
| 571 | }; | ||
| 572 | // clang-format on | ||
| 573 | 633 | ||
| 574 | RegisterHandlers(functions); | 634 | IPC::RequestParser rp{ctx}; |
| 635 | applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); | ||
| 636 | |||
| 637 | ASSERT(applet->IsInitialized()); | ||
| 638 | applet->ExecuteInteractive(); | ||
| 639 | applet->Execute(); | ||
| 640 | |||
| 641 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 642 | rb.Push(RESULT_SUCCESS); | ||
| 575 | } | 643 | } |
| 576 | 644 | ||
| 577 | private: | 645 | void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { |
| 578 | std::vector<u8> buffer; | 646 | LOG_DEBUG(Service_AM, "called"); |
| 579 | 647 | ||
| 580 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 581 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 648 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 582 | 649 | ||
| 650 | const auto storage = applet->GetBroker().PopInteractiveDataToGame(); | ||
| 651 | if (storage == nullptr) { | ||
| 652 | LOG_ERROR(Service_AM, | ||
| 653 | "storage is a nullptr. There is no data in the current interactive channel"); | ||
| 654 | |||
| 655 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 656 | return; | ||
| 657 | } | ||
| 658 | |||
| 659 | rb.Push(RESULT_SUCCESS); | ||
| 660 | rb.PushIpcInterface<IStorage>(std::move(*storage)); | ||
| 661 | } | ||
| 662 | |||
| 663 | void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { | ||
| 664 | LOG_DEBUG(Service_AM, "called"); | ||
| 665 | |||
| 666 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 583 | rb.Push(RESULT_SUCCESS); | 667 | rb.Push(RESULT_SUCCESS); |
| 584 | rb.PushIpcInterface<AM::IStorageAccessor>(buffer); | 668 | rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); |
| 669 | } | ||
| 585 | 670 | ||
| 671 | void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { | ||
| 586 | LOG_DEBUG(Service_AM, "called"); | 672 | LOG_DEBUG(Service_AM, "called"); |
| 673 | |||
| 674 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 675 | rb.Push(RESULT_SUCCESS); | ||
| 676 | rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); | ||
| 587 | } | 677 | } |
| 678 | |||
| 679 | std::shared_ptr<Applets::Applet> applet; | ||
| 588 | }; | 680 | }; |
| 589 | 681 | ||
| 590 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 682 | void IStorage::Open(Kernel::HLERequestContext& ctx) { |
| 591 | public: | 683 | LOG_DEBUG(Service_AM, "called"); |
| 592 | explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { | 684 | |
| 593 | // clang-format off | 685 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 686 | |||
| 687 | rb.Push(RESULT_SUCCESS); | ||
| 688 | rb.PushIpcInterface<IStorageAccessor>(*this); | ||
| 689 | } | ||
| 690 | |||
| 691 | IStorageAccessor::IStorageAccessor(IStorage& storage) | ||
| 692 | : ServiceFramework("IStorageAccessor"), backing(storage) { | ||
| 693 | // clang-format off | ||
| 594 | static const FunctionInfo functions[] = { | 694 | static const FunctionInfo functions[] = { |
| 595 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | 695 | {0, &IStorageAccessor::GetSize, "GetSize"}, |
| 596 | {1, nullptr, "IsCompleted"}, | 696 | {10, &IStorageAccessor::Write, "Write"}, |
| 597 | {10, &ILibraryAppletAccessor::Start, "Start"}, | 697 | {11, &IStorageAccessor::Read, "Read"}, |
| 598 | {20, nullptr, "RequestExit"}, | ||
| 599 | {25, nullptr, "Terminate"}, | ||
| 600 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, | ||
| 601 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, | ||
| 602 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, | ||
| 603 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, | ||
| 604 | {102, nullptr, "PushExtraStorage"}, | ||
| 605 | {103, nullptr, "PushInteractiveInData"}, | ||
| 606 | {104, nullptr, "PopInteractiveOutData"}, | ||
| 607 | {105, nullptr, "GetPopOutDataEvent"}, | ||
| 608 | {106, nullptr, "GetPopInteractiveOutDataEvent"}, | ||
| 609 | {110, nullptr, "NeedsToExitProcess"}, | ||
| 610 | {120, nullptr, "GetLibraryAppletInfo"}, | ||
| 611 | {150, nullptr, "RequestForAppletToGetForeground"}, | ||
| 612 | {160, nullptr, "GetIndirectLayerConsumerHandle"}, | ||
| 613 | }; | 698 | }; |
| 614 | // clang-format on | 699 | // clang-format on |
| 615 | 700 | ||
| 616 | RegisterHandlers(functions); | 701 | RegisterHandlers(functions); |
| 702 | } | ||
| 617 | 703 | ||
| 618 | auto& kernel = Core::System::GetInstance().Kernel(); | 704 | IStorageAccessor::~IStorageAccessor() = default; |
| 619 | state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 620 | "ILibraryAppletAccessor:StateChangedEvent"); | ||
| 621 | } | ||
| 622 | 705 | ||
| 623 | private: | 706 | void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { |
| 624 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { | 707 | LOG_DEBUG(Service_AM, "called"); |
| 625 | state_changed_event->Signal(); | ||
| 626 | 708 | ||
| 627 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 709 | IPC::ResponseBuilder rb{ctx, 4}; |
| 628 | rb.Push(RESULT_SUCCESS); | ||
| 629 | rb.PushCopyObjects(state_changed_event); | ||
| 630 | 710 | ||
| 631 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 711 | rb.Push(RESULT_SUCCESS); |
| 632 | } | 712 | rb.Push(static_cast<u64>(backing.buffer.size())); |
| 713 | } | ||
| 633 | 714 | ||
| 634 | void GetResult(Kernel::HLERequestContext& ctx) { | 715 | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { |
| 635 | IPC::ResponseBuilder rb{ctx, 2}; | 716 | IPC::RequestParser rp{ctx}; |
| 636 | rb.Push(RESULT_SUCCESS); | ||
| 637 | 717 | ||
| 638 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 718 | const u64 offset{rp.Pop<u64>()}; |
| 639 | } | 719 | LOG_DEBUG(Service_AM, "called, offset={}", offset); |
| 640 | 720 | ||
| 641 | void Start(Kernel::HLERequestContext& ctx) { | 721 | const std::vector<u8> data{ctx.ReadBuffer()}; |
| 642 | IPC::ResponseBuilder rb{ctx, 2}; | 722 | |
| 643 | rb.Push(RESULT_SUCCESS); | 723 | if (data.size() > backing.buffer.size() - offset) { |
| 724 | LOG_ERROR(Service_AM, | ||
| 725 | "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", | ||
| 726 | backing.buffer.size(), data.size(), offset); | ||
| 644 | 727 | ||
| 645 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 728 | IPC::ResponseBuilder rb{ctx, 2}; |
| 729 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||
| 646 | } | 730 | } |
| 647 | 731 | ||
| 648 | void PushInData(Kernel::HLERequestContext& ctx) { | 732 | std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); |
| 649 | IPC::RequestParser rp{ctx}; | ||
| 650 | storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); | ||
| 651 | 733 | ||
| 652 | IPC::ResponseBuilder rb{ctx, 2}; | 734 | IPC::ResponseBuilder rb{ctx, 2}; |
| 653 | rb.Push(RESULT_SUCCESS); | 735 | rb.Push(RESULT_SUCCESS); |
| 736 | } | ||
| 654 | 737 | ||
| 655 | LOG_DEBUG(Service_AM, "called"); | 738 | void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { |
| 656 | } | 739 | IPC::RequestParser rp{ctx}; |
| 657 | 740 | ||
| 658 | void PopOutData(Kernel::HLERequestContext& ctx) { | 741 | const u64 offset{rp.Pop<u64>()}; |
| 659 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 742 | LOG_DEBUG(Service_AM, "called, offset={}", offset); |
| 660 | rb.Push(RESULT_SUCCESS); | ||
| 661 | rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top())); | ||
| 662 | 743 | ||
| 663 | storage_stack.pop(); | 744 | const std::size_t size{ctx.GetWriteBufferSize()}; |
| 664 | 745 | ||
| 665 | LOG_DEBUG(Service_AM, "called"); | 746 | if (size > backing.buffer.size() - offset) { |
| 747 | LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", | ||
| 748 | backing.buffer.size(), size, offset); | ||
| 749 | |||
| 750 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 751 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||
| 666 | } | 752 | } |
| 667 | 753 | ||
| 668 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; | 754 | ctx.WriteBuffer(backing.buffer.data() + offset, size); |
| 669 | Kernel::SharedPtr<Kernel::Event> state_changed_event; | 755 | |
| 670 | }; | 756 | IPC::ResponseBuilder rb{ctx, 2}; |
| 757 | rb.Push(RESULT_SUCCESS); | ||
| 758 | } | ||
| 671 | 759 | ||
| 672 | ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { | 760 | ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { |
| 673 | static const FunctionInfo functions[] = { | 761 | static const FunctionInfo functions[] = { |
| @@ -675,7 +763,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple | |||
| 675 | {1, nullptr, "TerminateAllLibraryApplets"}, | 763 | {1, nullptr, "TerminateAllLibraryApplets"}, |
| 676 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, | 764 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, |
| 677 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, | 765 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, |
| 678 | {11, nullptr, "CreateTransferMemoryStorage"}, | 766 | {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, |
| 679 | {12, nullptr, "CreateHandleStorage"}, | 767 | {12, nullptr, "CreateHandleStorage"}, |
| 680 | }; | 768 | }; |
| 681 | RegisterHandlers(functions); | 769 | RegisterHandlers(functions); |
| @@ -683,25 +771,79 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple | |||
| 683 | 771 | ||
| 684 | ILibraryAppletCreator::~ILibraryAppletCreator() = default; | 772 | ILibraryAppletCreator::~ILibraryAppletCreator() = default; |
| 685 | 773 | ||
| 774 | static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { | ||
| 775 | switch (id) { | ||
| 776 | case AppletId::SoftwareKeyboard: | ||
| 777 | return std::make_shared<Applets::SoftwareKeyboard>(); | ||
| 778 | default: | ||
| 779 | LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", | ||
| 780 | static_cast<u32>(id)); | ||
| 781 | return std::make_shared<Applets::StubApplet>(); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 686 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { | 785 | void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { |
| 786 | IPC::RequestParser rp{ctx}; | ||
| 787 | const auto applet_id = rp.PopRaw<AppletId>(); | ||
| 788 | const auto applet_mode = rp.PopRaw<u32>(); | ||
| 789 | |||
| 790 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", | ||
| 791 | static_cast<u32>(applet_id), applet_mode); | ||
| 792 | |||
| 793 | const auto applet = GetAppletFromId(applet_id); | ||
| 794 | |||
| 795 | if (applet == nullptr) { | ||
| 796 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); | ||
| 797 | |||
| 798 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 799 | rb.Push(ResultCode(-1)); | ||
| 800 | return; | ||
| 801 | } | ||
| 802 | |||
| 687 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 803 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 688 | 804 | ||
| 689 | rb.Push(RESULT_SUCCESS); | 805 | rb.Push(RESULT_SUCCESS); |
| 690 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); | 806 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet); |
| 691 | |||
| 692 | LOG_DEBUG(Service_AM, "called"); | ||
| 693 | } | 807 | } |
| 694 | 808 | ||
| 695 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 809 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| 696 | IPC::RequestParser rp{ctx}; | 810 | IPC::RequestParser rp{ctx}; |
| 697 | const u64 size{rp.Pop<u64>()}; | 811 | const u64 size{rp.Pop<u64>()}; |
| 812 | LOG_DEBUG(Service_AM, "called, size={}", size); | ||
| 813 | |||
| 698 | std::vector<u8> buffer(size); | 814 | std::vector<u8> buffer(size); |
| 699 | 815 | ||
| 700 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 816 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 701 | rb.Push(RESULT_SUCCESS); | 817 | rb.Push(RESULT_SUCCESS); |
| 702 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); | 818 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); |
| 819 | } | ||
| 703 | 820 | ||
| 704 | LOG_DEBUG(Service_AM, "called, size={}", size); | 821 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { |
| 822 | LOG_DEBUG(Service_AM, "called"); | ||
| 823 | |||
| 824 | IPC::RequestParser rp{ctx}; | ||
| 825 | |||
| 826 | rp.SetCurrentOffset(3); | ||
| 827 | const auto handle{rp.Pop<Kernel::Handle>()}; | ||
| 828 | |||
| 829 | const auto shared_mem = | ||
| 830 | Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>( | ||
| 831 | handle); | ||
| 832 | |||
| 833 | if (shared_mem == nullptr) { | ||
| 834 | LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); | ||
| 835 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 836 | rb.Push(ResultCode(-1)); | ||
| 837 | return; | ||
| 838 | } | ||
| 839 | |||
| 840 | const u8* mem_begin = shared_mem->GetPointer(); | ||
| 841 | const u8* mem_end = mem_begin + shared_mem->GetSize(); | ||
| 842 | std::vector<u8> memory{mem_begin, mem_end}; | ||
| 843 | |||
| 844 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 845 | rb.Push(RESULT_SUCCESS); | ||
| 846 | rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); | ||
| 705 | } | 847 | } |
| 706 | 848 | ||
| 707 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { | 849 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { |
| @@ -733,7 +875,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF | |||
| 733 | {70, nullptr, "RequestToShutdown"}, | 875 | {70, nullptr, "RequestToShutdown"}, |
| 734 | {71, nullptr, "RequestToReboot"}, | 876 | {71, nullptr, "RequestToReboot"}, |
| 735 | {80, nullptr, "ExitAndRequestToShowThanksMessage"}, | 877 | {80, nullptr, "ExitAndRequestToShowThanksMessage"}, |
| 736 | {90, nullptr, "EnableApplicationCrashReport"}, | 878 | {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, |
| 737 | {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, | 879 | {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, |
| 738 | {101, nullptr, "SetApplicationCopyrightImage"}, | 880 | {101, nullptr, "SetApplicationCopyrightImage"}, |
| 739 | {102, nullptr, "SetApplicationCopyrightVisibility"}, | 881 | {102, nullptr, "SetApplicationCopyrightVisibility"}, |
| @@ -752,33 +894,46 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF | |||
| 752 | 894 | ||
| 753 | IApplicationFunctions::~IApplicationFunctions() = default; | 895 | IApplicationFunctions::~IApplicationFunctions() = default; |
| 754 | 896 | ||
| 897 | void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) { | ||
| 898 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 899 | |||
| 900 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 901 | rb.Push(RESULT_SUCCESS); | ||
| 902 | } | ||
| 903 | |||
| 755 | void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( | 904 | void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( |
| 756 | Kernel::HLERequestContext& ctx) { | 905 | Kernel::HLERequestContext& ctx) { |
| 906 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 907 | |||
| 757 | IPC::ResponseBuilder rb{ctx, 2}; | 908 | IPC::ResponseBuilder rb{ctx, 2}; |
| 758 | rb.Push(RESULT_SUCCESS); | 909 | rb.Push(RESULT_SUCCESS); |
| 759 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 760 | } | 910 | } |
| 761 | 911 | ||
| 762 | void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( | 912 | void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( |
| 763 | Kernel::HLERequestContext& ctx) { | 913 | Kernel::HLERequestContext& ctx) { |
| 914 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 915 | |||
| 764 | IPC::ResponseBuilder rb{ctx, 2}; | 916 | IPC::ResponseBuilder rb{ctx, 2}; |
| 765 | rb.Push(RESULT_SUCCESS); | 917 | rb.Push(RESULT_SUCCESS); |
| 766 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 767 | } | 918 | } |
| 768 | 919 | ||
| 769 | void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { | 920 | void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { |
| 921 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 922 | |||
| 770 | IPC::ResponseBuilder rb{ctx, 2}; | 923 | IPC::ResponseBuilder rb{ctx, 2}; |
| 771 | rb.Push(RESULT_SUCCESS); | 924 | rb.Push(RESULT_SUCCESS); |
| 772 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 773 | } | 925 | } |
| 774 | 926 | ||
| 775 | void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { | 927 | void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { |
| 928 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 929 | |||
| 776 | IPC::ResponseBuilder rb{ctx, 2}; | 930 | IPC::ResponseBuilder rb{ctx, 2}; |
| 777 | rb.Push(RESULT_SUCCESS); | 931 | rb.Push(RESULT_SUCCESS); |
| 778 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 779 | } | 932 | } |
| 780 | 933 | ||
| 781 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | 934 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { |
| 935 | LOG_DEBUG(Service_AM, "called"); | ||
| 936 | |||
| 782 | LaunchParameters params{}; | 937 | LaunchParameters params{}; |
| 783 | 938 | ||
| 784 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; | 939 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; |
| @@ -797,21 +952,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 797 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 952 | std::memcpy(buffer.data(), ¶ms, buffer.size()); |
| 798 | 953 | ||
| 799 | rb.PushIpcInterface<AM::IStorage>(buffer); | 954 | rb.PushIpcInterface<AM::IStorage>(buffer); |
| 800 | |||
| 801 | LOG_DEBUG(Service_AM, "called"); | ||
| 802 | } | 955 | } |
| 803 | 956 | ||
| 804 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( | 957 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( |
| 805 | Kernel::HLERequestContext& ctx) { | 958 | Kernel::HLERequestContext& ctx) { |
| 959 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 960 | |||
| 806 | IPC::ResponseBuilder rb{ctx, 2}; | 961 | IPC::ResponseBuilder rb{ctx, 2}; |
| 807 | rb.Push(RESULT_SUCCESS); | 962 | rb.Push(RESULT_SUCCESS); |
| 808 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 809 | } | 963 | } |
| 810 | 964 | ||
| 811 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | 965 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { |
| 812 | IPC::RequestParser rp{ctx}; | 966 | IPC::RequestParser rp{ctx}; |
| 813 | u128 uid = rp.PopRaw<u128>(); // What does this do? | 967 | u128 uid = rp.PopRaw<u128>(); // What does this do? |
| 814 | |||
| 815 | LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); | 968 | LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); |
| 816 | 969 | ||
| 817 | IPC::ResponseBuilder rb{ctx, 4}; | 970 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -821,71 +974,74 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | |||
| 821 | 974 | ||
| 822 | void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { | 975 | void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { |
| 823 | // Takes an input u32 Result, no output. | 976 | // Takes an input u32 Result, no output. |
| 824 | // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. | 977 | // For example, in some cases official apps use this with error 0x2A2 then |
| 978 | // uses svcBreak. | ||
| 825 | 979 | ||
| 826 | IPC::RequestParser rp{ctx}; | 980 | IPC::RequestParser rp{ctx}; |
| 827 | u32 result = rp.Pop<u32>(); | 981 | u32 result = rp.Pop<u32>(); |
| 982 | LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); | ||
| 828 | 983 | ||
| 829 | IPC::ResponseBuilder rb{ctx, 2}; | 984 | IPC::ResponseBuilder rb{ctx, 2}; |
| 830 | rb.Push(RESULT_SUCCESS); | 985 | rb.Push(RESULT_SUCCESS); |
| 831 | |||
| 832 | LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); | ||
| 833 | } | 986 | } |
| 834 | 987 | ||
| 835 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | 988 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { |
| 989 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 990 | |||
| 836 | IPC::ResponseBuilder rb{ctx, 6}; | 991 | IPC::ResponseBuilder rb{ctx, 6}; |
| 837 | rb.Push(RESULT_SUCCESS); | 992 | rb.Push(RESULT_SUCCESS); |
| 838 | rb.Push<u64>(1); | 993 | rb.Push<u64>(1); |
| 839 | rb.Push<u64>(0); | 994 | rb.Push<u64>(0); |
| 840 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 841 | } | 995 | } |
| 842 | 996 | ||
| 843 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | 997 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { |
| 844 | // TODO(bunnei): This should be configurable | 998 | // TODO(bunnei): This should be configurable |
| 999 | LOG_DEBUG(Service_AM, "called"); | ||
| 1000 | |||
| 845 | IPC::ResponseBuilder rb{ctx, 4}; | 1001 | IPC::ResponseBuilder rb{ctx, 4}; |
| 846 | rb.Push(RESULT_SUCCESS); | 1002 | rb.Push(RESULT_SUCCESS); |
| 847 | rb.Push( | 1003 | rb.Push( |
| 848 | static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); | 1004 | static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); |
| 849 | LOG_DEBUG(Service_AM, "called"); | ||
| 850 | } | 1005 | } |
| 851 | 1006 | ||
| 852 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { | 1007 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { |
| 1008 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1009 | |||
| 853 | IPC::ResponseBuilder rb{ctx, 2}; | 1010 | IPC::ResponseBuilder rb{ctx, 2}; |
| 854 | rb.Push(RESULT_SUCCESS); | 1011 | rb.Push(RESULT_SUCCESS); |
| 855 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 856 | } | 1012 | } |
| 857 | 1013 | ||
| 858 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { | 1014 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { |
| 1015 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1016 | |||
| 859 | IPC::ResponseBuilder rb{ctx, 2}; | 1017 | IPC::ResponseBuilder rb{ctx, 2}; |
| 860 | rb.Push(RESULT_SUCCESS); | 1018 | rb.Push(RESULT_SUCCESS); |
| 861 | |||
| 862 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 863 | } | 1019 | } |
| 864 | 1020 | ||
| 865 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { | 1021 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { |
| 1022 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1023 | |||
| 866 | IPC::ResponseBuilder rb{ctx, 3}; | 1024 | IPC::ResponseBuilder rb{ctx, 3}; |
| 867 | rb.Push(RESULT_SUCCESS); | 1025 | rb.Push(RESULT_SUCCESS); |
| 868 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes | 1026 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes |
| 869 | |||
| 870 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 871 | } | 1027 | } |
| 872 | 1028 | ||
| 873 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { | 1029 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { |
| 1030 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1031 | |||
| 874 | IPC::ResponseBuilder rb{ctx, 6}; | 1032 | IPC::ResponseBuilder rb{ctx, 6}; |
| 875 | rb.Push(RESULT_SUCCESS); | 1033 | rb.Push(RESULT_SUCCESS); |
| 876 | 1034 | ||
| 877 | // Returns a 128-bit UUID | 1035 | // Returns a 128-bit UUID |
| 878 | rb.Push<u64>(0); | 1036 | rb.Push<u64>(0); |
| 879 | rb.Push<u64>(0); | 1037 | rb.Push<u64>(0); |
| 880 | |||
| 881 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 882 | } | 1038 | } |
| 883 | 1039 | ||
| 884 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1040 | void InstallInterfaces(SM::ServiceManager& service_manager, |
| 885 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { | 1041 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { |
| 886 | auto message_queue = std::make_shared<AppletMessageQueue>(); | 1042 | auto message_queue = std::make_shared<AppletMessageQueue>(); |
| 887 | message_queue->PushMessage( | 1043 | message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on |
| 888 | AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot | 1044 | // game boot |
| 889 | 1045 | ||
| 890 | std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); | 1046 | std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); |
| 891 | std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); | 1047 | std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); |
| @@ -915,9 +1071,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" | |||
| 915 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; | 1071 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; |
| 916 | 1072 | ||
| 917 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { | 1073 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { |
| 1074 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1075 | |||
| 918 | IPC::ResponseBuilder rb{ctx, 2}; | 1076 | IPC::ResponseBuilder rb{ctx, 2}; |
| 919 | rb.Push(RESULT_SUCCESS); | 1077 | rb.Push(RESULT_SUCCESS); |
| 920 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 921 | } | 1078 | } |
| 922 | 1079 | ||
| 923 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { | 1080 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 2f1c20bce..34c45fadf 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -6,12 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <queue> | 8 | #include <queue> |
| 9 | #include "core/hle/kernel/writable_event.h" | ||
| 9 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| 10 | 11 | ||
| 11 | namespace Kernel { | ||
| 12 | class Event; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service { | 12 | namespace Service { |
| 16 | namespace NVFlinger { | 13 | namespace NVFlinger { |
| 17 | class NVFlinger; | 14 | class NVFlinger; |
| @@ -52,8 +49,8 @@ public: | |||
| 52 | AppletMessageQueue(); | 49 | AppletMessageQueue(); |
| 53 | ~AppletMessageQueue(); | 50 | ~AppletMessageQueue(); |
| 54 | 51 | ||
| 55 | const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; | 52 | const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; |
| 56 | const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; | 53 | const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; |
| 57 | void PushMessage(AppletMessage msg); | 54 | void PushMessage(AppletMessage msg); |
| 58 | AppletMessage PopMessage(); | 55 | AppletMessage PopMessage(); |
| 59 | std::size_t GetMessageCount() const; | 56 | std::size_t GetMessageCount() const; |
| @@ -61,8 +58,8 @@ public: | |||
| 61 | 58 | ||
| 62 | private: | 59 | private: |
| 63 | std::queue<AppletMessage> messages; | 60 | std::queue<AppletMessage> messages; |
| 64 | Kernel::SharedPtr<Kernel::Event> on_new_message; | 61 | Kernel::EventPair on_new_message; |
| 65 | Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; | 62 | Kernel::EventPair on_operation_mode_changed; |
| 66 | }; | 63 | }; |
| 67 | 64 | ||
| 68 | class IWindowController final : public ServiceFramework<IWindowController> { | 65 | class IWindowController final : public ServiceFramework<IWindowController> { |
| @@ -122,7 +119,7 @@ private: | |||
| 122 | void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); | 119 | void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); |
| 123 | 120 | ||
| 124 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 121 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 125 | Kernel::SharedPtr<Kernel::Event> launchable_event; | 122 | Kernel::EventPair launchable_event; |
| 126 | u32 idle_time_detection_extension = 0; | 123 | u32 idle_time_detection_extension = 0; |
| 127 | }; | 124 | }; |
| 128 | 125 | ||
| @@ -151,10 +148,37 @@ private: | |||
| 151 | void GetBootMode(Kernel::HLERequestContext& ctx); | 148 | void GetBootMode(Kernel::HLERequestContext& ctx); |
| 152 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); | 149 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); |
| 153 | 150 | ||
| 154 | Kernel::SharedPtr<Kernel::Event> event; | ||
| 155 | std::shared_ptr<AppletMessageQueue> msg_queue; | 151 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 156 | }; | 152 | }; |
| 157 | 153 | ||
| 154 | class IStorage final : public ServiceFramework<IStorage> { | ||
| 155 | public: | ||
| 156 | explicit IStorage(std::vector<u8> buffer); | ||
| 157 | ~IStorage() override; | ||
| 158 | |||
| 159 | const std::vector<u8>& GetData() const; | ||
| 160 | |||
| 161 | private: | ||
| 162 | void Open(Kernel::HLERequestContext& ctx); | ||
| 163 | |||
| 164 | std::vector<u8> buffer; | ||
| 165 | |||
| 166 | friend class IStorageAccessor; | ||
| 167 | }; | ||
| 168 | |||
| 169 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | ||
| 170 | public: | ||
| 171 | explicit IStorageAccessor(IStorage& backing); | ||
| 172 | ~IStorageAccessor() override; | ||
| 173 | |||
| 174 | private: | ||
| 175 | void GetSize(Kernel::HLERequestContext& ctx); | ||
| 176 | void Write(Kernel::HLERequestContext& ctx); | ||
| 177 | void Read(Kernel::HLERequestContext& ctx); | ||
| 178 | |||
| 179 | IStorage& backing; | ||
| 180 | }; | ||
| 181 | |||
| 158 | class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { | 182 | class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { |
| 159 | public: | 183 | public: |
| 160 | ILibraryAppletCreator(); | 184 | ILibraryAppletCreator(); |
| @@ -163,6 +187,7 @@ public: | |||
| 163 | private: | 187 | private: |
| 164 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); | 188 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); |
| 165 | void CreateStorage(Kernel::HLERequestContext& ctx); | 189 | void CreateStorage(Kernel::HLERequestContext& ctx); |
| 190 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); | ||
| 166 | }; | 191 | }; |
| 167 | 192 | ||
| 168 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | 193 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { |
| @@ -185,6 +210,7 @@ private: | |||
| 185 | void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); | 210 | void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); |
| 186 | void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); | 211 | void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); |
| 187 | void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); | 212 | void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); |
| 213 | void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); | ||
| 188 | }; | 214 | }; |
| 189 | 215 | ||
| 190 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { | 216 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index ec93e3529..41a573a91 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -32,66 +32,75 @@ public: | |||
| 32 | 32 | ||
| 33 | private: | 33 | private: |
| 34 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 34 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 35 | LOG_DEBUG(Service_AM, "called"); | ||
| 36 | |||
| 35 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 37 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 36 | rb.Push(RESULT_SUCCESS); | 38 | rb.Push(RESULT_SUCCESS); |
| 37 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 39 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 38 | LOG_DEBUG(Service_AM, "called"); | ||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 42 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 43 | LOG_DEBUG(Service_AM, "called"); | ||
| 44 | |||
| 42 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 43 | rb.Push(RESULT_SUCCESS); | 46 | rb.Push(RESULT_SUCCESS); |
| 44 | rb.PushIpcInterface<ISelfController>(nvflinger); | 47 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 45 | LOG_DEBUG(Service_AM, "called"); | ||
| 46 | } | 48 | } |
| 47 | 49 | ||
| 48 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 50 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 51 | LOG_DEBUG(Service_AM, "called"); | ||
| 52 | |||
| 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 53 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 50 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 51 | rb.PushIpcInterface<IWindowController>(); | 55 | rb.PushIpcInterface<IWindowController>(); |
| 52 | LOG_DEBUG(Service_AM, "called"); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 58 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 59 | LOG_DEBUG(Service_AM, "called"); | ||
| 60 | |||
| 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 57 | rb.Push(RESULT_SUCCESS); | 62 | rb.Push(RESULT_SUCCESS); |
| 58 | rb.PushIpcInterface<IAudioController>(); | 63 | rb.PushIpcInterface<IAudioController>(); |
| 59 | LOG_DEBUG(Service_AM, "called"); | ||
| 60 | } | 64 | } |
| 61 | 65 | ||
| 62 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 66 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 67 | LOG_DEBUG(Service_AM, "called"); | ||
| 68 | |||
| 63 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 69 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 64 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 65 | rb.PushIpcInterface<IDisplayController>(); | 71 | rb.PushIpcInterface<IDisplayController>(); |
| 66 | LOG_DEBUG(Service_AM, "called"); | ||
| 67 | } | 72 | } |
| 68 | 73 | ||
| 69 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { | 74 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { |
| 75 | LOG_DEBUG(Service_AM, "called"); | ||
| 76 | |||
| 70 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 77 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 71 | rb.Push(RESULT_SUCCESS); | 78 | rb.Push(RESULT_SUCCESS); |
| 72 | rb.PushIpcInterface<IProcessWindingController>(); | 79 | rb.PushIpcInterface<IProcessWindingController>(); |
| 73 | LOG_DEBUG(Service_AM, "called"); | ||
| 74 | } | 80 | } |
| 75 | 81 | ||
| 76 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 82 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_DEBUG(Service_AM, "called"); | ||
| 84 | |||
| 77 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 85 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 78 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| 79 | rb.PushIpcInterface<IDebugFunctions>(); | 87 | rb.PushIpcInterface<IDebugFunctions>(); |
| 80 | LOG_DEBUG(Service_AM, "called"); | ||
| 81 | } | 88 | } |
| 82 | 89 | ||
| 83 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 90 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_DEBUG(Service_AM, "called"); | ||
| 92 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 93 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 85 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 86 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 95 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 87 | LOG_DEBUG(Service_AM, "called"); | ||
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 98 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 99 | LOG_DEBUG(Service_AM, "called"); | ||
| 100 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 92 | rb.Push(RESULT_SUCCESS); | 102 | rb.Push(RESULT_SUCCESS); |
| 93 | rb.PushIpcInterface<IApplicationFunctions>(); | 103 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 94 | LOG_DEBUG(Service_AM, "called"); | ||
| 95 | } | 104 | } |
| 96 | 105 | ||
| 97 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 106 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -122,97 +131,110 @@ public: | |||
| 122 | 131 | ||
| 123 | private: | 132 | private: |
| 124 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 133 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 134 | LOG_DEBUG(Service_AM, "called"); | ||
| 135 | |||
| 125 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 136 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 126 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 127 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 138 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 128 | LOG_DEBUG(Service_AM, "called"); | ||
| 129 | } | 139 | } |
| 130 | 140 | ||
| 131 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 141 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 142 | LOG_DEBUG(Service_AM, "called"); | ||
| 143 | |||
| 132 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 144 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 133 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 134 | rb.PushIpcInterface<ISelfController>(nvflinger); | 146 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 135 | LOG_DEBUG(Service_AM, "called"); | ||
| 136 | } | 147 | } |
| 137 | 148 | ||
| 138 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 149 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 150 | LOG_DEBUG(Service_AM, "called"); | ||
| 151 | |||
| 139 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 152 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 140 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| 141 | rb.PushIpcInterface<IWindowController>(); | 154 | rb.PushIpcInterface<IWindowController>(); |
| 142 | LOG_DEBUG(Service_AM, "called"); | ||
| 143 | } | 155 | } |
| 144 | 156 | ||
| 145 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 157 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 158 | LOG_DEBUG(Service_AM, "called"); | ||
| 159 | |||
| 146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 160 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 147 | rb.Push(RESULT_SUCCESS); | 161 | rb.Push(RESULT_SUCCESS); |
| 148 | rb.PushIpcInterface<IAudioController>(); | 162 | rb.PushIpcInterface<IAudioController>(); |
| 149 | LOG_DEBUG(Service_AM, "called"); | ||
| 150 | } | 163 | } |
| 151 | 164 | ||
| 152 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 165 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 166 | LOG_DEBUG(Service_AM, "called"); | ||
| 167 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 168 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 154 | rb.Push(RESULT_SUCCESS); | 169 | rb.Push(RESULT_SUCCESS); |
| 155 | rb.PushIpcInterface<IDisplayController>(); | 170 | rb.PushIpcInterface<IDisplayController>(); |
| 156 | LOG_DEBUG(Service_AM, "called"); | ||
| 157 | } | 171 | } |
| 158 | 172 | ||
| 159 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 173 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 174 | LOG_DEBUG(Service_AM, "called"); | ||
| 175 | |||
| 160 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 161 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 162 | rb.PushIpcInterface<IDebugFunctions>(); | 178 | rb.PushIpcInterface<IDebugFunctions>(); |
| 163 | LOG_DEBUG(Service_AM, "called"); | ||
| 164 | } | 179 | } |
| 165 | 180 | ||
| 166 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 181 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 182 | LOG_DEBUG(Service_AM, "called"); | ||
| 183 | |||
| 167 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 184 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 168 | rb.Push(RESULT_SUCCESS); | 185 | rb.Push(RESULT_SUCCESS); |
| 169 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 186 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 170 | LOG_DEBUG(Service_AM, "called"); | ||
| 171 | } | 187 | } |
| 172 | 188 | ||
| 173 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { | 189 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { |
| 190 | LOG_DEBUG(Service_AM, "called"); | ||
| 191 | |||
| 174 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 192 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 175 | rb.Push(RESULT_SUCCESS); | 193 | rb.Push(RESULT_SUCCESS); |
| 176 | rb.PushIpcInterface<IHomeMenuFunctions>(); | 194 | rb.PushIpcInterface<IHomeMenuFunctions>(); |
| 177 | LOG_DEBUG(Service_AM, "called"); | ||
| 178 | } | 195 | } |
| 179 | 196 | ||
| 180 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { | 197 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { |
| 198 | LOG_DEBUG(Service_AM, "called"); | ||
| 199 | |||
| 181 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 200 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 182 | rb.Push(RESULT_SUCCESS); | 201 | rb.Push(RESULT_SUCCESS); |
| 183 | rb.PushIpcInterface<IGlobalStateController>(); | 202 | rb.PushIpcInterface<IGlobalStateController>(); |
| 184 | LOG_DEBUG(Service_AM, "called"); | ||
| 185 | } | 203 | } |
| 186 | 204 | ||
| 187 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { | 205 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { |
| 206 | LOG_DEBUG(Service_AM, "called"); | ||
| 207 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 208 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 189 | rb.Push(RESULT_SUCCESS); | 209 | rb.Push(RESULT_SUCCESS); |
| 190 | rb.PushIpcInterface<IApplicationCreator>(); | 210 | rb.PushIpcInterface<IApplicationCreator>(); |
| 191 | LOG_DEBUG(Service_AM, "called"); | ||
| 192 | } | 211 | } |
| 193 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 212 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 194 | std::shared_ptr<AppletMessageQueue> msg_queue; | 213 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 195 | }; | 214 | }; |
| 196 | 215 | ||
| 197 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { | 216 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { |
| 217 | LOG_DEBUG(Service_AM, "called"); | ||
| 218 | |||
| 198 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 199 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 200 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); | 221 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); |
| 201 | LOG_DEBUG(Service_AM, "called"); | ||
| 202 | } | 222 | } |
| 203 | 223 | ||
| 204 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { | 224 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { |
| 225 | LOG_DEBUG(Service_AM, "called"); | ||
| 226 | |||
| 205 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 227 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 206 | rb.Push(RESULT_SUCCESS); | 228 | rb.Push(RESULT_SUCCESS); |
| 207 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); | 229 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); |
| 208 | LOG_DEBUG(Service_AM, "called"); | ||
| 209 | } | 230 | } |
| 210 | 231 | ||
| 211 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { | 232 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { |
| 233 | LOG_DEBUG(Service_AM, "called"); | ||
| 234 | |||
| 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 235 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 213 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| 214 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); | 237 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); |
| 215 | LOG_DEBUG(Service_AM, "called"); | ||
| 216 | } | 238 | } |
| 217 | 239 | ||
| 218 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 240 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 20c8d5fff..d3a0a1568 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp | |||
| @@ -35,59 +35,67 @@ public: | |||
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 37 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 38 | LOG_DEBUG(Service_AM, "called"); | ||
| 39 | |||
| 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 39 | rb.Push(RESULT_SUCCESS); | 41 | rb.Push(RESULT_SUCCESS); |
| 40 | rb.PushIpcInterface<IAudioController>(); | 42 | rb.PushIpcInterface<IAudioController>(); |
| 41 | LOG_DEBUG(Service_AM, "called"); | ||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 45 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_DEBUG(Service_AM, "called"); | ||
| 47 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 46 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.PushIpcInterface<IDisplayController>(); | 50 | rb.PushIpcInterface<IDisplayController>(); |
| 48 | LOG_DEBUG(Service_AM, "called"); | ||
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 53 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 54 | LOG_DEBUG(Service_AM, "called"); | ||
| 55 | |||
| 52 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 53 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 54 | rb.PushIpcInterface<IDebugFunctions>(); | 58 | rb.PushIpcInterface<IDebugFunctions>(); |
| 55 | LOG_DEBUG(Service_AM, "called"); | ||
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 61 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 62 | LOG_DEBUG(Service_AM, "called"); | ||
| 63 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 60 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 61 | rb.PushIpcInterface<IWindowController>(); | 66 | rb.PushIpcInterface<IWindowController>(); |
| 62 | LOG_DEBUG(Service_AM, "called"); | ||
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 69 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_DEBUG(Service_AM, "called"); | ||
| 71 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 72 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 67 | rb.Push(RESULT_SUCCESS); | 73 | rb.Push(RESULT_SUCCESS); |
| 68 | rb.PushIpcInterface<ISelfController>(nvflinger); | 74 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 69 | LOG_DEBUG(Service_AM, "called"); | ||
| 70 | } | 75 | } |
| 71 | 76 | ||
| 72 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 77 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 78 | LOG_DEBUG(Service_AM, "called"); | ||
| 79 | |||
| 73 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 80 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 74 | rb.Push(RESULT_SUCCESS); | 81 | rb.Push(RESULT_SUCCESS); |
| 75 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 82 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 76 | LOG_DEBUG(Service_AM, "called"); | ||
| 77 | } | 83 | } |
| 78 | 84 | ||
| 79 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 85 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_DEBUG(Service_AM, "called"); | ||
| 87 | |||
| 80 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 88 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 81 | rb.Push(RESULT_SUCCESS); | 89 | rb.Push(RESULT_SUCCESS); |
| 82 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 90 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 83 | LOG_DEBUG(Service_AM, "called"); | ||
| 84 | } | 91 | } |
| 85 | 92 | ||
| 86 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 93 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_AM, "called"); | ||
| 95 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 88 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.PushIpcInterface<IApplicationFunctions>(); | 98 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 90 | LOG_DEBUG(Service_AM, "called"); | ||
| 91 | } | 99 | } |
| 92 | 100 | ||
| 93 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 101 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -95,10 +103,11 @@ private: | |||
| 95 | }; | 103 | }; |
| 96 | 104 | ||
| 97 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | 105 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_DEBUG(Service_AM, "called"); | ||
| 107 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 108 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 99 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 100 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); | 110 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); |
| 101 | LOG_DEBUG(Service_AM, "called"); | ||
| 102 | } | 111 | } |
| 103 | 112 | ||
| 104 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 113 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp new file mode 100644 index 000000000..47da35537 --- /dev/null +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/hle/kernel/readable_event.h" | ||
| 9 | #include "core/hle/kernel/server_port.h" | ||
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 11 | #include "core/hle/service/am/am.h" | ||
| 12 | #include "core/hle/service/am/applets/applets.h" | ||
| 13 | |||
| 14 | namespace Service::AM::Applets { | ||
| 15 | |||
| 16 | AppletDataBroker::AppletDataBroker() { | ||
| 17 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 18 | state_changed_event = Kernel::WritableEvent::CreateEventPair( | ||
| 19 | kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent"); | ||
| 20 | pop_out_data_event = Kernel::WritableEvent::CreateEventPair( | ||
| 21 | kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent"); | ||
| 22 | pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( | ||
| 23 | kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | ||
| 24 | } | ||
| 25 | |||
| 26 | AppletDataBroker::~AppletDataBroker() = default; | ||
| 27 | |||
| 28 | std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { | ||
| 29 | if (out_channel.empty()) | ||
| 30 | return nullptr; | ||
| 31 | |||
| 32 | auto out = std::move(out_channel.front()); | ||
| 33 | out_channel.pop(); | ||
| 34 | return out; | ||
| 35 | } | ||
| 36 | |||
| 37 | std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { | ||
| 38 | if (in_channel.empty()) | ||
| 39 | return nullptr; | ||
| 40 | |||
| 41 | auto out = std::move(in_channel.front()); | ||
| 42 | in_channel.pop(); | ||
| 43 | return out; | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { | ||
| 47 | if (out_interactive_channel.empty()) | ||
| 48 | return nullptr; | ||
| 49 | |||
| 50 | auto out = std::move(out_interactive_channel.front()); | ||
| 51 | out_interactive_channel.pop(); | ||
| 52 | return out; | ||
| 53 | } | ||
| 54 | |||
| 55 | std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { | ||
| 56 | if (in_interactive_channel.empty()) | ||
| 57 | return nullptr; | ||
| 58 | |||
| 59 | auto out = std::move(in_interactive_channel.front()); | ||
| 60 | in_interactive_channel.pop(); | ||
| 61 | return out; | ||
| 62 | } | ||
| 63 | |||
| 64 | void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { | ||
| 65 | in_channel.push(std::make_unique<IStorage>(storage)); | ||
| 66 | } | ||
| 67 | |||
| 68 | void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { | ||
| 69 | out_channel.push(std::make_unique<IStorage>(storage)); | ||
| 70 | pop_out_data_event.writable->Signal(); | ||
| 71 | } | ||
| 72 | |||
| 73 | void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { | ||
| 74 | in_interactive_channel.push(std::make_unique<IStorage>(storage)); | ||
| 75 | } | ||
| 76 | |||
| 77 | void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { | ||
| 78 | out_interactive_channel.push(std::make_unique<IStorage>(storage)); | ||
| 79 | pop_interactive_out_data_event.writable->Signal(); | ||
| 80 | } | ||
| 81 | |||
| 82 | void AppletDataBroker::SignalStateChanged() const { | ||
| 83 | state_changed_event.writable->Signal(); | ||
| 84 | } | ||
| 85 | |||
| 86 | Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { | ||
| 87 | return pop_out_data_event.readable; | ||
| 88 | } | ||
| 89 | |||
| 90 | Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { | ||
| 91 | return pop_interactive_out_data_event.readable; | ||
| 92 | } | ||
| 93 | |||
| 94 | Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { | ||
| 95 | return state_changed_event.readable; | ||
| 96 | } | ||
| 97 | |||
| 98 | Applet::Applet() = default; | ||
| 99 | |||
| 100 | Applet::~Applet() = default; | ||
| 101 | |||
| 102 | void Applet::Initialize() { | ||
| 103 | const auto common = broker.PopNormalDataToApplet(); | ||
| 104 | ASSERT(common != nullptr); | ||
| 105 | |||
| 106 | const auto common_data = common->GetData(); | ||
| 107 | |||
| 108 | ASSERT(common_data.size() >= sizeof(CommonArguments)); | ||
| 109 | std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); | ||
| 110 | |||
| 111 | initialized = true; | ||
| 112 | } | ||
| 113 | |||
| 114 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h new file mode 100644 index 000000000..b0a8913c3 --- /dev/null +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <queue> | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 12 | |||
| 13 | union ResultCode; | ||
| 14 | |||
| 15 | namespace Service::AM { | ||
| 16 | |||
| 17 | class IStorage; | ||
| 18 | |||
| 19 | namespace Applets { | ||
| 20 | |||
| 21 | class AppletDataBroker final { | ||
| 22 | public: | ||
| 23 | AppletDataBroker(); | ||
| 24 | ~AppletDataBroker(); | ||
| 25 | |||
| 26 | std::unique_ptr<IStorage> PopNormalDataToGame(); | ||
| 27 | std::unique_ptr<IStorage> PopNormalDataToApplet(); | ||
| 28 | |||
| 29 | std::unique_ptr<IStorage> PopInteractiveDataToGame(); | ||
| 30 | std::unique_ptr<IStorage> PopInteractiveDataToApplet(); | ||
| 31 | |||
| 32 | void PushNormalDataFromGame(IStorage storage); | ||
| 33 | void PushNormalDataFromApplet(IStorage storage); | ||
| 34 | |||
| 35 | void PushInteractiveDataFromGame(IStorage storage); | ||
| 36 | void PushInteractiveDataFromApplet(IStorage storage); | ||
| 37 | |||
| 38 | void SignalStateChanged() const; | ||
| 39 | |||
| 40 | Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const; | ||
| 41 | Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const; | ||
| 42 | Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const; | ||
| 43 | |||
| 44 | private: | ||
| 45 | // Queues are named from applet's perspective | ||
| 46 | |||
| 47 | // PopNormalDataToApplet and PushNormalDataFromGame | ||
| 48 | std::queue<std::unique_ptr<IStorage>> in_channel; | ||
| 49 | |||
| 50 | // PopNormalDataToGame and PushNormalDataFromApplet | ||
| 51 | std::queue<std::unique_ptr<IStorage>> out_channel; | ||
| 52 | |||
| 53 | // PopInteractiveDataToApplet and PushInteractiveDataFromGame | ||
| 54 | std::queue<std::unique_ptr<IStorage>> in_interactive_channel; | ||
| 55 | |||
| 56 | // PopInteractiveDataToGame and PushInteractiveDataFromApplet | ||
| 57 | std::queue<std::unique_ptr<IStorage>> out_interactive_channel; | ||
| 58 | |||
| 59 | Kernel::EventPair state_changed_event; | ||
| 60 | |||
| 61 | // Signaled on PushNormalDataFromApplet | ||
| 62 | Kernel::EventPair pop_out_data_event; | ||
| 63 | |||
| 64 | // Signaled on PushInteractiveDataFromApplet | ||
| 65 | Kernel::EventPair pop_interactive_out_data_event; | ||
| 66 | }; | ||
| 67 | |||
| 68 | class Applet { | ||
| 69 | public: | ||
| 70 | Applet(); | ||
| 71 | virtual ~Applet(); | ||
| 72 | |||
| 73 | virtual void Initialize(); | ||
| 74 | |||
| 75 | virtual bool TransactionComplete() const = 0; | ||
| 76 | virtual ResultCode GetStatus() const = 0; | ||
| 77 | virtual void ExecuteInteractive() = 0; | ||
| 78 | virtual void Execute() = 0; | ||
| 79 | |||
| 80 | bool IsInitialized() const { | ||
| 81 | return initialized; | ||
| 82 | } | ||
| 83 | |||
| 84 | AppletDataBroker& GetBroker() { | ||
| 85 | return broker; | ||
| 86 | } | ||
| 87 | |||
| 88 | const AppletDataBroker& GetBroker() const { | ||
| 89 | return broker; | ||
| 90 | } | ||
| 91 | |||
| 92 | protected: | ||
| 93 | struct CommonArguments { | ||
| 94 | u32_le arguments_version; | ||
| 95 | u32_le size; | ||
| 96 | u32_le library_version; | ||
| 97 | u32_le theme_color; | ||
| 98 | u8 play_startup_sound; | ||
| 99 | u64_le system_tick; | ||
| 100 | }; | ||
| 101 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); | ||
| 102 | |||
| 103 | CommonArguments common_args{}; | ||
| 104 | AppletDataBroker broker; | ||
| 105 | bool initialized = false; | ||
| 106 | }; | ||
| 107 | |||
| 108 | } // namespace Applets | ||
| 109 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp new file mode 100644 index 000000000..981bdec51 --- /dev/null +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/frontend/applets/software_keyboard.h" | ||
| 10 | #include "core/hle/service/am/am.h" | ||
| 11 | #include "core/hle/service/am/applets/software_keyboard.h" | ||
| 12 | |||
| 13 | namespace Service::AM::Applets { | ||
| 14 | |||
| 15 | constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; | ||
| 16 | constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; | ||
| 17 | constexpr std::size_t DEFAULT_MAX_LENGTH = 500; | ||
| 18 | constexpr bool INTERACTIVE_STATUS_OK = false; | ||
| 19 | |||
| 20 | static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( | ||
| 21 | KeyboardConfig config, std::u16string initial_text) { | ||
| 22 | Core::Frontend::SoftwareKeyboardParameters params{}; | ||
| 23 | |||
| 24 | params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 25 | config.submit_text.data(), config.submit_text.size()); | ||
| 26 | params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( | ||
| 27 | config.header_text.data(), config.header_text.size()); | ||
| 28 | params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(), | ||
| 29 | config.sub_text.size()); | ||
| 30 | params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(), | ||
| 31 | config.guide_text.size()); | ||
| 32 | params.initial_text = initial_text; | ||
| 33 | params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit; | ||
| 34 | params.password = static_cast<bool>(config.is_password); | ||
| 35 | params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position); | ||
| 36 | params.value = static_cast<u8>(config.keyset_disable_bitmask); | ||
| 37 | |||
| 38 | return params; | ||
| 39 | } | ||
| 40 | |||
| 41 | SoftwareKeyboard::SoftwareKeyboard() = default; | ||
| 42 | |||
| 43 | SoftwareKeyboard::~SoftwareKeyboard() = default; | ||
| 44 | |||
| 45 | void SoftwareKeyboard::Initialize() { | ||
| 46 | complete = false; | ||
| 47 | initial_text.clear(); | ||
| 48 | final_data.clear(); | ||
| 49 | |||
| 50 | Applet::Initialize(); | ||
| 51 | |||
| 52 | const auto keyboard_config_storage = broker.PopNormalDataToApplet(); | ||
| 53 | ASSERT(keyboard_config_storage != nullptr); | ||
| 54 | const auto& keyboard_config = keyboard_config_storage->GetData(); | ||
| 55 | |||
| 56 | ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); | ||
| 57 | std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); | ||
| 58 | |||
| 59 | const auto work_buffer_storage = broker.PopNormalDataToApplet(); | ||
| 60 | ASSERT(work_buffer_storage != nullptr); | ||
| 61 | const auto& work_buffer = work_buffer_storage->GetData(); | ||
| 62 | |||
| 63 | if (config.initial_string_size == 0) | ||
| 64 | return; | ||
| 65 | |||
| 66 | std::vector<char16_t> string(config.initial_string_size); | ||
| 67 | std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset, | ||
| 68 | string.size() * 2); | ||
| 69 | initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()); | ||
| 70 | } | ||
| 71 | |||
| 72 | bool SoftwareKeyboard::TransactionComplete() const { | ||
| 73 | return complete; | ||
| 74 | } | ||
| 75 | |||
| 76 | ResultCode SoftwareKeyboard::GetStatus() const { | ||
| 77 | return RESULT_SUCCESS; | ||
| 78 | } | ||
| 79 | |||
| 80 | void SoftwareKeyboard::ExecuteInteractive() { | ||
| 81 | if (complete) | ||
| 82 | return; | ||
| 83 | |||
| 84 | const auto storage = broker.PopInteractiveDataToApplet(); | ||
| 85 | ASSERT(storage != nullptr); | ||
| 86 | const auto data = storage->GetData(); | ||
| 87 | const auto status = static_cast<bool>(data[0]); | ||
| 88 | |||
| 89 | if (status == INTERACTIVE_STATUS_OK) { | ||
| 90 | complete = true; | ||
| 91 | } else { | ||
| 92 | const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; | ||
| 93 | |||
| 94 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; | ||
| 95 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); | ||
| 96 | frontend.SendTextCheckDialog( | ||
| 97 | Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), | ||
| 98 | [this] { broker.SignalStateChanged(); }); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | void SoftwareKeyboard::Execute() { | ||
| 103 | if (complete) { | ||
| 104 | broker.PushNormalDataFromApplet(IStorage{final_data}); | ||
| 105 | return; | ||
| 106 | } | ||
| 107 | |||
| 108 | const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; | ||
| 109 | |||
| 110 | const auto parameters = ConvertToFrontendParameters(config, initial_text); | ||
| 111 | |||
| 112 | frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, | ||
| 113 | parameters); | ||
| 114 | } | ||
| 115 | |||
| 116 | void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | ||
| 117 | std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE); | ||
| 118 | |||
| 119 | if (text.has_value()) { | ||
| 120 | std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE); | ||
| 121 | |||
| 122 | if (config.utf_8) { | ||
| 123 | const u64 size = text->size() + 8; | ||
| 124 | const auto new_text = Common::UTF16ToUTF8(*text); | ||
| 125 | |||
| 126 | std::memcpy(output_sub.data(), &size, sizeof(u64)); | ||
| 127 | std::memcpy(output_sub.data() + 8, new_text.data(), | ||
| 128 | std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8)); | ||
| 129 | |||
| 130 | output_main[0] = INTERACTIVE_STATUS_OK; | ||
| 131 | std::memcpy(output_main.data() + 4, new_text.data(), | ||
| 132 | std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); | ||
| 133 | } else { | ||
| 134 | const u64 size = text->size() * 2 + 8; | ||
| 135 | std::memcpy(output_sub.data(), &size, sizeof(u64)); | ||
| 136 | std::memcpy(output_sub.data() + 8, text->data(), | ||
| 137 | std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); | ||
| 138 | |||
| 139 | output_main[0] = INTERACTIVE_STATUS_OK; | ||
| 140 | std::memcpy(output_main.data() + 4, text->data(), | ||
| 141 | std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); | ||
| 142 | } | ||
| 143 | |||
| 144 | complete = !config.text_check; | ||
| 145 | final_data = output_main; | ||
| 146 | |||
| 147 | if (complete) { | ||
| 148 | broker.PushNormalDataFromApplet(IStorage{output_main}); | ||
| 149 | } else { | ||
| 150 | broker.PushInteractiveDataFromApplet(IStorage{output_sub}); | ||
| 151 | } | ||
| 152 | |||
| 153 | broker.SignalStateChanged(); | ||
| 154 | } else { | ||
| 155 | output_main[0] = 1; | ||
| 156 | complete = true; | ||
| 157 | broker.PushNormalDataFromApplet(IStorage{output_main}); | ||
| 158 | broker.SignalStateChanged(); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h new file mode 100644 index 000000000..efd5753a1 --- /dev/null +++ b/src/core/hle/service/am/applets/software_keyboard.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <string> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_funcs.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | #include "core/hle/service/am/am.h" | ||
| 14 | #include "core/hle/service/am/applets/applets.h" | ||
| 15 | |||
| 16 | namespace Service::AM::Applets { | ||
| 17 | |||
| 18 | enum class KeysetDisable : u32 { | ||
| 19 | Space = 0x02, | ||
| 20 | Address = 0x04, | ||
| 21 | Percent = 0x08, | ||
| 22 | Slashes = 0x10, | ||
| 23 | Numbers = 0x40, | ||
| 24 | DownloadCode = 0x80, | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct KeyboardConfig { | ||
| 28 | INSERT_PADDING_BYTES(4); | ||
| 29 | std::array<char16_t, 9> submit_text; | ||
| 30 | u16_le left_symbol_key; | ||
| 31 | u16_le right_symbol_key; | ||
| 32 | INSERT_PADDING_BYTES(1); | ||
| 33 | KeysetDisable keyset_disable_bitmask; | ||
| 34 | u32_le initial_cursor_position; | ||
| 35 | std::array<char16_t, 65> header_text; | ||
| 36 | std::array<char16_t, 129> sub_text; | ||
| 37 | std::array<char16_t, 257> guide_text; | ||
| 38 | u32_le length_limit; | ||
| 39 | INSERT_PADDING_BYTES(4); | ||
| 40 | u32_le is_password; | ||
| 41 | INSERT_PADDING_BYTES(5); | ||
| 42 | bool utf_8; | ||
| 43 | bool draw_background; | ||
| 44 | u32_le initial_string_offset; | ||
| 45 | u32_le initial_string_size; | ||
| 46 | u32_le user_dictionary_offset; | ||
| 47 | u32_le user_dictionary_size; | ||
| 48 | bool text_check; | ||
| 49 | u64_le text_check_callback; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size."); | ||
| 52 | |||
| 53 | class SoftwareKeyboard final : public Applet { | ||
| 54 | public: | ||
| 55 | SoftwareKeyboard(); | ||
| 56 | ~SoftwareKeyboard() override; | ||
| 57 | |||
| 58 | void Initialize() override; | ||
| 59 | |||
| 60 | bool TransactionComplete() const override; | ||
| 61 | ResultCode GetStatus() const override; | ||
| 62 | void ExecuteInteractive() override; | ||
| 63 | void Execute() override; | ||
| 64 | |||
| 65 | void WriteText(std::optional<std::u16string> text); | ||
| 66 | |||
| 67 | private: | ||
| 68 | KeyboardConfig config; | ||
| 69 | std::u16string initial_text; | ||
| 70 | bool complete = false; | ||
| 71 | std::vector<u8> final_data; | ||
| 72 | }; | ||
| 73 | |||
| 74 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/stub_applet.cpp new file mode 100644 index 000000000..ed166b87d --- /dev/null +++ b/src/core/hle/service/am/applets/stub_applet.cpp | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | |||
| 7 | #include "common/hex_util.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/am/am.h" | ||
| 11 | #include "core/hle/service/am/applets/stub_applet.h" | ||
| 12 | |||
| 13 | namespace Service::AM::Applets { | ||
| 14 | |||
| 15 | static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) { | ||
| 16 | std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet(); | ||
| 17 | for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { | ||
| 18 | const auto data = storage->GetData(); | ||
| 19 | LOG_INFO(Service_AM, | ||
| 20 | "called (STUBBED), during {} recieved normal data with size={:08X}, data={}", | ||
| 21 | prefix, data.size(), Common::HexVectorToString(data)); | ||
| 22 | } | ||
| 23 | |||
| 24 | storage = broker.PopInteractiveDataToApplet(); | ||
| 25 | for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { | ||
| 26 | const auto data = storage->GetData(); | ||
| 27 | LOG_INFO(Service_AM, | ||
| 28 | "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}", | ||
| 29 | prefix, data.size(), Common::HexVectorToString(data)); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | StubApplet::StubApplet() = default; | ||
| 34 | |||
| 35 | StubApplet::~StubApplet() = default; | ||
| 36 | |||
| 37 | void StubApplet::Initialize() { | ||
| 38 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 39 | Applet::Initialize(); | ||
| 40 | LogCurrentStorage(broker, "Initialize"); | ||
| 41 | } | ||
| 42 | |||
| 43 | bool StubApplet::TransactionComplete() const { | ||
| 44 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | |||
| 48 | ResultCode StubApplet::GetStatus() const { | ||
| 49 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 50 | return RESULT_SUCCESS; | ||
| 51 | } | ||
| 52 | |||
| 53 | void StubApplet::ExecuteInteractive() { | ||
| 54 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 55 | LogCurrentStorage(broker, "ExecuteInteractive"); | ||
| 56 | |||
| 57 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 58 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 59 | broker.SignalStateChanged(); | ||
| 60 | } | ||
| 61 | |||
| 62 | void StubApplet::Execute() { | ||
| 63 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 64 | LogCurrentStorage(broker, "Execute"); | ||
| 65 | |||
| 66 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 67 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 68 | broker.SignalStateChanged(); | ||
| 69 | } | ||
| 70 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h new file mode 100644 index 000000000..7d8dc968d --- /dev/null +++ b/src/core/hle/service/am/applets/stub_applet.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/am/applets/applets.h" | ||
| 8 | |||
| 9 | namespace Service::AM::Applets { | ||
| 10 | |||
| 11 | class StubApplet final : public Applet { | ||
| 12 | public: | ||
| 13 | StubApplet(); | ||
| 14 | ~StubApplet() override; | ||
| 15 | |||
| 16 | void Initialize() override; | ||
| 17 | |||
| 18 | bool TransactionComplete() const override; | ||
| 19 | ResultCode GetStatus() const override; | ||
| 20 | void ExecuteInteractive() override; | ||
| 21 | void Execute() override; | ||
| 22 | }; | ||
| 23 | |||
| 24 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 54305cf05..0417fdb92 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -13,8 +13,10 @@ | |||
| 13 | #include "core/file_sys/patch_manager.h" | 13 | #include "core/file_sys/patch_manager.h" |
| 14 | #include "core/file_sys/registered_cache.h" | 14 | #include "core/file_sys/registered_cache.h" |
| 15 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/event.h" | 16 | #include "core/hle/kernel/kernel.h" |
| 17 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/kernel/writable_event.h" | ||
| 18 | #include "core/hle/service/aoc/aoc_u.h" | 20 | #include "core/hle/service/aoc/aoc_u.h" |
| 19 | #include "core/hle/service/filesystem/filesystem.h" | 21 | #include "core/hle/service/filesystem/filesystem.h" |
| 20 | #include "core/loader/loader.h" | 22 | #include "core/loader/loader.h" |
| @@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() { | |||
| 32 | std::vector<u64> add_on_content; | 34 | std::vector<u64> add_on_content; |
| 33 | const auto rcu = FileSystem::GetUnionContents(); | 35 | const auto rcu = FileSystem::GetUnionContents(); |
| 34 | const auto list = | 36 | const auto list = |
| 35 | rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); | 37 | rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); |
| 36 | std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), | 38 | std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), |
| 37 | [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; }); | 39 | [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; }); |
| 38 | add_on_content.erase( | 40 | add_on_content.erase( |
| 39 | std::remove_if( | 41 | std::remove_if( |
| 40 | add_on_content.begin(), add_on_content.end(), | 42 | add_on_content.begin(), add_on_content.end(), |
| 41 | [&rcu](u64 tid) { | 43 | [&rcu](u64 tid) { |
| 42 | return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() != | 44 | return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() != |
| 43 | Loader::ResultStatus::Success; | 45 | Loader::ResultStatus::Success; |
| 44 | }), | 46 | }), |
| 45 | add_on_content.end()); | 47 | add_on_content.end()); |
| @@ -61,13 +63,15 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs | |||
| 61 | RegisterHandlers(functions); | 63 | RegisterHandlers(functions); |
| 62 | 64 | ||
| 63 | auto& kernel = Core::System::GetInstance().Kernel(); | 65 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 64 | aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, | 66 | aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 65 | "GetAddOnContentListChanged:Event"); | 67 | "GetAddOnContentListChanged:Event"); |
| 66 | } | 68 | } |
| 67 | 69 | ||
| 68 | AOC_U::~AOC_U() = default; | 70 | AOC_U::~AOC_U() = default; |
| 69 | 71 | ||
| 70 | void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { | 72 | void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_DEBUG(Service_AOC, "called"); | ||
| 74 | |||
| 71 | IPC::ResponseBuilder rb{ctx, 3}; | 75 | IPC::ResponseBuilder rb{ctx, 3}; |
| 72 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 73 | 77 | ||
| @@ -82,6 +86,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 82 | 86 | ||
| 83 | const auto offset = rp.PopRaw<u32>(); | 87 | const auto offset = rp.PopRaw<u32>(); |
| 84 | auto count = rp.PopRaw<u32>(); | 88 | auto count = rp.PopRaw<u32>(); |
| 89 | LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count); | ||
| 85 | 90 | ||
| 86 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 91 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 87 | 92 | ||
| @@ -110,6 +115,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 110 | } | 115 | } |
| 111 | 116 | ||
| 112 | void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { | 117 | void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { |
| 118 | LOG_DEBUG(Service_AOC, "called"); | ||
| 119 | |||
| 113 | IPC::ResponseBuilder rb{ctx, 4}; | 120 | IPC::ResponseBuilder rb{ctx, 4}; |
| 114 | rb.Push(RESULT_SUCCESS); | 121 | rb.Push(RESULT_SUCCESS); |
| 115 | const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 122 | const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| @@ -128,7 +135,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 128 | IPC::RequestParser rp{ctx}; | 135 | IPC::RequestParser rp{ctx}; |
| 129 | 136 | ||
| 130 | const auto aoc_id = rp.PopRaw<u32>(); | 137 | const auto aoc_id = rp.PopRaw<u32>(); |
| 131 | |||
| 132 | LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); | 138 | LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); |
| 133 | 139 | ||
| 134 | IPC::ResponseBuilder rb{ctx, 2}; | 140 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -140,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { | |||
| 140 | 146 | ||
| 141 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 147 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 142 | rb.Push(RESULT_SUCCESS); | 148 | rb.Push(RESULT_SUCCESS); |
| 143 | rb.PushCopyObjects(aoc_change_event); | 149 | rb.PushCopyObjects(aoc_change_event.readable); |
| 144 | } | 150 | } |
| 145 | 151 | ||
| 146 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 152 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 68d94fdaa..5effea730 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_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 Kernel { | ||
| 10 | class WritableEvent; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::AOC { | 13 | namespace Service::AOC { |
| 10 | 14 | ||
| 11 | class AOC_U final : public ServiceFramework<AOC_U> { | 15 | class AOC_U final : public ServiceFramework<AOC_U> { |
| @@ -21,7 +25,7 @@ private: | |||
| 21 | void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); | 25 | void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); |
| 22 | 26 | ||
| 23 | std::vector<u64> add_on_content; | 27 | std::vector<u64> add_on_content; |
| 24 | Kernel::SharedPtr<Kernel::Event> aoc_change_event; | 28 | Kernel::EventPair aoc_change_event; |
| 25 | }; | 29 | }; |
| 26 | 30 | ||
| 27 | /// Registers all AOC services with the specified service manager. | 31 | /// Registers all AOC services with the specified service manager. |
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index c22bd3859..fcacbab72 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp | |||
| @@ -40,24 +40,22 @@ private: | |||
| 40 | 40 | ||
| 41 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); | 41 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); |
| 42 | u32 config = rp.Pop<u32>(); | 42 | u32 config = rp.Pop<u32>(); |
| 43 | LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), | ||
| 44 | config); | ||
| 43 | 45 | ||
| 44 | IPC::ResponseBuilder rb{ctx, 2}; | 46 | IPC::ResponseBuilder rb{ctx, 2}; |
| 45 | rb.Push(RESULT_SUCCESS); | 47 | rb.Push(RESULT_SUCCESS); |
| 46 | |||
| 47 | LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), | ||
| 48 | config); | ||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { | 50 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { |
| 52 | IPC::RequestParser rp{ctx}; | 51 | IPC::RequestParser rp{ctx}; |
| 53 | 52 | ||
| 54 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); | 53 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); |
| 54 | LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); | ||
| 55 | 55 | ||
| 56 | IPC::ResponseBuilder rb{ctx, 3}; | 56 | IPC::ResponseBuilder rb{ctx, 3}; |
| 57 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 58 | rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); | 58 | rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); |
| 59 | |||
| 60 | LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); | ||
| 61 | } | 59 | } |
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| @@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name) | |||
| 73 | APM::~APM() = default; | 71 | APM::~APM() = default; |
| 74 | 72 | ||
| 75 | void APM::OpenSession(Kernel::HLERequestContext& ctx) { | 73 | void APM::OpenSession(Kernel::HLERequestContext& ctx) { |
| 74 | LOG_DEBUG(Service_APM, "called"); | ||
| 75 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 76 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 77 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.PushIpcInterface<ISession>(); | 78 | rb.PushIpcInterface<ISession>(); |
| 79 | |||
| 80 | LOG_DEBUG(Service_APM, "called"); | ||
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | 81 | APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { |
| @@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | |||
| 98 | APM_Sys::~APM_Sys() = default; | 96 | APM_Sys::~APM_Sys() = default; |
| 99 | 97 | ||
| 100 | void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { | 98 | void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { |
| 99 | LOG_DEBUG(Service_APM, "called"); | ||
| 100 | |||
| 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 102 | rb.Push(RESULT_SUCCESS); | 102 | rb.Push(RESULT_SUCCESS); |
| 103 | rb.PushIpcInterface<ISession>(); | 103 | rb.PushIpcInterface<ISession>(); |
| 104 | |||
| 105 | LOG_DEBUG(Service_APM, "called"); | ||
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | } // namespace Service::APM | 106 | } // namespace Service::APM |
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp index 358ef2576..e675b0188 100644 --- a/src/core/hle/service/arp/arp.cpp +++ b/src/core/hle/service/arp/arp.cpp | |||
| @@ -59,11 +59,11 @@ public: | |||
| 59 | 59 | ||
| 60 | private: | 60 | private: |
| 61 | void AcquireRegistrar(Kernel::HLERequestContext& ctx) { | 61 | void AcquireRegistrar(Kernel::HLERequestContext& ctx) { |
| 62 | LOG_DEBUG(Service_ARP, "called"); | ||
| 63 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 63 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 64 | rb.PushIpcInterface<IRegistrar>(); | 66 | rb.PushIpcInterface<IRegistrar>(); |
| 65 | |||
| 66 | LOG_DEBUG(Service_ARP, "called"); | ||
| 67 | } | 67 | } |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index ff1edefbb..dc6a6b188 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -13,8 +13,10 @@ | |||
| 13 | #include "common/swap.h" | 13 | #include "common/swap.h" |
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/event.h" | ||
| 17 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| 17 | #include "core/hle/kernel/kernel.h" | ||
| 18 | #include "core/hle/kernel/readable_event.h" | ||
| 19 | #include "core/hle/kernel/writable_event.h" | ||
| 18 | #include "core/hle/service/audio/audout_u.h" | 20 | #include "core/hle/service/audio/audout_u.h" |
| 19 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| 20 | 22 | ||
| @@ -44,8 +46,10 @@ enum class AudioState : u32 { | |||
| 44 | 46 | ||
| 45 | class IAudioOut final : public ServiceFramework<IAudioOut> { | 47 | class IAudioOut final : public ServiceFramework<IAudioOut> { |
| 46 | public: | 48 | public: |
| 47 | IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) | 49 | IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, |
| 48 | : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) { | 50 | std::string&& unique_name) |
| 51 | : ServiceFramework("IAudioOut"), audio_core(audio_core), | ||
| 52 | device_name(std::move(device_name)), audio_params(audio_params) { | ||
| 49 | 53 | ||
| 50 | static const FunctionInfo functions[] = { | 54 | static const FunctionInfo functions[] = { |
| 51 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | 55 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, |
| @@ -65,11 +69,12 @@ public: | |||
| 65 | 69 | ||
| 66 | // This is the event handle used to check if the audio buffer was released | 70 | // This is the event handle used to check if the audio buffer was released |
| 67 | auto& kernel = Core::System::GetInstance().Kernel(); | 71 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 68 | buffer_event = | 72 | buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 69 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); | 73 | "IAudioOutBufferReleased"); |
| 70 | 74 | ||
| 71 | stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, | 75 | stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, |
| 72 | "IAudioOut", [=]() { buffer_event->Signal(); }); | 76 | std::move(unique_name), |
| 77 | [=]() { buffer_event.writable->Signal(); }); | ||
| 73 | } | 78 | } |
| 74 | 79 | ||
| 75 | private: | 80 | private: |
| @@ -84,6 +89,7 @@ private: | |||
| 84 | 89 | ||
| 85 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { | 90 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_DEBUG(Service_Audio, "called"); | 91 | LOG_DEBUG(Service_Audio, "called"); |
| 92 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | 93 | IPC::ResponseBuilder rb{ctx, 3}; |
| 88 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); | 95 | rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); |
| @@ -118,7 +124,7 @@ private: | |||
| 118 | 124 | ||
| 119 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 125 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 120 | rb.Push(RESULT_SUCCESS); | 126 | rb.Push(RESULT_SUCCESS); |
| 121 | rb.PushCopyObjects(buffer_event); | 127 | rb.PushCopyObjects(buffer_event.readable); |
| 122 | } | 128 | } |
| 123 | 129 | ||
| 124 | void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { | 130 | void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { |
| @@ -146,6 +152,7 @@ private: | |||
| 146 | 152 | ||
| 147 | void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { | 153 | void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { |
| 148 | LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); | 154 | LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); |
| 155 | |||
| 149 | IPC::RequestParser rp{ctx}; | 156 | IPC::RequestParser rp{ctx}; |
| 150 | const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; | 157 | const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; |
| 151 | const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; | 158 | const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; |
| @@ -161,6 +168,7 @@ private: | |||
| 161 | 168 | ||
| 162 | void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { | 169 | void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { |
| 163 | LOG_DEBUG(Service_Audio, "called"); | 170 | LOG_DEBUG(Service_Audio, "called"); |
| 171 | |||
| 164 | IPC::RequestParser rp{ctx}; | 172 | IPC::RequestParser rp{ctx}; |
| 165 | const u64 tag{rp.Pop<u64>()}; | 173 | const u64 tag{rp.Pop<u64>()}; |
| 166 | IPC::ResponseBuilder rb{ctx, 3}; | 174 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -170,6 +178,7 @@ private: | |||
| 170 | 178 | ||
| 171 | void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { | 179 | void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { |
| 172 | LOG_DEBUG(Service_Audio, "called"); | 180 | LOG_DEBUG(Service_Audio, "called"); |
| 181 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 3}; | 182 | IPC::ResponseBuilder rb{ctx, 3}; |
| 174 | rb.Push(RESULT_SUCCESS); | 183 | rb.Push(RESULT_SUCCESS); |
| 175 | rb.Push(static_cast<u32>(stream->GetQueueSize())); | 184 | rb.Push(static_cast<u32>(stream->GetQueueSize())); |
| @@ -177,15 +186,17 @@ private: | |||
| 177 | 186 | ||
| 178 | AudioCore::AudioOut& audio_core; | 187 | AudioCore::AudioOut& audio_core; |
| 179 | AudioCore::StreamPtr stream; | 188 | AudioCore::StreamPtr stream; |
| 189 | std::string device_name; | ||
| 180 | 190 | ||
| 181 | AudoutParams audio_params{}; | 191 | AudoutParams audio_params{}; |
| 182 | 192 | ||
| 183 | /// This is the evend handle used to check if the audio buffer was released | 193 | /// This is the event handle used to check if the audio buffer was released |
| 184 | Kernel::SharedPtr<Kernel::Event> buffer_event; | 194 | Kernel::EventPair buffer_event; |
| 185 | }; | 195 | }; |
| 186 | 196 | ||
| 187 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { | 197 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { |
| 188 | LOG_DEBUG(Service_Audio, "called"); | 198 | LOG_DEBUG(Service_Audio, "called"); |
| 199 | |||
| 189 | IPC::RequestParser rp{ctx}; | 200 | IPC::RequestParser rp{ctx}; |
| 190 | 201 | ||
| 191 | ctx.WriteBuffer(DefaultDevice); | 202 | ctx.WriteBuffer(DefaultDevice); |
| @@ -199,7 +210,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { | |||
| 199 | void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | 210 | void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { |
| 200 | LOG_DEBUG(Service_Audio, "called"); | 211 | LOG_DEBUG(Service_Audio, "called"); |
| 201 | 212 | ||
| 202 | ctx.WriteBuffer(DefaultDevice); | 213 | const auto device_name_data{ctx.ReadBuffer()}; |
| 214 | std::string device_name; | ||
| 215 | if (device_name_data[0] != '\0') { | ||
| 216 | device_name.assign(device_name_data.begin(), device_name_data.end()); | ||
| 217 | } else { | ||
| 218 | device_name.assign(DefaultDevice.begin(), DefaultDevice.end()); | ||
| 219 | } | ||
| 220 | ctx.WriteBuffer(device_name); | ||
| 221 | |||
| 203 | IPC::RequestParser rp{ctx}; | 222 | IPC::RequestParser rp{ctx}; |
| 204 | auto params{rp.PopRaw<AudoutParams>()}; | 223 | auto params{rp.PopRaw<AudoutParams>()}; |
| 205 | if (params.channel_count <= 2) { | 224 | if (params.channel_count <= 2) { |
| @@ -212,10 +231,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 212 | params.sample_rate = DefaultSampleRate; | 231 | params.sample_rate = DefaultSampleRate; |
| 213 | } | 232 | } |
| 214 | 233 | ||
| 215 | // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl | 234 | std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())}; |
| 216 | // will likely need to be updated as well. | 235 | auto audio_out_interface = std::make_shared<IAudioOut>( |
| 217 | ASSERT_MSG(!audio_out_interface, "Unimplemented"); | 236 | params, *audio_core, std::move(device_name), std::move(unique_name)); |
| 218 | audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core); | ||
| 219 | 237 | ||
| 220 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | 238 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
| 221 | rb.Push(RESULT_SUCCESS); | 239 | rb.Push(RESULT_SUCCESS); |
| @@ -224,6 +242,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 224 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); | 242 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); |
| 225 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); | 243 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); |
| 226 | rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); | 244 | rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); |
| 245 | |||
| 246 | audio_out_interfaces.push_back(std::move(audio_out_interface)); | ||
| 227 | } | 247 | } |
| 228 | 248 | ||
| 229 | AudOutU::AudOutU() : ServiceFramework("audout:u") { | 249 | AudOutU::AudOutU() : ServiceFramework("audout:u") { |
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index dcaf64708..aed4c43b2 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | 9 | ||
| 9 | namespace AudioCore { | 10 | namespace AudioCore { |
| @@ -24,7 +25,7 @@ public: | |||
| 24 | ~AudOutU() override; | 25 | ~AudOutU() override; |
| 25 | 26 | ||
| 26 | private: | 27 | private: |
| 27 | std::shared_ptr<IAudioOut> audio_out_interface; | 28 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; |
| 28 | std::unique_ptr<AudioCore::AudioOut> audio_core; | 29 | std::unique_ptr<AudioCore::AudioOut> audio_core; |
| 29 | 30 | ||
| 30 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); | 31 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index fac6785a5..945259c7d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -12,8 +12,10 @@ | |||
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "core/core.h" | 13 | #include "core/core.h" |
| 14 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 15 | #include "core/hle/kernel/event.h" | ||
| 16 | #include "core/hle/kernel/hle_ipc.h" | 15 | #include "core/hle/kernel/hle_ipc.h" |
| 16 | #include "core/hle/kernel/kernel.h" | ||
| 17 | #include "core/hle/kernel/readable_event.h" | ||
| 18 | #include "core/hle/kernel/writable_event.h" | ||
| 17 | #include "core/hle/service/audio/audren_u.h" | 19 | #include "core/hle/service/audio/audren_u.h" |
| 18 | 20 | ||
| 19 | namespace Service::Audio { | 21 | namespace Service::Audio { |
| @@ -28,90 +30,116 @@ public: | |||
| 28 | {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, | 30 | {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, |
| 29 | {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, | 31 | {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, |
| 30 | {3, &IAudioRenderer::GetState, "GetState"}, | 32 | {3, &IAudioRenderer::GetState, "GetState"}, |
| 31 | {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, | 33 | {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"}, |
| 32 | {5, &IAudioRenderer::Start, "Start"}, | 34 | {5, &IAudioRenderer::Start, "Start"}, |
| 33 | {6, &IAudioRenderer::Stop, "Stop"}, | 35 | {6, &IAudioRenderer::Stop, "Stop"}, |
| 34 | {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, | 36 | {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, |
| 35 | {8, nullptr, "SetRenderingTimeLimit"}, | 37 | {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, |
| 36 | {9, nullptr, "GetRenderingTimeLimit"}, | 38 | {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, |
| 37 | {10, nullptr, "RequestUpdateAuto"}, | 39 | {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"}, |
| 38 | {11, nullptr, "ExecuteAudioRendererRendering"}, | 40 | {11, nullptr, "ExecuteAudioRendererRendering"}, |
| 39 | }; | 41 | }; |
| 40 | // clang-format on | 42 | // clang-format on |
| 41 | RegisterHandlers(functions); | 43 | RegisterHandlers(functions); |
| 42 | 44 | ||
| 43 | auto& kernel = Core::System::GetInstance().Kernel(); | 45 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 44 | system_event = | 46 | system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 45 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); | 47 | "IAudioRenderer:SystemEvent"); |
| 46 | renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); | 48 | renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable); |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | private: | 51 | private: |
| 50 | void UpdateAudioCallback() { | 52 | void UpdateAudioCallback() { |
| 51 | system_event->Signal(); | 53 | system_event.writable->Signal(); |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | void GetSampleRate(Kernel::HLERequestContext& ctx) { | 56 | void GetSampleRate(Kernel::HLERequestContext& ctx) { |
| 57 | LOG_DEBUG(Service_Audio, "called"); | ||
| 58 | |||
| 55 | IPC::ResponseBuilder rb{ctx, 3}; | 59 | IPC::ResponseBuilder rb{ctx, 3}; |
| 56 | rb.Push(RESULT_SUCCESS); | 60 | rb.Push(RESULT_SUCCESS); |
| 57 | rb.Push<u32>(renderer->GetSampleRate()); | 61 | rb.Push<u32>(renderer->GetSampleRate()); |
| 58 | LOG_DEBUG(Service_Audio, "called"); | ||
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | void GetSampleCount(Kernel::HLERequestContext& ctx) { | 64 | void GetSampleCount(Kernel::HLERequestContext& ctx) { |
| 65 | LOG_DEBUG(Service_Audio, "called"); | ||
| 66 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 3}; | 67 | IPC::ResponseBuilder rb{ctx, 3}; |
| 63 | rb.Push(RESULT_SUCCESS); | 68 | rb.Push(RESULT_SUCCESS); |
| 64 | rb.Push<u32>(renderer->GetSampleCount()); | 69 | rb.Push<u32>(renderer->GetSampleCount()); |
| 65 | LOG_DEBUG(Service_Audio, "called"); | ||
| 66 | } | 70 | } |
| 67 | 71 | ||
| 68 | void GetState(Kernel::HLERequestContext& ctx) { | 72 | void GetState(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_DEBUG(Service_Audio, "called"); | ||
| 74 | |||
| 69 | IPC::ResponseBuilder rb{ctx, 3}; | 75 | IPC::ResponseBuilder rb{ctx, 3}; |
| 70 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 71 | rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); | 77 | rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); |
| 72 | LOG_DEBUG(Service_Audio, "called"); | ||
| 73 | } | 78 | } |
| 74 | 79 | ||
| 75 | void GetMixBufferCount(Kernel::HLERequestContext& ctx) { | 80 | void GetMixBufferCount(Kernel::HLERequestContext& ctx) { |
| 81 | LOG_DEBUG(Service_Audio, "called"); | ||
| 82 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | 83 | IPC::ResponseBuilder rb{ctx, 3}; |
| 77 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.Push<u32>(renderer->GetMixBufferCount()); | 85 | rb.Push<u32>(renderer->GetMixBufferCount()); |
| 79 | LOG_DEBUG(Service_Audio, "called"); | ||
| 80 | } | 86 | } |
| 81 | 87 | ||
| 82 | void RequestUpdate(Kernel::HLERequestContext& ctx) { | 88 | void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { |
| 89 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 90 | |||
| 83 | ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); | 91 | ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); |
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 92 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 93 | rb.Push(RESULT_SUCCESS); |
| 86 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 87 | } | 94 | } |
| 88 | 95 | ||
| 89 | void Start(Kernel::HLERequestContext& ctx) { | 96 | void Start(Kernel::HLERequestContext& ctx) { |
| 97 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 98 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 2}; | 99 | IPC::ResponseBuilder rb{ctx, 2}; |
| 91 | 100 | ||
| 92 | rb.Push(RESULT_SUCCESS); | 101 | rb.Push(RESULT_SUCCESS); |
| 93 | |||
| 94 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 95 | } | 102 | } |
| 96 | 103 | ||
| 97 | void Stop(Kernel::HLERequestContext& ctx) { | 104 | void Stop(Kernel::HLERequestContext& ctx) { |
| 105 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 106 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 107 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | 108 | ||
| 100 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 101 | |||
| 102 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 103 | } | 110 | } |
| 104 | 111 | ||
| 105 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { | 112 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { |
| 113 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 114 | |||
| 106 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 115 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 107 | rb.Push(RESULT_SUCCESS); | 116 | rb.Push(RESULT_SUCCESS); |
| 108 | rb.PushCopyObjects(system_event); | 117 | rb.PushCopyObjects(system_event.readable); |
| 118 | } | ||
| 109 | 119 | ||
| 110 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 120 | void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { |
| 121 | IPC::RequestParser rp{ctx}; | ||
| 122 | rendering_time_limit_percent = rp.Pop<u32>(); | ||
| 123 | LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}", | ||
| 124 | rendering_time_limit_percent); | ||
| 125 | |||
| 126 | ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100); | ||
| 127 | |||
| 128 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 129 | rb.Push(RESULT_SUCCESS); | ||
| 111 | } | 130 | } |
| 112 | 131 | ||
| 113 | Kernel::SharedPtr<Kernel::Event> system_event; | 132 | void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { |
| 133 | LOG_DEBUG(Service_Audio, "called"); | ||
| 134 | |||
| 135 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 136 | rb.Push(RESULT_SUCCESS); | ||
| 137 | rb.Push(rendering_time_limit_percent); | ||
| 138 | } | ||
| 139 | |||
| 140 | Kernel::EventPair system_event; | ||
| 114 | std::unique_ptr<AudioCore::AudioRenderer> renderer; | 141 | std::unique_ptr<AudioCore::AudioRenderer> renderer; |
| 142 | u32 rendering_time_limit_percent = 100; | ||
| 115 | }; | 143 | }; |
| 116 | 144 | ||
| 117 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 145 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
| @@ -136,8 +164,8 @@ public: | |||
| 136 | RegisterHandlers(functions); | 164 | RegisterHandlers(functions); |
| 137 | 165 | ||
| 138 | auto& kernel = Core::System::GetInstance().Kernel(); | 166 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 139 | buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | 167 | buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, |
| 140 | "IAudioOutBufferReleasedEvent"); | 168 | "IAudioOutBufferReleasedEvent"); |
| 141 | } | 169 | } |
| 142 | 170 | ||
| 143 | private: | 171 | private: |
| @@ -181,21 +209,22 @@ private: | |||
| 181 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { | 209 | void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { |
| 182 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 210 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 183 | 211 | ||
| 184 | buffer_event->Signal(); | 212 | buffer_event.writable->Signal(); |
| 185 | 213 | ||
| 186 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 214 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 187 | rb.Push(RESULT_SUCCESS); | 215 | rb.Push(RESULT_SUCCESS); |
| 188 | rb.PushCopyObjects(buffer_event); | 216 | rb.PushCopyObjects(buffer_event.readable); |
| 189 | } | 217 | } |
| 190 | 218 | ||
| 191 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { | 219 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { |
| 192 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 220 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 221 | |||
| 193 | IPC::ResponseBuilder rb{ctx, 3}; | 222 | IPC::ResponseBuilder rb{ctx, 3}; |
| 194 | rb.Push(RESULT_SUCCESS); | 223 | rb.Push(RESULT_SUCCESS); |
| 195 | rb.Push<u32>(1); | 224 | rb.Push<u32>(1); |
| 196 | } | 225 | } |
| 197 | 226 | ||
| 198 | Kernel::SharedPtr<Kernel::Event> buffer_event; | 227 | Kernel::EventPair buffer_event; |
| 199 | 228 | ||
| 200 | }; // namespace Audio | 229 | }; // namespace Audio |
| 201 | 230 | ||
| @@ -214,19 +243,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { | |||
| 214 | AudRenU::~AudRenU() = default; | 243 | AudRenU::~AudRenU() = default; |
| 215 | 244 | ||
| 216 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { | 245 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { |
| 246 | LOG_DEBUG(Service_Audio, "called"); | ||
| 247 | |||
| 217 | IPC::RequestParser rp{ctx}; | 248 | IPC::RequestParser rp{ctx}; |
| 218 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); | 249 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); |
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 250 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | 251 | ||
| 221 | rb.Push(RESULT_SUCCESS); | 252 | rb.Push(RESULT_SUCCESS); |
| 222 | rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); | 253 | rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); |
| 223 | |||
| 224 | LOG_DEBUG(Service_Audio, "called"); | ||
| 225 | } | 254 | } |
| 226 | 255 | ||
| 227 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | 256 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { |
| 228 | IPC::RequestParser rp{ctx}; | 257 | IPC::RequestParser rp{ctx}; |
| 229 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); | 258 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); |
| 259 | LOG_DEBUG(Service_Audio, "called"); | ||
| 230 | 260 | ||
| 231 | u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); | 261 | u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); |
| 232 | buffer_sz += params.unknown_c * 1024; | 262 | buffer_sz += params.unknown_c * 1024; |
| @@ -280,26 +310,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 280 | rb.Push(RESULT_SUCCESS); | 310 | rb.Push(RESULT_SUCCESS); |
| 281 | rb.Push<u64>(output_sz); | 311 | rb.Push<u64>(output_sz); |
| 282 | 312 | ||
| 283 | LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); | 313 | LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz); |
| 284 | } | 314 | } |
| 285 | 315 | ||
| 286 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { | 316 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { |
| 317 | LOG_DEBUG(Service_Audio, "called"); | ||
| 318 | |||
| 287 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 319 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 288 | 320 | ||
| 289 | rb.Push(RESULT_SUCCESS); | 321 | rb.Push(RESULT_SUCCESS); |
| 290 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 322 | rb.PushIpcInterface<Audio::IAudioDevice>(); |
| 291 | |||
| 292 | LOG_DEBUG(Service_Audio, "called"); | ||
| 293 | } | 323 | } |
| 294 | 324 | ||
| 295 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { | 325 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { |
| 326 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 327 | |||
| 296 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 328 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 297 | 329 | ||
| 298 | rb.Push(RESULT_SUCCESS); | 330 | rb.Push(RESULT_SUCCESS); |
| 299 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 331 | rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different |
| 300 | 332 | // based on the current revision | |
| 301 | LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different | ||
| 302 | // based on the current revision | ||
| 303 | } | 333 | } |
| 304 | 334 | ||
| 305 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { | 335 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 783c39503..a850cadc8 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -46,10 +46,13 @@ public: | |||
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { | 48 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { |
| 49 | LOG_DEBUG(Audio, "called"); | ||
| 50 | |||
| 49 | u32 consumed = 0; | 51 | u32 consumed = 0; |
| 50 | u32 sample_count = 0; | 52 | u32 sample_count = 0; |
| 51 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); | 53 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); |
| 52 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { | 54 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { |
| 55 | LOG_ERROR(Audio, "Failed to decode opus data"); | ||
| 53 | IPC::ResponseBuilder rb{ctx, 2}; | 56 | IPC::ResponseBuilder rb{ctx, 2}; |
| 54 | // TODO(ogniK): Use correct error code | 57 | // TODO(ogniK): Use correct error code |
| 55 | rb.Push(ResultCode(-1)); | 58 | rb.Push(ResultCode(-1)); |
| @@ -63,12 +66,15 @@ private: | |||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { | 68 | void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { |
| 69 | LOG_DEBUG(Audio, "called"); | ||
| 70 | |||
| 66 | u32 consumed = 0; | 71 | u32 consumed = 0; |
| 67 | u32 sample_count = 0; | 72 | u32 sample_count = 0; |
| 68 | u64 performance = 0; | 73 | u64 performance = 0; |
| 69 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); | 74 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); |
| 70 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, | 75 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, |
| 71 | performance)) { | 76 | performance)) { |
| 77 | LOG_ERROR(Audio, "Failed to decode opus data"); | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 78 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | // TODO(ogniK): Use correct error code | 79 | // TODO(ogniK): Use correct error code |
| 74 | rb.Push(ResultCode(-1)); | 80 | rb.Push(ResultCode(-1)); |
| @@ -77,8 +83,8 @@ private: | |||
| 77 | IPC::ResponseBuilder rb{ctx, 6}; | 83 | IPC::ResponseBuilder rb{ctx, 6}; |
| 78 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 79 | rb.Push<u32>(consumed); | 85 | rb.Push<u32>(consumed); |
| 80 | rb.Push<u64>(performance); | ||
| 81 | rb.Push<u32>(sample_count); | 86 | rb.Push<u32>(sample_count); |
| 87 | rb.Push<u64>(performance); | ||
| 82 | ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); | 88 | ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); |
| 83 | } | 89 | } |
| 84 | 90 | ||
| @@ -88,24 +94,39 @@ private: | |||
| 88 | std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { | 94 | std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { |
| 89 | const auto start_time = std::chrono::high_resolution_clock::now(); | 95 | const auto start_time = std::chrono::high_resolution_clock::now(); |
| 90 | std::size_t raw_output_sz = output.size() * sizeof(opus_int16); | 96 | std::size_t raw_output_sz = output.size() * sizeof(opus_int16); |
| 91 | if (sizeof(OpusHeader) > input.size()) | 97 | if (sizeof(OpusHeader) > input.size()) { |
| 98 | LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", | ||
| 99 | sizeof(OpusHeader), input.size()); | ||
| 92 | return false; | 100 | return false; |
| 101 | } | ||
| 93 | OpusHeader hdr{}; | 102 | OpusHeader hdr{}; |
| 94 | std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); | 103 | std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); |
| 95 | if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { | 104 | if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { |
| 105 | LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}", | ||
| 106 | sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size()); | ||
| 96 | return false; | 107 | return false; |
| 97 | } | 108 | } |
| 98 | auto frame = input.data() + sizeof(OpusHeader); | 109 | auto frame = input.data() + sizeof(OpusHeader); |
| 99 | auto decoded_sample_count = opus_packet_get_nb_samples( | 110 | auto decoded_sample_count = opus_packet_get_nb_samples( |
| 100 | frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), | 111 | frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), |
| 101 | static_cast<opus_int32>(sample_rate)); | 112 | static_cast<opus_int32>(sample_rate)); |
| 102 | if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) | 113 | if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) { |
| 114 | LOG_ERROR( | ||
| 115 | Audio, | ||
| 116 | "Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}", | ||
| 117 | decoded_sample_count * channel_count * sizeof(u16), raw_output_sz); | ||
| 103 | return false; | 118 | return false; |
| 119 | } | ||
| 120 | const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); | ||
| 104 | auto out_sample_count = | 121 | auto out_sample_count = |
| 105 | opus_decode(decoder.get(), frame, hdr.sz, output.data(), | 122 | opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0); |
| 106 | (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); | 123 | if (out_sample_count < 0) { |
| 107 | if (out_sample_count < 0) | 124 | LOG_ERROR(Audio, |
| 125 | "Incorrect sample count received from opus_decode, " | ||
| 126 | "output_sample_count={}, frame_size={}, data_sz_from_hdr={}", | ||
| 127 | out_sample_count, frame_size, static_cast<u32>(hdr.sz)); | ||
| 108 | return false; | 128 | return false; |
| 129 | } | ||
| 109 | const auto end_time = std::chrono::high_resolution_clock::now() - start_time; | 130 | const auto end_time = std::chrono::high_resolution_clock::now() - start_time; |
| 110 | sample_count = out_sample_count; | 131 | sample_count = out_sample_count; |
| 111 | consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); | 132 | consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); |
| @@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) { | |||
| 134 | 155 | ||
| 135 | void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { | 156 | void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { |
| 136 | IPC::RequestParser rp{ctx}; | 157 | IPC::RequestParser rp{ctx}; |
| 137 | auto sample_rate = rp.Pop<u32>(); | 158 | const auto sample_rate = rp.Pop<u32>(); |
| 138 | auto channel_count = rp.Pop<u32>(); | 159 | const auto channel_count = rp.Pop<u32>(); |
| 160 | LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count); | ||
| 161 | |||
| 139 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || | 162 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || |
| 140 | sample_rate == 12000 || sample_rate == 8000, | 163 | sample_rate == 12000 || sample_rate == 8000, |
| 141 | "Invalid sample rate"); | 164 | "Invalid sample rate"); |
| 142 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); | 165 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); |
| 143 | u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); | 166 | |
| 144 | LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); | 167 | const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); |
| 168 | LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz); | ||
| 145 | 169 | ||
| 146 | IPC::ResponseBuilder rb{ctx, 3}; | 170 | IPC::ResponseBuilder rb{ctx, 3}; |
| 147 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| @@ -155,6 +179,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 155 | auto buffer_sz = rp.Pop<u32>(); | 179 | auto buffer_sz = rp.Pop<u32>(); |
| 156 | LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, | 180 | LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, |
| 157 | channel_count, buffer_sz); | 181 | channel_count, buffer_sz); |
| 182 | |||
| 158 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || | 183 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || |
| 159 | sample_rate == 12000 || sample_rate == 8000, | 184 | sample_rate == 12000 || sample_rate == 8000, |
| 160 | "Invalid sample rate"); | 185 | "Invalid sample rate"); |
| @@ -164,7 +189,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 164 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); | 189 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); |
| 165 | std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ | 190 | std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ |
| 166 | static_cast<OpusDecoder*>(operator new(worker_sz))}; | 191 | static_cast<OpusDecoder*>(operator new(worker_sz))}; |
| 167 | if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { | 192 | if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) { |
| 193 | LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err); | ||
| 168 | IPC::ResponseBuilder rb{ctx, 2}; | 194 | IPC::ResponseBuilder rb{ctx, 2}; |
| 169 | // TODO(ogniK): Use correct error code | 195 | // TODO(ogniK): Use correct error code |
| 170 | rb.Push(ResultCode(-1)); | 196 | rb.Push(ResultCode(-1)); |
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 6e7b795fb..b7bd738fc 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -33,10 +33,11 @@ public: | |||
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { |
| 36 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 37 | |||
| 36 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 37 | rb.Push(RESULT_SUCCESS); | 39 | rb.Push(RESULT_SUCCESS); |
| 38 | rb.PushIpcInterface<IBcatService>(); | 40 | rb.PushIpcInterface<IBcatService>(); |
| 39 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 43 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index d0a15cc4c..5704ca0ab 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -2,12 +2,54 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | ||
| 9 | #include "core/hle/kernel/readable_event.h" | ||
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 5 | #include "core/hle/service/btdrv/btdrv.h" | 11 | #include "core/hle/service/btdrv/btdrv.h" |
| 6 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 7 | #include "core/hle/service/sm/sm.h" | 13 | #include "core/hle/service/sm/sm.h" |
| 8 | 14 | ||
| 9 | namespace Service::BtDrv { | 15 | namespace Service::BtDrv { |
| 10 | 16 | ||
| 17 | class Bt final : public ServiceFramework<Bt> { | ||
| 18 | public: | ||
| 19 | explicit Bt() : ServiceFramework{"bt"} { | ||
| 20 | // clang-format off | ||
| 21 | static const FunctionInfo functions[] = { | ||
| 22 | {0, nullptr, "Unknown0"}, | ||
| 23 | {1, nullptr, "Unknown1"}, | ||
| 24 | {2, nullptr, "Unknown2"}, | ||
| 25 | {3, nullptr, "Unknown3"}, | ||
| 26 | {4, nullptr, "Unknown4"}, | ||
| 27 | {5, nullptr, "Unknown5"}, | ||
| 28 | {6, nullptr, "Unknown6"}, | ||
| 29 | {7, nullptr, "Unknown7"}, | ||
| 30 | {8, nullptr, "Unknown8"}, | ||
| 31 | {9, &Bt::RegisterEvent, "RegisterEvent"}, | ||
| 32 | }; | ||
| 33 | // clang-format on | ||
| 34 | RegisterHandlers(functions); | ||
| 35 | |||
| 36 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 37 | register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, | ||
| 38 | "BT:RegisterEvent"); | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | void RegisterEvent(Kernel::HLERequestContext& ctx) { | ||
| 43 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 44 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 46 | rb.Push(RESULT_SUCCESS); | ||
| 47 | rb.PushCopyObjects(register_event.readable); | ||
| 48 | } | ||
| 49 | |||
| 50 | Kernel::EventPair register_event; | ||
| 51 | }; | ||
| 52 | |||
| 11 | class BtDrv final : public ServiceFramework<BtDrv> { | 53 | class BtDrv final : public ServiceFramework<BtDrv> { |
| 12 | public: | 54 | public: |
| 13 | explicit BtDrv() : ServiceFramework{"btdrv"} { | 55 | explicit BtDrv() : ServiceFramework{"btdrv"} { |
| @@ -67,6 +109,7 @@ public: | |||
| 67 | 109 | ||
| 68 | void InstallInterfaces(SM::ServiceManager& sm) { | 110 | void InstallInterfaces(SM::ServiceManager& sm) { |
| 69 | std::make_shared<BtDrv>()->InstallAsService(sm); | 111 | std::make_shared<BtDrv>()->InstallAsService(sm); |
| 112 | std::make_shared<Bt>()->InstallAsService(sm); | ||
| 70 | } | 113 | } |
| 71 | 114 | ||
| 72 | } // namespace Service::BtDrv | 115 | } // namespace Service::BtDrv |
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index b949bfabd..ef7398a23 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -7,12 +7,126 @@ | |||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/hle_ipc.h" | 9 | #include "core/hle/kernel/hle_ipc.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/btm/btm.h" | 13 | #include "core/hle/service/btm/btm.h" |
| 11 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 12 | #include "core/hle/service/sm/sm.h" | ||
| 13 | 15 | ||
| 14 | namespace Service::BTM { | 16 | namespace Service::BTM { |
| 15 | 17 | ||
| 18 | class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { | ||
| 19 | public: | ||
| 20 | explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} { | ||
| 21 | // clang-format off | ||
| 22 | static const FunctionInfo functions[] = { | ||
| 23 | {0, &IBtmUserCore::GetScanEvent, "GetScanEvent"}, | ||
| 24 | {1, nullptr, "Unknown1"}, | ||
| 25 | {2, nullptr, "Unknown2"}, | ||
| 26 | {3, nullptr, "Unknown3"}, | ||
| 27 | {4, nullptr, "Unknown4"}, | ||
| 28 | {5, nullptr, "Unknown5"}, | ||
| 29 | {6, nullptr, "Unknown6"}, | ||
| 30 | {7, nullptr, "Unknown7"}, | ||
| 31 | {8, nullptr, "Unknown8"}, | ||
| 32 | {9, nullptr, "Unknown9"}, | ||
| 33 | {10, nullptr, "Unknown10"}, | ||
| 34 | {17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"}, | ||
| 35 | {18, nullptr, "Unknown18"}, | ||
| 36 | {19, nullptr, "Unknown19"}, | ||
| 37 | {20, nullptr, "Unknown20"}, | ||
| 38 | {21, nullptr, "Unknown21"}, | ||
| 39 | {22, nullptr, "Unknown22"}, | ||
| 40 | {23, nullptr, "Unknown23"}, | ||
| 41 | {24, nullptr, "Unknown24"}, | ||
| 42 | {25, nullptr, "Unknown25"}, | ||
| 43 | {26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"}, | ||
| 44 | {27, nullptr, "Unknown27"}, | ||
| 45 | {28, nullptr, "Unknown28"}, | ||
| 46 | {29, nullptr, "Unknown29"}, | ||
| 47 | {30, nullptr, "Unknown30"}, | ||
| 48 | {31, nullptr, "Unknown31"}, | ||
| 49 | {32, nullptr, "Unknown32"}, | ||
| 50 | {33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"}, | ||
| 51 | {34, nullptr, "Unknown34"}, | ||
| 52 | {35, nullptr, "Unknown35"}, | ||
| 53 | {36, nullptr, "Unknown36"}, | ||
| 54 | {37, nullptr, "Unknown37"}, | ||
| 55 | }; | ||
| 56 | // clang-format on | ||
| 57 | RegisterHandlers(functions); | ||
| 58 | |||
| 59 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 60 | scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, | ||
| 61 | "IBtmUserCore:ScanEvent"); | ||
| 62 | connection_event = Kernel::WritableEvent::CreateEventPair( | ||
| 63 | kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent"); | ||
| 64 | service_discovery = Kernel::WritableEvent::CreateEventPair( | ||
| 65 | kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); | ||
| 66 | config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, | ||
| 67 | "IBtmUserCore:ConfigEvent"); | ||
| 68 | } | ||
| 69 | |||
| 70 | private: | ||
| 71 | void GetScanEvent(Kernel::HLERequestContext& ctx) { | ||
| 72 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 73 | |||
| 74 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 75 | rb.Push(RESULT_SUCCESS); | ||
| 76 | rb.PushCopyObjects(scan_event.readable); | ||
| 77 | } | ||
| 78 | |||
| 79 | void GetConnectionEvent(Kernel::HLERequestContext& ctx) { | ||
| 80 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 81 | |||
| 82 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 83 | rb.Push(RESULT_SUCCESS); | ||
| 84 | rb.PushCopyObjects(connection_event.readable); | ||
| 85 | } | ||
| 86 | |||
| 87 | void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) { | ||
| 88 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 89 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 91 | rb.Push(RESULT_SUCCESS); | ||
| 92 | rb.PushCopyObjects(service_discovery.readable); | ||
| 93 | } | ||
| 94 | |||
| 95 | void GetConfigEvent(Kernel::HLERequestContext& ctx) { | ||
| 96 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | rb.PushCopyObjects(config_event.readable); | ||
| 101 | } | ||
| 102 | |||
| 103 | Kernel::EventPair scan_event; | ||
| 104 | Kernel::EventPair connection_event; | ||
| 105 | Kernel::EventPair service_discovery; | ||
| 106 | Kernel::EventPair config_event; | ||
| 107 | }; | ||
| 108 | |||
| 109 | class BTM_USR final : public ServiceFramework<BTM_USR> { | ||
| 110 | public: | ||
| 111 | explicit BTM_USR() : ServiceFramework{"btm:u"} { | ||
| 112 | // clang-format off | ||
| 113 | static const FunctionInfo functions[] = { | ||
| 114 | {0, &BTM_USR::GetCoreImpl, "GetCoreImpl"}, | ||
| 115 | }; | ||
| 116 | // clang-format on | ||
| 117 | RegisterHandlers(functions); | ||
| 118 | } | ||
| 119 | |||
| 120 | private: | ||
| 121 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { | ||
| 122 | LOG_DEBUG(Service_BTM, "called"); | ||
| 123 | |||
| 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 125 | rb.Push(RESULT_SUCCESS); | ||
| 126 | rb.PushIpcInterface<IBtmUserCore>(); | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | |||
| 16 | class BTM final : public ServiceFramework<BTM> { | 130 | class BTM final : public ServiceFramework<BTM> { |
| 17 | public: | 131 | public: |
| 18 | explicit BTM() : ServiceFramework{"btm"} { | 132 | explicit BTM() : ServiceFramework{"btm"} { |
| @@ -104,11 +218,11 @@ public: | |||
| 104 | 218 | ||
| 105 | private: | 219 | private: |
| 106 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { | 220 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { |
| 221 | LOG_DEBUG(Service_BTM, "called"); | ||
| 222 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 223 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 108 | rb.Push(RESULT_SUCCESS); | 224 | rb.Push(RESULT_SUCCESS); |
| 109 | rb.PushIpcInterface<IBtmSystemCore>(); | 225 | rb.PushIpcInterface<IBtmSystemCore>(); |
| 110 | |||
| 111 | LOG_DEBUG(Service_BTM, "called"); | ||
| 112 | } | 226 | } |
| 113 | }; | 227 | }; |
| 114 | 228 | ||
| @@ -116,6 +230,7 @@ void InstallInterfaces(SM::ServiceManager& sm) { | |||
| 116 | std::make_shared<BTM>()->InstallAsService(sm); | 230 | std::make_shared<BTM>()->InstallAsService(sm); |
| 117 | std::make_shared<BTM_DBG>()->InstallAsService(sm); | 231 | std::make_shared<BTM_DBG>()->InstallAsService(sm); |
| 118 | std::make_shared<BTM_SYS>()->InstallAsService(sm); | 232 | std::make_shared<BTM_SYS>()->InstallAsService(sm); |
| 233 | std::make_shared<BTM_USR>()->InstallAsService(sm); | ||
| 119 | } | 234 | } |
| 120 | 235 | ||
| 121 | } // namespace Service::BTM | 236 | } // namespace Service::BTM |
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp index ee11cd78e..d9b32954e 100644 --- a/src/core/hle/service/erpt/erpt.cpp +++ b/src/core/hle/service/erpt/erpt.cpp | |||
| @@ -17,11 +17,13 @@ public: | |||
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SubmitContext"}, | 18 | {0, nullptr, "SubmitContext"}, |
| 19 | {1, nullptr, "CreateReport"}, | 19 | {1, nullptr, "CreateReport"}, |
| 20 | {2, nullptr, "Unknown1"}, | 20 | {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, |
| 21 | {3, nullptr, "Unknown2"}, | 21 | {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, |
| 22 | {4, nullptr, "Unknown3"}, | 22 | {4, nullptr, "UpdatePowerOnTime"}, |
| 23 | {5, nullptr, "Unknown4"}, | 23 | {5, nullptr, "UpdateAwakeTime"}, |
| 24 | {6, nullptr, "Unknown5"}, | 24 | {6, nullptr, "SubmitMultipleCategoryContext"}, |
| 25 | {7, nullptr, "UpdateApplicationLaunchTime"}, | ||
| 26 | {8, nullptr, "ClearApplicationLaunchTime"}, | ||
| 25 | }; | 27 | }; |
| 26 | // clang-format on | 28 | // clang-format on |
| 27 | 29 | ||
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp index 566fbf924..e461274c1 100644 --- a/src/core/hle/service/fgm/fgm.cpp +++ b/src/core/hle/service/fgm/fgm.cpp | |||
| @@ -42,11 +42,11 @@ public: | |||
| 42 | 42 | ||
| 43 | private: | 43 | private: |
| 44 | void Initialize(Kernel::HLERequestContext& ctx) { | 44 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 45 | LOG_DEBUG(Service_FGM, "called"); | ||
| 46 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 46 | rb.Push(RESULT_SUCCESS); | 48 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.PushIpcInterface<IRequest>(); | 49 | rb.PushIpcInterface<IRequest>(); |
| 48 | |||
| 49 | LOG_DEBUG(Service_FGM, "called"); | ||
| 50 | } | 50 | } |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index e32a7c48e..b1490e6fa 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -113,6 +113,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str | |||
| 113 | return RESULT_SUCCESS; | 113 | return RESULT_SUCCESS; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const { | ||
| 117 | const std::string sanitized_path(FileUtil::SanitizePath(path)); | ||
| 118 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path)); | ||
| 119 | |||
| 120 | if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) { | ||
| 121 | // TODO(DarkLordZach): Find a better error code for this | ||
| 122 | return ResultCode(-1); | ||
| 123 | } | ||
| 124 | |||
| 125 | return RESULT_SUCCESS; | ||
| 126 | } | ||
| 127 | |||
| 116 | ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, | 128 | ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, |
| 117 | const std::string& dest_path_) const { | 129 | const std::string& dest_path_) const { |
| 118 | std::string src_path(FileUtil::SanitizePath(src_path_)); | 130 | std::string src_path(FileUtil::SanitizePath(src_path_)); |
| @@ -303,25 +315,35 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, | |||
| 303 | static_cast<u8>(space), save_struct.DebugInfo()); | 315 | static_cast<u8>(space), save_struct.DebugInfo()); |
| 304 | 316 | ||
| 305 | if (save_data_factory == nullptr) { | 317 | if (save_data_factory == nullptr) { |
| 306 | return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); | 318 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| 307 | } | 319 | } |
| 308 | 320 | ||
| 309 | return save_data_factory->Open(space, save_struct); | 321 | return save_data_factory->Open(space, save_struct); |
| 310 | } | 322 | } |
| 311 | 323 | ||
| 324 | ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { | ||
| 325 | LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); | ||
| 326 | |||
| 327 | if (save_data_factory == nullptr) { | ||
| 328 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 329 | } | ||
| 330 | |||
| 331 | return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space)); | ||
| 332 | } | ||
| 333 | |||
| 312 | ResultVal<FileSys::VirtualDir> OpenSDMC() { | 334 | ResultVal<FileSys::VirtualDir> OpenSDMC() { |
| 313 | LOG_TRACE(Service_FS, "Opening SDMC"); | 335 | LOG_TRACE(Service_FS, "Opening SDMC"); |
| 314 | 336 | ||
| 315 | if (sdmc_factory == nullptr) { | 337 | if (sdmc_factory == nullptr) { |
| 316 | return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound); | 338 | return FileSys::ERROR_SD_CARD_NOT_FOUND; |
| 317 | } | 339 | } |
| 318 | 340 | ||
| 319 | return sdmc_factory->Open(); | 341 | return sdmc_factory->Open(); |
| 320 | } | 342 | } |
| 321 | 343 | ||
| 322 | std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { | 344 | FileSys::RegisteredCacheUnion GetUnionContents() { |
| 323 | return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ | 345 | return FileSys::RegisteredCacheUnion{ |
| 324 | GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); | 346 | {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}}; |
| 325 | } | 347 | } |
| 326 | 348 | ||
| 327 | FileSys::RegisteredCache* GetSystemNANDContents() { | 349 | FileSys::RegisteredCache* GetSystemNANDContents() { |
| @@ -360,6 +382,15 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) { | |||
| 360 | return bis_factory->GetModificationLoadRoot(title_id); | 382 | return bis_factory->GetModificationLoadRoot(title_id); |
| 361 | } | 383 | } |
| 362 | 384 | ||
| 385 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) { | ||
| 386 | LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id); | ||
| 387 | |||
| 388 | if (bis_factory == nullptr) | ||
| 389 | return nullptr; | ||
| 390 | |||
| 391 | return bis_factory->GetModificationDumpRoot(title_id); | ||
| 392 | } | ||
| 393 | |||
| 363 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 394 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { |
| 364 | if (overwrite) { | 395 | if (overwrite) { |
| 365 | bis_factory = nullptr; | 396 | bis_factory = nullptr; |
| @@ -373,13 +404,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | |||
| 373 | FileSys::Mode::ReadWrite); | 404 | FileSys::Mode::ReadWrite); |
| 374 | auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | 405 | auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), |
| 375 | FileSys::Mode::ReadWrite); | 406 | FileSys::Mode::ReadWrite); |
| 407 | auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), | ||
| 408 | FileSys::Mode::ReadWrite); | ||
| 376 | 409 | ||
| 377 | if (bis_factory == nullptr) | 410 | if (bis_factory == nullptr) { |
| 378 | bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); | 411 | bis_factory = |
| 379 | if (save_data_factory == nullptr) | 412 | std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory); |
| 413 | } | ||
| 414 | |||
| 415 | if (save_data_factory == nullptr) { | ||
| 380 | save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); | 416 | save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); |
| 381 | if (sdmc_factory == nullptr) | 417 | } |
| 418 | |||
| 419 | if (sdmc_factory == nullptr) { | ||
| 382 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); | 420 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); |
| 421 | } | ||
| 383 | } | 422 | } |
| 384 | 423 | ||
| 385 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { | 424 | void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 6ca5c5636..965414be0 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -45,15 +45,17 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora | |||
| 45 | FileSys::ContentRecordType type); | 45 | FileSys::ContentRecordType type); |
| 46 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, | 46 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, |
| 47 | FileSys::SaveDataDescriptor save_struct); | 47 | FileSys::SaveDataDescriptor save_struct); |
| 48 | ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); | ||
| 48 | ResultVal<FileSys::VirtualDir> OpenSDMC(); | 49 | ResultVal<FileSys::VirtualDir> OpenSDMC(); |
| 49 | 50 | ||
| 50 | std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); | 51 | FileSys::RegisteredCacheUnion GetUnionContents(); |
| 51 | 52 | ||
| 52 | FileSys::RegisteredCache* GetSystemNANDContents(); | 53 | FileSys::RegisteredCache* GetSystemNANDContents(); |
| 53 | FileSys::RegisteredCache* GetUserNANDContents(); | 54 | FileSys::RegisteredCache* GetUserNANDContents(); |
| 54 | FileSys::RegisteredCache* GetSDMCContents(); | 55 | FileSys::RegisteredCache* GetSDMCContents(); |
| 55 | 56 | ||
| 56 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); | 57 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); |
| 58 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id); | ||
| 57 | 59 | ||
| 58 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function | 60 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function |
| 59 | // above is called. | 61 | // above is called. |
| @@ -111,6 +113,18 @@ public: | |||
| 111 | ResultCode DeleteDirectoryRecursively(const std::string& path) const; | 113 | ResultCode DeleteDirectoryRecursively(const std::string& path) const; |
| 112 | 114 | ||
| 113 | /** | 115 | /** |
| 116 | * Cleans the specified directory. This is similar to DeleteDirectoryRecursively, | ||
| 117 | * in that it deletes all the contents of the specified directory, however, this | ||
| 118 | * function does *not* delete the directory itself. It only deletes everything | ||
| 119 | * within it. | ||
| 120 | * | ||
| 121 | * @param path Path relative to the archive. | ||
| 122 | * | ||
| 123 | * @return Result of the operation. | ||
| 124 | */ | ||
| 125 | ResultCode CleanDirectoryRecursively(const std::string& path) const; | ||
| 126 | |||
| 127 | /** | ||
| 114 | * Rename a File specified by its path | 128 | * Rename a File specified by its path |
| 115 | * @param src_path Source path relative to the archive | 129 | * @param src_path Source path relative to the archive |
| 116 | * @param dest_path Destination path relative to the archive | 130 | * @param dest_path Destination path relative to the archive |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f06bb33ae..d2ffd5776 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/hex_util.h" | ||
| 14 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 15 | #include "common/string_util.h" | 16 | #include "common/string_util.h" |
| 16 | #include "core/file_sys/directory.h" | 17 | #include "core/file_sys/directory.h" |
| @@ -62,13 +63,15 @@ private: | |||
| 62 | 63 | ||
| 63 | // Error checking | 64 | // Error checking |
| 64 | if (length < 0) { | 65 | if (length < 0) { |
| 66 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | 67 | IPC::ResponseBuilder rb{ctx, 2}; |
| 66 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | 68 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 67 | return; | 69 | return; |
| 68 | } | 70 | } |
| 69 | if (offset < 0) { | 71 | if (offset < 0) { |
| 72 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 70 | IPC::ResponseBuilder rb{ctx, 2}; | 73 | IPC::ResponseBuilder rb{ctx, 2}; |
| 71 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); | 74 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 72 | return; | 75 | return; |
| 73 | } | 76 | } |
| 74 | 77 | ||
| @@ -107,13 +110,15 @@ private: | |||
| 107 | 110 | ||
| 108 | // Error checking | 111 | // Error checking |
| 109 | if (length < 0) { | 112 | if (length < 0) { |
| 113 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 110 | IPC::ResponseBuilder rb{ctx, 2}; | 114 | IPC::ResponseBuilder rb{ctx, 2}; |
| 111 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | 115 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 112 | return; | 116 | return; |
| 113 | } | 117 | } |
| 114 | if (offset < 0) { | 118 | if (offset < 0) { |
| 119 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 120 | IPC::ResponseBuilder rb{ctx, 2}; |
| 116 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); | 121 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 117 | return; | 122 | return; |
| 118 | } | 123 | } |
| 119 | 124 | ||
| @@ -138,13 +143,15 @@ private: | |||
| 138 | 143 | ||
| 139 | // Error checking | 144 | // Error checking |
| 140 | if (length < 0) { | 145 | if (length < 0) { |
| 146 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | 147 | IPC::ResponseBuilder rb{ctx, 2}; |
| 142 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | 148 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 143 | return; | 149 | return; |
| 144 | } | 150 | } |
| 145 | if (offset < 0) { | 151 | if (offset < 0) { |
| 152 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 146 | IPC::ResponseBuilder rb{ctx, 2}; | 153 | IPC::ResponseBuilder rb{ctx, 2}; |
| 147 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); | 154 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 148 | return; | 155 | return; |
| 149 | } | 156 | } |
| 150 | 157 | ||
| @@ -180,9 +187,10 @@ private: | |||
| 180 | void SetSize(Kernel::HLERequestContext& ctx) { | 187 | void SetSize(Kernel::HLERequestContext& ctx) { |
| 181 | IPC::RequestParser rp{ctx}; | 188 | IPC::RequestParser rp{ctx}; |
| 182 | const u64 size = rp.Pop<u64>(); | 189 | const u64 size = rp.Pop<u64>(); |
| 183 | backend->Resize(size); | ||
| 184 | LOG_DEBUG(Service_FS, "called, size={}", size); | 190 | LOG_DEBUG(Service_FS, "called, size={}", size); |
| 185 | 191 | ||
| 192 | backend->Resize(size); | ||
| 193 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2}; | 194 | IPC::ResponseBuilder rb{ctx, 2}; |
| 187 | rb.Push(RESULT_SUCCESS); | 195 | rb.Push(RESULT_SUCCESS); |
| 188 | } | 196 | } |
| @@ -284,7 +292,7 @@ public: | |||
| 284 | {10, &IFileSystem::Commit, "Commit"}, | 292 | {10, &IFileSystem::Commit, "Commit"}, |
| 285 | {11, nullptr, "GetFreeSpaceSize"}, | 293 | {11, nullptr, "GetFreeSpaceSize"}, |
| 286 | {12, nullptr, "GetTotalSpaceSize"}, | 294 | {12, nullptr, "GetTotalSpaceSize"}, |
| 287 | {13, nullptr, "CleanDirectoryRecursively"}, | 295 | {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, |
| 288 | {14, nullptr, "GetFileTimeStampRaw"}, | 296 | {14, nullptr, "GetFileTimeStampRaw"}, |
| 289 | {15, nullptr, "QueryEntry"}, | 297 | {15, nullptr, "QueryEntry"}, |
| 290 | }; | 298 | }; |
| @@ -354,6 +362,16 @@ public: | |||
| 354 | rb.Push(backend.DeleteDirectoryRecursively(name)); | 362 | rb.Push(backend.DeleteDirectoryRecursively(name)); |
| 355 | } | 363 | } |
| 356 | 364 | ||
| 365 | void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) { | ||
| 366 | const auto file_buffer = ctx.ReadBuffer(); | ||
| 367 | const std::string name = Common::StringFromBuffer(file_buffer); | ||
| 368 | |||
| 369 | LOG_DEBUG(Service_FS, "called. Directory: {}", name); | ||
| 370 | |||
| 371 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 372 | rb.Push(backend.CleanDirectoryRecursively(name)); | ||
| 373 | } | ||
| 374 | |||
| 357 | void RenameFile(Kernel::HLERequestContext& ctx) { | 375 | void RenameFile(Kernel::HLERequestContext& ctx) { |
| 358 | IPC::RequestParser rp{ctx}; | 376 | IPC::RequestParser rp{ctx}; |
| 359 | 377 | ||
| @@ -452,7 +470,149 @@ private: | |||
| 452 | VfsDirectoryServiceWrapper backend; | 470 | VfsDirectoryServiceWrapper backend; |
| 453 | }; | 471 | }; |
| 454 | 472 | ||
| 473 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | ||
| 474 | public: | ||
| 475 | explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) | ||
| 476 | : ServiceFramework("ISaveDataInfoReader") { | ||
| 477 | static const FunctionInfo functions[] = { | ||
| 478 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, | ||
| 479 | }; | ||
| 480 | RegisterHandlers(functions); | ||
| 481 | |||
| 482 | FindAllSaves(space); | ||
| 483 | } | ||
| 484 | |||
| 485 | void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { | ||
| 486 | LOG_DEBUG(Service_FS, "called"); | ||
| 487 | |||
| 488 | // Calculate how many entries we can fit in the output buffer | ||
| 489 | const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); | ||
| 490 | |||
| 491 | // Cap at total number of entries. | ||
| 492 | const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); | ||
| 493 | |||
| 494 | // Determine data start and end | ||
| 495 | const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index); | ||
| 496 | const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries); | ||
| 497 | const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); | ||
| 498 | |||
| 499 | next_entry_index += actual_entries; | ||
| 500 | |||
| 501 | // Write the data to memory | ||
| 502 | ctx.WriteBuffer(begin, range_size); | ||
| 503 | |||
| 504 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 505 | rb.Push(RESULT_SUCCESS); | ||
| 506 | rb.Push<u32>(static_cast<u32>(actual_entries)); | ||
| 507 | } | ||
| 508 | |||
| 509 | private: | ||
| 510 | static u64 stoull_be(std::string_view str) { | ||
| 511 | if (str.size() != 16) | ||
| 512 | return 0; | ||
| 513 | |||
| 514 | const auto bytes = Common::HexStringToArray<0x8>(str); | ||
| 515 | u64 out{}; | ||
| 516 | std::memcpy(&out, bytes.data(), sizeof(u64)); | ||
| 517 | |||
| 518 | return Common::swap64(out); | ||
| 519 | } | ||
| 520 | |||
| 521 | void FindAllSaves(FileSys::SaveDataSpaceId space) { | ||
| 522 | const auto save_root = OpenSaveDataSpace(space); | ||
| 523 | ASSERT(save_root.Succeeded()); | ||
| 524 | |||
| 525 | for (const auto& type : (*save_root)->GetSubdirectories()) { | ||
| 526 | if (type->GetName() == "save") { | ||
| 527 | for (const auto& save_id : type->GetSubdirectories()) { | ||
| 528 | for (const auto& user_id : save_id->GetSubdirectories()) { | ||
| 529 | const auto save_id_numeric = stoull_be(save_id->GetName()); | ||
| 530 | auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); | ||
| 531 | std::reverse(user_id_numeric.begin(), user_id_numeric.end()); | ||
| 532 | |||
| 533 | if (save_id_numeric != 0) { | ||
| 534 | // System Save Data | ||
| 535 | info.emplace_back(SaveDataInfo{ | ||
| 536 | 0, | ||
| 537 | space, | ||
| 538 | FileSys::SaveDataType::SystemSaveData, | ||
| 539 | {}, | ||
| 540 | user_id_numeric, | ||
| 541 | save_id_numeric, | ||
| 542 | 0, | ||
| 543 | user_id->GetSize(), | ||
| 544 | {}, | ||
| 545 | }); | ||
| 546 | |||
| 547 | continue; | ||
| 548 | } | ||
| 549 | |||
| 550 | for (const auto& title_id : user_id->GetSubdirectories()) { | ||
| 551 | const auto device = | ||
| 552 | std::all_of(user_id_numeric.begin(), user_id_numeric.end(), | ||
| 553 | [](u8 val) { return val == 0; }); | ||
| 554 | info.emplace_back(SaveDataInfo{ | ||
| 555 | 0, | ||
| 556 | space, | ||
| 557 | device ? FileSys::SaveDataType::DeviceSaveData | ||
| 558 | : FileSys::SaveDataType::SaveData, | ||
| 559 | {}, | ||
| 560 | user_id_numeric, | ||
| 561 | save_id_numeric, | ||
| 562 | stoull_be(title_id->GetName()), | ||
| 563 | title_id->GetSize(), | ||
| 564 | {}, | ||
| 565 | }); | ||
| 566 | } | ||
| 567 | } | ||
| 568 | } | ||
| 569 | } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { | ||
| 570 | // Temporary Storage | ||
| 571 | for (const auto& user_id : type->GetSubdirectories()) { | ||
| 572 | for (const auto& title_id : user_id->GetSubdirectories()) { | ||
| 573 | if (!title_id->GetFiles().empty() || | ||
| 574 | !title_id->GetSubdirectories().empty()) { | ||
| 575 | auto user_id_numeric = | ||
| 576 | Common::HexStringToArray<0x10>(user_id->GetName()); | ||
| 577 | std::reverse(user_id_numeric.begin(), user_id_numeric.end()); | ||
| 578 | |||
| 579 | info.emplace_back(SaveDataInfo{ | ||
| 580 | 0, | ||
| 581 | space, | ||
| 582 | FileSys::SaveDataType::TemporaryStorage, | ||
| 583 | {}, | ||
| 584 | user_id_numeric, | ||
| 585 | stoull_be(type->GetName()), | ||
| 586 | stoull_be(title_id->GetName()), | ||
| 587 | title_id->GetSize(), | ||
| 588 | {}, | ||
| 589 | }); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | } | ||
| 593 | } | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | struct SaveDataInfo { | ||
| 598 | u64_le save_id_unknown; | ||
| 599 | FileSys::SaveDataSpaceId space; | ||
| 600 | FileSys::SaveDataType type; | ||
| 601 | INSERT_PADDING_BYTES(0x6); | ||
| 602 | std::array<u8, 0x10> user_id; | ||
| 603 | u64_le save_id; | ||
| 604 | u64_le title_id; | ||
| 605 | u64_le save_image_size; | ||
| 606 | INSERT_PADDING_BYTES(0x28); | ||
| 607 | }; | ||
| 608 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); | ||
| 609 | |||
| 610 | std::vector<SaveDataInfo> info; | ||
| 611 | u64 next_entry_index = 0; | ||
| 612 | }; | ||
| 613 | |||
| 455 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | 614 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { |
| 615 | // clang-format off | ||
| 456 | static const FunctionInfo functions[] = { | 616 | static const FunctionInfo functions[] = { |
| 457 | {0, nullptr, "MountContent"}, | 617 | {0, nullptr, "MountContent"}, |
| 458 | {1, &FSP_SRV::Initialize, "Initialize"}, | 618 | {1, &FSP_SRV::Initialize, "Initialize"}, |
| @@ -486,7 +646,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 486 | {58, nullptr, "ReadSaveDataFileSystemExtraData"}, | 646 | {58, nullptr, "ReadSaveDataFileSystemExtraData"}, |
| 487 | {59, nullptr, "WriteSaveDataFileSystemExtraData"}, | 647 | {59, nullptr, "WriteSaveDataFileSystemExtraData"}, |
| 488 | {60, nullptr, "OpenSaveDataInfoReader"}, | 648 | {60, nullptr, "OpenSaveDataInfoReader"}, |
| 489 | {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, | 649 | {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, |
| 490 | {62, nullptr, "OpenCacheStorageList"}, | 650 | {62, nullptr, "OpenCacheStorageList"}, |
| 491 | {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, | 651 | {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, |
| 492 | {65, nullptr, "UpdateSaveDataMacForDebug"}, | 652 | {65, nullptr, "UpdateSaveDataMacForDebug"}, |
| @@ -545,6 +705,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | |||
| 545 | {1009, nullptr, "GetAndClearMemoryReportInfo"}, | 705 | {1009, nullptr, "GetAndClearMemoryReportInfo"}, |
| 546 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, | 706 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, |
| 547 | }; | 707 | }; |
| 708 | // clang-format on | ||
| 548 | RegisterHandlers(functions); | 709 | RegisterHandlers(functions); |
| 549 | } | 710 | } |
| 550 | 711 | ||
| @@ -562,6 +723,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { | |||
| 562 | 723 | ||
| 563 | const auto type = rp.PopRaw<FileSystemType>(); | 724 | const auto type = rp.PopRaw<FileSystemType>(); |
| 564 | const auto title_id = rp.PopRaw<u64>(); | 725 | const auto title_id = rp.PopRaw<u64>(); |
| 726 | LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", | ||
| 727 | static_cast<u8>(type), title_id); | ||
| 565 | 728 | ||
| 566 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 729 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 567 | rb.Push(ResultCode(-1)); | 730 | rb.Push(ResultCode(-1)); |
| @@ -597,13 +760,14 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | |||
| 597 | auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); | 760 | auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); |
| 598 | auto unk = rp.Pop<u32>(); | 761 | auto unk = rp.Pop<u32>(); |
| 599 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); | 762 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); |
| 763 | |||
| 600 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); | 764 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); |
| 601 | 765 | ||
| 602 | auto dir = OpenSaveData(space_id, save_struct); | 766 | auto dir = OpenSaveData(space_id, save_struct); |
| 603 | 767 | ||
| 604 | if (dir.Failed()) { | 768 | if (dir.Failed()) { |
| 605 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 769 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 606 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); | 770 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); |
| 607 | return; | 771 | return; |
| 608 | } | 772 | } |
| 609 | 773 | ||
| @@ -619,6 +783,16 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 619 | MountSaveData(ctx); | 783 | MountSaveData(ctx); |
| 620 | } | 784 | } |
| 621 | 785 | ||
| 786 | void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { | ||
| 787 | IPC::RequestParser rp{ctx}; | ||
| 788 | const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); | ||
| 789 | LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space)); | ||
| 790 | |||
| 791 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 792 | rb.Push(RESULT_SUCCESS); | ||
| 793 | rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space)); | ||
| 794 | } | ||
| 795 | |||
| 622 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 796 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| 623 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 797 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 624 | 798 | ||
| @@ -695,7 +869,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { | |||
| 695 | static_cast<u8>(storage_id), title_id); | 869 | static_cast<u8>(storage_id), title_id); |
| 696 | 870 | ||
| 697 | IPC::ResponseBuilder rb{ctx, 2}; | 871 | IPC::ResponseBuilder rb{ctx, 2}; |
| 698 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); | 872 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); |
| 699 | } | 873 | } |
| 700 | 874 | ||
| 701 | } // namespace Service::FileSystem | 875 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4aa0358cb..e7abec0a3 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -25,6 +25,7 @@ private: | |||
| 25 | void CreateSaveData(Kernel::HLERequestContext& ctx); | 25 | void CreateSaveData(Kernel::HLERequestContext& ctx); |
| 26 | void MountSaveData(Kernel::HLERequestContext& ctx); | 26 | void MountSaveData(Kernel::HLERequestContext& ctx); |
| 27 | void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); | 27 | void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); |
| 28 | void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); | ||
| 28 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); | 29 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); |
| 29 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 30 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 30 | void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); | 31 | void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 3d100763f..c22357d8c 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -6,9 +6,14 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hle/service/hid/controllers/debug_pad.h" | 8 | #include "core/hle/service/hid/controllers/debug_pad.h" |
| 9 | #include "core/settings.h" | ||
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
| 11 | 12 | ||
| 13 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | ||
| 14 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | ||
| 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | ||
| 16 | |||
| 12 | Controller_DebugPad::Controller_DebugPad() = default; | 17 | Controller_DebugPad::Controller_DebugPad() = default; |
| 13 | Controller_DebugPad::~Controller_DebugPad() = default; | 18 | Controller_DebugPad::~Controller_DebugPad() = default; |
| 14 | 19 | ||
| @@ -33,10 +38,44 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { | |||
| 33 | 38 | ||
| 34 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 39 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 35 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 40 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 36 | // TODO(ogniK): Update debug pad states | 41 | cur_entry.attribute.connected.Assign(1); |
| 42 | auto& pad = cur_entry.pad_state; | ||
| 43 | |||
| 44 | using namespace Settings::NativeButton; | ||
| 45 | pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 46 | pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 47 | pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 48 | pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 49 | pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 50 | pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 51 | pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 52 | pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 53 | pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 54 | pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 55 | pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 56 | pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 57 | pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 58 | pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 59 | |||
| 60 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 61 | analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 62 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 63 | analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 64 | cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 65 | cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 66 | cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 67 | cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 37 | 68 | ||
| 38 | std::memcpy(data, &shared_memory, sizeof(SharedMemory)); | 69 | std::memcpy(data, &shared_memory, sizeof(SharedMemory)); |
| 39 | } | 70 | } |
| 40 | 71 | ||
| 41 | void Controller_DebugPad::OnLoadInputDevices() {} | 72 | void Controller_DebugPad::OnLoadInputDevices() { |
| 73 | std::transform(Settings::values.debug_pad_buttons.begin(), | ||
| 74 | Settings::values.debug_pad_buttons.begin() + | ||
| 75 | Settings::NativeButton::NUM_BUTTONS_HID, | ||
| 76 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 77 | std::transform(Settings::values.debug_pad_analogs.begin(), | ||
| 78 | Settings::values.debug_pad_analogs.end(), analogs.begin(), | ||
| 79 | Input::CreateDevice<Input::AnalogDevice>); | ||
| 80 | } | ||
| 42 | } // namespace Service::HID | 81 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 62b4f2682..68b734248 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h | |||
| @@ -5,10 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/frontend/input.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | 13 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 14 | #include "core/settings.h" | ||
| 12 | 15 | ||
| 13 | namespace Service::HID { | 16 | namespace Service::HID { |
| 14 | class Controller_DebugPad final : public ControllerBase { | 17 | class Controller_DebugPad final : public ControllerBase { |
| @@ -35,11 +38,40 @@ private: | |||
| 35 | }; | 38 | }; |
| 36 | static_assert(sizeof(AnalogStick) == 0x8); | 39 | static_assert(sizeof(AnalogStick) == 0x8); |
| 37 | 40 | ||
| 41 | struct PadState { | ||
| 42 | union { | ||
| 43 | u32_le raw{}; | ||
| 44 | BitField<0, 1, u32_le> a; | ||
| 45 | BitField<1, 1, u32_le> b; | ||
| 46 | BitField<2, 1, u32_le> x; | ||
| 47 | BitField<3, 1, u32_le> y; | ||
| 48 | BitField<4, 1, u32_le> l; | ||
| 49 | BitField<5, 1, u32_le> r; | ||
| 50 | BitField<6, 1, u32_le> zl; | ||
| 51 | BitField<7, 1, u32_le> zr; | ||
| 52 | BitField<8, 1, u32_le> plus; | ||
| 53 | BitField<9, 1, u32_le> minus; | ||
| 54 | BitField<10, 1, u32_le> d_left; | ||
| 55 | BitField<11, 1, u32_le> d_up; | ||
| 56 | BitField<12, 1, u32_le> d_right; | ||
| 57 | BitField<13, 1, u32_le> d_down; | ||
| 58 | }; | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); | ||
| 61 | |||
| 62 | struct Attributes { | ||
| 63 | union { | ||
| 64 | u32_le raw{}; | ||
| 65 | BitField<0, 1, u32_le> connected; | ||
| 66 | }; | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 69 | |||
| 38 | struct PadStates { | 70 | struct PadStates { |
| 39 | s64_le sampling_number; | 71 | s64_le sampling_number; |
| 40 | s64_le sampling_number2; | 72 | s64_le sampling_number2; |
| 41 | u32_le attribute; | 73 | Attributes attribute; |
| 42 | u32_le button_state; | 74 | PadState pad_state; |
| 43 | AnalogStick r_stick; | 75 | AnalogStick r_stick; |
| 44 | AnalogStick l_stick; | 76 | AnalogStick l_stick; |
| 45 | }; | 77 | }; |
| @@ -52,5 +84,10 @@ private: | |||
| 52 | }; | 84 | }; |
| 53 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | 85 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); |
| 54 | SharedMemory shared_memory{}; | 86 | SharedMemory shared_memory{}; |
| 87 | |||
| 88 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | ||
| 89 | buttons; | ||
| 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> | ||
| 91 | analogs; | ||
| 55 | }; | 92 | }; |
| 56 | } // namespace Service::HID | 93 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index ccfbce9ac..ca75adc2b 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -6,9 +6,11 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hle/service/hid/controllers/keyboard.h" | 8 | #include "core/hle/service/hid/controllers/keyboard.h" |
| 9 | #include "core/settings.h" | ||
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; |
| 13 | constexpr u8 KEYS_PER_BYTE = 8; | ||
| 12 | 14 | ||
| 13 | Controller_Keyboard::Controller_Keyboard() = default; | 15 | Controller_Keyboard::Controller_Keyboard() = default; |
| 14 | Controller_Keyboard::~Controller_Keyboard() = default; | 16 | Controller_Keyboard::~Controller_Keyboard() = default; |
| @@ -34,10 +36,24 @@ void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { | |||
| 34 | 36 | ||
| 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 37 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 38 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 37 | // TODO(ogniK): Update keyboard states | 39 | |
| 40 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { | ||
| 41 | for (std::size_t k = 0; k < KEYS_PER_BYTE; ++k) { | ||
| 42 | cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << k); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { | ||
| 47 | cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i); | ||
| 48 | } | ||
| 38 | 49 | ||
| 39 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 50 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
| 40 | } | 51 | } |
| 41 | 52 | ||
| 42 | void Controller_Keyboard::OnLoadInputDevices() {} | 53 | void Controller_Keyboard::OnLoadInputDevices() { |
| 54 | std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), | ||
| 55 | keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 56 | std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), | ||
| 57 | keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 58 | } | ||
| 43 | } // namespace Service::HID | 59 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 493e68fce..f52775456 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -8,7 +8,9 @@ | |||
| 8 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.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/frontend/input.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/settings.h" | ||
| 12 | 14 | ||
| 13 | namespace Service::HID { | 15 | namespace Service::HID { |
| 14 | class Controller_Keyboard final : public ControllerBase { | 16 | class Controller_Keyboard final : public ControllerBase { |
| @@ -46,5 +48,10 @@ private: | |||
| 46 | }; | 48 | }; |
| 47 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | 49 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); |
| 48 | SharedMemory shared_memory{}; | 50 | SharedMemory shared_memory{}; |
| 51 | |||
| 52 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys> | ||
| 53 | keyboard_keys; | ||
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> | ||
| 55 | keyboard_mods; | ||
| 49 | }; | 56 | }; |
| 50 | } // namespace Service::HID | 57 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 4e246a57d..63391dbe9 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/frontend/emu_window.h" | ||
| 8 | #include "core/hle/service/hid/controllers/mouse.h" | 9 | #include "core/hle/service/hid/controllers/mouse.h" |
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
| @@ -14,7 +15,6 @@ Controller_Mouse::Controller_Mouse() = default; | |||
| 14 | Controller_Mouse::~Controller_Mouse() = default; | 15 | Controller_Mouse::~Controller_Mouse() = default; |
| 15 | 16 | ||
| 16 | void Controller_Mouse::OnInit() {} | 17 | void Controller_Mouse::OnInit() {} |
| 17 | |||
| 18 | void Controller_Mouse::OnRelease() {} | 18 | void Controller_Mouse::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { | 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { |
| @@ -34,10 +34,29 @@ void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { | |||
| 34 | 34 | ||
| 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 35 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 36 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 37 | // TODO(ogniK): Update mouse states | 37 | |
| 38 | if (Settings::values.mouse_enabled) { | ||
| 39 | const auto [px, py, sx, sy] = mouse_device->GetStatus(); | ||
| 40 | const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); | ||
| 41 | const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height); | ||
| 42 | cur_entry.x = x; | ||
| 43 | cur_entry.y = y; | ||
| 44 | cur_entry.delta_x = x - last_entry.x; | ||
| 45 | cur_entry.delta_y = y - last_entry.y; | ||
| 46 | cur_entry.mouse_wheel_x = sx; | ||
| 47 | cur_entry.mouse_wheel_y = sy; | ||
| 48 | |||
| 49 | for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) { | ||
| 50 | cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i); | ||
| 51 | } | ||
| 52 | } | ||
| 38 | 53 | ||
| 39 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 54 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
| 40 | } | 55 | } |
| 41 | 56 | ||
| 42 | void Controller_Mouse::OnLoadInputDevices() {} | 57 | void Controller_Mouse::OnLoadInputDevices() { |
| 58 | mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device); | ||
| 59 | std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), | ||
| 60 | mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 61 | } | ||
| 43 | } // namespace Service::HID | 62 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 543b0b71f..70b654d07 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/swap.h" | 9 | #include "common/swap.h" |
| 10 | #include "core/frontend/input.h" | ||
| 10 | #include "core/hle/service/hid/controllers/controller_base.h" | 11 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 12 | #include "core/settings.h" | ||
| 11 | 13 | ||
| 12 | namespace Service::HID { | 14 | namespace Service::HID { |
| 13 | class Controller_Mouse final : public ControllerBase { | 15 | class Controller_Mouse final : public ControllerBase { |
| @@ -35,7 +37,8 @@ private: | |||
| 35 | s32_le y; | 37 | s32_le y; |
| 36 | s32_le delta_x; | 38 | s32_le delta_x; |
| 37 | s32_le delta_y; | 39 | s32_le delta_y; |
| 38 | s32_le mouse_wheel; | 40 | s32_le mouse_wheel_x; |
| 41 | s32_le mouse_wheel_y; | ||
| 39 | s32_le button; | 42 | s32_le button; |
| 40 | s32_le attribute; | 43 | s32_le attribute; |
| 41 | }; | 44 | }; |
| @@ -46,5 +49,9 @@ private: | |||
| 46 | std::array<MouseState, 17> mouse_states; | 49 | std::array<MouseState, 17> mouse_states; |
| 47 | }; | 50 | }; |
| 48 | SharedMemory shared_memory{}; | 51 | SharedMemory shared_memory{}; |
| 52 | |||
| 53 | std::unique_ptr<Input::MouseDevice> mouse_device; | ||
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> | ||
| 55 | mouse_button_devices; | ||
| 49 | }; | 56 | }; |
| 50 | } // namespace Service::HID | 57 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ff9b64be4..d6829d0b8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -12,27 +12,20 @@ | |||
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 14 | #include "core/frontend/input.h" | 14 | #include "core/frontend/input.h" |
| 15 | #include "core/hle/kernel/event.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/readable_event.h" | ||
| 17 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/service/hid/controllers/npad.h" | 18 | #include "core/hle/service/hid/controllers/npad.h" |
| 17 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| 18 | 20 | ||
| 19 | namespace Service::HID { | 21 | namespace Service::HID { |
| 20 | |||
| 21 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; | ||
| 22 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; | ||
| 23 | constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; | ||
| 24 | constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; | ||
| 25 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | 22 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; |
| 26 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 23 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
| 27 | constexpr std::size_t NPAD_OFFSET = 0x9A00; | 24 | constexpr std::size_t NPAD_OFFSET = 0x9A00; |
| 28 | constexpr u32 BATTERY_FULL = 2; | 25 | constexpr u32 BATTERY_FULL = 2; |
| 29 | constexpr u32 NPAD_HANDHELD = 32; | ||
| 30 | constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? | ||
| 31 | constexpr u32 MAX_NPAD_ID = 7; | 26 | constexpr u32 MAX_NPAD_ID = 7; |
| 32 | constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER = | ||
| 33 | Controller_NPad::NPadControllerType::JoyDual; | ||
| 34 | constexpr std::array<u32, 10> npad_id_list{ | 27 | constexpr std::array<u32, 10> npad_id_list{ |
| 35 | 0, 1, 2, 3, 4, 5, 6, 7, 32, 16, | 28 | 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, |
| 36 | }; | 29 | }; |
| 37 | 30 | ||
| 38 | enum class JoystickId : std::size_t { | 31 | enum class JoystickId : std::size_t { |
| @@ -40,6 +33,66 @@ enum class JoystickId : std::size_t { | |||
| 40 | Joystick_Right, | 33 | Joystick_Right, |
| 41 | }; | 34 | }; |
| 42 | 35 | ||
| 36 | static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) { | ||
| 37 | switch (type) { | ||
| 38 | case Settings::ControllerType::ProController: | ||
| 39 | return Controller_NPad::NPadControllerType::ProController; | ||
| 40 | case Settings::ControllerType::DualJoycon: | ||
| 41 | return Controller_NPad::NPadControllerType::JoyDual; | ||
| 42 | case Settings::ControllerType::LeftJoycon: | ||
| 43 | return Controller_NPad::NPadControllerType::JoyLeft; | ||
| 44 | case Settings::ControllerType::RightJoycon: | ||
| 45 | return Controller_NPad::NPadControllerType::JoyRight; | ||
| 46 | default: | ||
| 47 | UNREACHABLE(); | ||
| 48 | return Controller_NPad::NPadControllerType::JoyDual; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { | ||
| 53 | switch (npad_id) { | ||
| 54 | case 0: | ||
| 55 | case 1: | ||
| 56 | case 2: | ||
| 57 | case 3: | ||
| 58 | case 4: | ||
| 59 | case 5: | ||
| 60 | case 6: | ||
| 61 | case 7: | ||
| 62 | return npad_id; | ||
| 63 | case 8: | ||
| 64 | case NPAD_HANDHELD: | ||
| 65 | return 8; | ||
| 66 | case 9: | ||
| 67 | case NPAD_UNKNOWN: | ||
| 68 | return 9; | ||
| 69 | default: | ||
| 70 | UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | u32 Controller_NPad::IndexToNPad(std::size_t index) { | ||
| 76 | switch (index) { | ||
| 77 | case 0: | ||
| 78 | case 1: | ||
| 79 | case 2: | ||
| 80 | case 3: | ||
| 81 | case 4: | ||
| 82 | case 5: | ||
| 83 | case 6: | ||
| 84 | case 7: | ||
| 85 | return static_cast<u32>(index); | ||
| 86 | case 8: | ||
| 87 | return NPAD_HANDHELD; | ||
| 88 | case 9: | ||
| 89 | return NPAD_UNKNOWN; | ||
| 90 | default: | ||
| 91 | UNIMPLEMENTED_MSG("Unknown npad index {}", index); | ||
| 92 | return 0; | ||
| 93 | }; | ||
| 94 | } | ||
| 95 | |||
| 43 | Controller_NPad::Controller_NPad() = default; | 96 | Controller_NPad::Controller_NPad() = default; |
| 44 | Controller_NPad::~Controller_NPad() = default; | 97 | Controller_NPad::~Controller_NPad() = default; |
| 45 | 98 | ||
| @@ -56,22 +109,32 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 56 | controller.joy_styles.handheld.Assign(1); | 109 | controller.joy_styles.handheld.Assign(1); |
| 57 | controller.device_type.handheld.Assign(1); | 110 | controller.device_type.handheld.Assign(1); |
| 58 | controller.pad_assignment = NPadAssignments::Dual; | 111 | controller.pad_assignment = NPadAssignments::Dual; |
| 112 | controller.properties.is_vertical.Assign(1); | ||
| 113 | controller.properties.use_plus.Assign(1); | ||
| 114 | controller.properties.use_minus.Assign(1); | ||
| 59 | break; | 115 | break; |
| 60 | case NPadControllerType::JoyDual: | 116 | case NPadControllerType::JoyDual: |
| 61 | controller.joy_styles.joycon_dual.Assign(1); | 117 | controller.joy_styles.joycon_dual.Assign(1); |
| 62 | controller.device_type.joycon_left.Assign(1); | 118 | controller.device_type.joycon_left.Assign(1); |
| 63 | controller.device_type.joycon_right.Assign(1); | 119 | controller.device_type.joycon_right.Assign(1); |
| 120 | controller.properties.is_vertical.Assign(1); | ||
| 121 | controller.properties.use_plus.Assign(1); | ||
| 122 | controller.properties.use_minus.Assign(1); | ||
| 64 | controller.pad_assignment = NPadAssignments::Dual; | 123 | controller.pad_assignment = NPadAssignments::Dual; |
| 65 | break; | 124 | break; |
| 66 | case NPadControllerType::JoyLeft: | 125 | case NPadControllerType::JoyLeft: |
| 67 | controller.joy_styles.joycon_left.Assign(1); | 126 | controller.joy_styles.joycon_left.Assign(1); |
| 68 | controller.device_type.joycon_left.Assign(1); | 127 | controller.device_type.joycon_left.Assign(1); |
| 69 | controller.pad_assignment = NPadAssignments::Dual; | 128 | controller.properties.is_horizontal.Assign(1); |
| 129 | controller.properties.use_minus.Assign(1); | ||
| 130 | controller.pad_assignment = NPadAssignments::Single; | ||
| 70 | break; | 131 | break; |
| 71 | case NPadControllerType::JoyRight: | 132 | case NPadControllerType::JoyRight: |
| 72 | controller.joy_styles.joycon_right.Assign(1); | 133 | controller.joy_styles.joycon_right.Assign(1); |
| 73 | controller.device_type.joycon_right.Assign(1); | 134 | controller.device_type.joycon_right.Assign(1); |
| 74 | controller.pad_assignment = NPadAssignments::Dual; | 135 | controller.properties.is_horizontal.Assign(1); |
| 136 | controller.properties.use_plus.Assign(1); | ||
| 137 | controller.pad_assignment = NPadAssignments::Single; | ||
| 75 | break; | 138 | break; |
| 76 | case NPadControllerType::Pokeball: | 139 | case NPadControllerType::Pokeball: |
| 77 | controller.joy_styles.pokeball.Assign(1); | 140 | controller.joy_styles.pokeball.Assign(1); |
| @@ -81,6 +144,9 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 81 | case NPadControllerType::ProController: | 144 | case NPadControllerType::ProController: |
| 82 | controller.joy_styles.pro_controller.Assign(1); | 145 | controller.joy_styles.pro_controller.Assign(1); |
| 83 | controller.device_type.pro_controller.Assign(1); | 146 | controller.device_type.pro_controller.Assign(1); |
| 147 | controller.properties.is_vertical.Assign(1); | ||
| 148 | controller.properties.use_plus.Assign(1); | ||
| 149 | controller.properties.use_minus.Assign(1); | ||
| 84 | controller.pad_assignment = NPadAssignments::Single; | 150 | controller.pad_assignment = NPadAssignments::Single; |
| 85 | break; | 151 | break; |
| 86 | } | 152 | } |
| @@ -90,14 +156,12 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 90 | controller.single_color.button_color = 0; | 156 | controller.single_color.button_color = 0; |
| 91 | 157 | ||
| 92 | controller.dual_color_error = ColorReadError::ReadOk; | 158 | controller.dual_color_error = ColorReadError::ReadOk; |
| 93 | controller.left_color.body_color = JOYCON_BODY_NEON_BLUE; | 159 | controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left; |
| 94 | controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE; | 160 | controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left; |
| 95 | controller.right_color.body_color = JOYCON_BODY_NEON_RED; | 161 | controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right; |
| 96 | controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; | 162 | controller.right_color.button_color = |
| 97 | 163 | Settings::values.players[controller_idx].button_color_right; | |
| 98 | controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations | 164 | |
| 99 | controller.properties.use_plus.Assign(1); | ||
| 100 | controller.properties.use_minus.Assign(1); | ||
| 101 | controller.battery_level[0] = BATTERY_FULL; | 165 | controller.battery_level[0] = BATTERY_FULL; |
| 102 | controller.battery_level[1] = BATTERY_FULL; | 166 | controller.battery_level[1] = BATTERY_FULL; |
| 103 | controller.battery_level[2] = BATTERY_FULL; | 167 | controller.battery_level[2] = BATTERY_FULL; |
| @@ -105,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 105 | 169 | ||
| 106 | void Controller_NPad::OnInit() { | 170 | void Controller_NPad::OnInit() { |
| 107 | auto& kernel = Core::System::GetInstance().Kernel(); | 171 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 108 | styleset_changed_event = | 172 | styleset_changed_event = Kernel::WritableEvent::CreateEventPair( |
| 109 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); | 173 | kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); |
| 110 | 174 | ||
| 111 | if (!IsControllerActivated()) { | 175 | if (!IsControllerActivated()) { |
| 112 | return; | 176 | return; |
| @@ -121,26 +185,109 @@ void Controller_NPad::OnInit() { | |||
| 121 | style.pro_controller.Assign(1); | 185 | style.pro_controller.Assign(1); |
| 122 | style.pokeball.Assign(1); | 186 | style.pokeball.Assign(1); |
| 123 | } | 187 | } |
| 188 | |||
| 189 | std::transform( | ||
| 190 | Settings::values.players.begin(), Settings::values.players.end(), | ||
| 191 | connected_controllers.begin(), [](const Settings::PlayerInput& player) { | ||
| 192 | return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected}; | ||
| 193 | }); | ||
| 194 | |||
| 195 | std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8, | ||
| 196 | [](const ControllerHolder& holder) { return holder.is_connected; }); | ||
| 197 | |||
| 198 | // Account for handheld | ||
| 199 | if (connected_controllers[8].is_connected) | ||
| 200 | connected_controllers[8].type = NPadControllerType::Handheld; | ||
| 201 | |||
| 202 | supported_npad_id_types.resize(npad_id_list.size()); | ||
| 203 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), | ||
| 204 | npad_id_list.size() * sizeof(u32)); | ||
| 205 | |||
| 206 | // Add a default dual joycon controller if none are present. | ||
| 124 | if (std::none_of(connected_controllers.begin(), connected_controllers.end(), | 207 | if (std::none_of(connected_controllers.begin(), connected_controllers.end(), |
| 125 | [](const ControllerHolder& controller) { return controller.is_connected; })) { | 208 | [](const ControllerHolder& controller) { return controller.is_connected; })) { |
| 126 | supported_npad_id_types.resize(npad_id_list.size()); | 209 | supported_npad_id_types.resize(npad_id_list.size()); |
| 127 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), | 210 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), |
| 128 | npad_id_list.size() * sizeof(u32)); | 211 | npad_id_list.size() * sizeof(u32)); |
| 129 | AddNewController(PREFERRED_CONTROLLER); | 212 | AddNewController(NPadControllerType::JoyDual); |
| 213 | } | ||
| 214 | |||
| 215 | for (std::size_t i = 0; i < connected_controllers.size(); ++i) { | ||
| 216 | const auto& controller = connected_controllers[i]; | ||
| 217 | if (controller.is_connected) { | ||
| 218 | AddNewControllerAt(controller.type, IndexToNPad(i)); | ||
| 219 | } | ||
| 130 | } | 220 | } |
| 131 | } | 221 | } |
| 132 | 222 | ||
| 133 | void Controller_NPad::OnLoadInputDevices() { | 223 | void Controller_NPad::OnLoadInputDevices() { |
| 134 | std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | 224 | const auto& players = Settings::values.players; |
| 135 | Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | 225 | for (std::size_t i = 0; i < players.size(); ++i) { |
| 136 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | 226 | std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, |
| 137 | std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | 227 | players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, |
| 138 | Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | 228 | buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>); |
| 139 | sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); | 229 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, |
| 230 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | ||
| 231 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); | ||
| 232 | } | ||
| 140 | } | 233 | } |
| 141 | 234 | ||
| 142 | void Controller_NPad::OnRelease() {} | 235 | void Controller_NPad::OnRelease() {} |
| 143 | 236 | ||
| 237 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | ||
| 238 | const auto controller_idx = NPadIdToIndex(npad_id); | ||
| 239 | const auto controller_type = connected_controllers[controller_idx].type; | ||
| 240 | if (!connected_controllers[controller_idx].is_connected) { | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | auto& pad_state = npad_pad_states[controller_idx].pad_states; | ||
| 244 | auto& lstick_entry = npad_pad_states[controller_idx].l_stick; | ||
| 245 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; | ||
| 246 | const auto& button_state = buttons[controller_idx]; | ||
| 247 | const auto& analog_state = sticks[controller_idx]; | ||
| 248 | |||
| 249 | using namespace Settings::NativeButton; | ||
| 250 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 251 | pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 252 | pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 253 | pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 254 | pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 255 | pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 256 | pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 257 | pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 258 | pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 259 | pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 260 | pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 261 | pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 262 | |||
| 263 | pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 264 | pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 265 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 266 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 267 | |||
| 268 | pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 269 | pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 270 | pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 271 | pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 272 | |||
| 273 | pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 274 | pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 275 | pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 276 | pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 277 | |||
| 278 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 279 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 280 | |||
| 281 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 282 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 283 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 284 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 285 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 286 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 287 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 288 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 289 | } | ||
| 290 | |||
| 144 | void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | 291 | void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { |
| 145 | if (!IsControllerActivated()) | 292 | if (!IsControllerActivated()) |
| 146 | return; | 293 | return; |
| @@ -176,97 +323,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||
| 176 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { | 323 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { |
| 177 | continue; | 324 | continue; |
| 178 | } | 325 | } |
| 179 | 326 | const u32 npad_index = static_cast<u32>(i); | |
| 180 | // Pad states | 327 | RequestPadStateUpdate(npad_index); |
| 181 | ControllerPadState pad_state{}; | 328 | auto& pad_state = npad_pad_states[npad_index]; |
| 182 | using namespace Settings::NativeButton; | ||
| 183 | pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 184 | pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 185 | pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 186 | pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 187 | pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 188 | pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 189 | pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 190 | pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 191 | pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 192 | pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 193 | pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 194 | pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 195 | |||
| 196 | pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 197 | pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 198 | pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 199 | pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 200 | |||
| 201 | pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 202 | pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 203 | pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 204 | pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 205 | |||
| 206 | pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 207 | pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 208 | pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 209 | pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 210 | |||
| 211 | pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 212 | pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 213 | |||
| 214 | AnalogPosition lstick_entry{}; | ||
| 215 | AnalogPosition rstick_entry{}; | ||
| 216 | |||
| 217 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 218 | sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 219 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 220 | sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 221 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 222 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 223 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 224 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 225 | |||
| 226 | if (controller_type == NPadControllerType::JoyLeft || | ||
| 227 | controller_type == NPadControllerType::JoyRight) { | ||
| 228 | if (npad.properties.is_horizontal) { | ||
| 229 | ControllerPadState state{}; | ||
| 230 | AnalogPosition temp_lstick_entry{}; | ||
| 231 | AnalogPosition temp_rstick_entry{}; | ||
| 232 | if (controller_type == NPadControllerType::JoyLeft) { | ||
| 233 | state.d_down.Assign(pad_state.d_left.Value()); | ||
| 234 | state.d_left.Assign(pad_state.d_up.Value()); | ||
| 235 | state.d_right.Assign(pad_state.d_down.Value()); | ||
| 236 | state.d_up.Assign(pad_state.d_right.Value()); | ||
| 237 | state.l.Assign(pad_state.l.Value() | pad_state.sl.Value()); | ||
| 238 | state.r.Assign(pad_state.r.Value() | pad_state.sr.Value()); | ||
| 239 | |||
| 240 | state.zl.Assign(pad_state.zl.Value()); | ||
| 241 | state.plus.Assign(pad_state.minus.Value()); | ||
| 242 | |||
| 243 | temp_lstick_entry = lstick_entry; | ||
| 244 | temp_rstick_entry = rstick_entry; | ||
| 245 | std::swap(temp_lstick_entry.x, temp_lstick_entry.y); | ||
| 246 | std::swap(temp_rstick_entry.x, temp_rstick_entry.y); | ||
| 247 | temp_lstick_entry.y *= -1; | ||
| 248 | } else if (controller_type == NPadControllerType::JoyRight) { | ||
| 249 | state.x.Assign(pad_state.a.Value()); | ||
| 250 | state.a.Assign(pad_state.b.Value()); | ||
| 251 | state.b.Assign(pad_state.y.Value()); | ||
| 252 | state.y.Assign(pad_state.b.Value()); | ||
| 253 | |||
| 254 | state.l.Assign(pad_state.l.Value() | pad_state.sl.Value()); | ||
| 255 | state.r.Assign(pad_state.r.Value() | pad_state.sr.Value()); | ||
| 256 | state.zr.Assign(pad_state.zr.Value()); | ||
| 257 | state.plus.Assign(pad_state.plus.Value()); | ||
| 258 | |||
| 259 | temp_lstick_entry = lstick_entry; | ||
| 260 | temp_rstick_entry = rstick_entry; | ||
| 261 | std::swap(temp_lstick_entry.x, temp_lstick_entry.y); | ||
| 262 | std::swap(temp_rstick_entry.x, temp_rstick_entry.y); | ||
| 263 | temp_rstick_entry.x *= -1; | ||
| 264 | } | ||
| 265 | pad_state.raw = state.raw; | ||
| 266 | lstick_entry = temp_lstick_entry; | ||
| 267 | rstick_entry = temp_rstick_entry; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | 329 | ||
| 271 | auto& main_controller = | 330 | auto& main_controller = |
| 272 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; | 331 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; |
| @@ -281,20 +340,64 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||
| 281 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; | 340 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; |
| 282 | 341 | ||
| 283 | if (hold_type == NpadHoldType::Horizontal) { | 342 | if (hold_type == NpadHoldType::Horizontal) { |
| 284 | // TODO(ogniK): Remap buttons for different orientations | 343 | ControllerPadState state{}; |
| 344 | AnalogPosition temp_lstick_entry{}; | ||
| 345 | AnalogPosition temp_rstick_entry{}; | ||
| 346 | if (controller_type == NPadControllerType::JoyLeft) { | ||
| 347 | state.d_down.Assign(pad_state.pad_states.d_left.Value()); | ||
| 348 | state.d_left.Assign(pad_state.pad_states.d_up.Value()); | ||
| 349 | state.d_right.Assign(pad_state.pad_states.d_down.Value()); | ||
| 350 | state.d_up.Assign(pad_state.pad_states.d_right.Value()); | ||
| 351 | state.l.Assign(pad_state.pad_states.l.Value() | | ||
| 352 | pad_state.pad_states.left_sl.Value()); | ||
| 353 | state.r.Assign(pad_state.pad_states.r.Value() | | ||
| 354 | pad_state.pad_states.left_sr.Value()); | ||
| 355 | |||
| 356 | state.zl.Assign(pad_state.pad_states.zl.Value()); | ||
| 357 | state.plus.Assign(pad_state.pad_states.minus.Value()); | ||
| 358 | |||
| 359 | temp_lstick_entry = pad_state.l_stick; | ||
| 360 | temp_rstick_entry = pad_state.r_stick; | ||
| 361 | std::swap(temp_lstick_entry.x, temp_lstick_entry.y); | ||
| 362 | std::swap(temp_rstick_entry.x, temp_rstick_entry.y); | ||
| 363 | temp_lstick_entry.y *= -1; | ||
| 364 | } else if (controller_type == NPadControllerType::JoyRight) { | ||
| 365 | state.x.Assign(pad_state.pad_states.a.Value()); | ||
| 366 | state.a.Assign(pad_state.pad_states.b.Value()); | ||
| 367 | state.b.Assign(pad_state.pad_states.y.Value()); | ||
| 368 | state.y.Assign(pad_state.pad_states.b.Value()); | ||
| 369 | |||
| 370 | state.l.Assign(pad_state.pad_states.l.Value() | | ||
| 371 | pad_state.pad_states.right_sl.Value()); | ||
| 372 | state.r.Assign(pad_state.pad_states.r.Value() | | ||
| 373 | pad_state.pad_states.right_sr.Value()); | ||
| 374 | state.zr.Assign(pad_state.pad_states.zr.Value()); | ||
| 375 | state.plus.Assign(pad_state.pad_states.plus.Value()); | ||
| 376 | |||
| 377 | temp_lstick_entry = pad_state.l_stick; | ||
| 378 | temp_rstick_entry = pad_state.r_stick; | ||
| 379 | std::swap(temp_lstick_entry.x, temp_lstick_entry.y); | ||
| 380 | std::swap(temp_rstick_entry.x, temp_rstick_entry.y); | ||
| 381 | temp_rstick_entry.x *= -1; | ||
| 382 | } | ||
| 383 | pad_state.pad_states.raw = state.raw; | ||
| 384 | pad_state.l_stick = temp_lstick_entry; | ||
| 385 | pad_state.r_stick = temp_rstick_entry; | ||
| 285 | } | 386 | } |
| 387 | |||
| 286 | libnx_entry.connection_status.raw = 0; | 388 | libnx_entry.connection_status.raw = 0; |
| 287 | 389 | ||
| 288 | switch (controller_type) { | 390 | switch (controller_type) { |
| 289 | case NPadControllerType::Handheld: | 391 | case NPadControllerType::Handheld: |
| 290 | handheld_entry.connection_status.raw = 0; | 392 | handheld_entry.connection_status.raw = 0; |
| 291 | handheld_entry.connection_status.IsConnected.Assign(1); | 393 | handheld_entry.connection_status.IsWired.Assign(1); |
| 292 | if (!Settings::values.use_docked_mode) { | 394 | handheld_entry.connection_status.IsLeftJoyConnected.Assign(1); |
| 293 | handheld_entry.connection_status.IsWired.Assign(1); | 395 | handheld_entry.connection_status.IsRightJoyConnected.Assign(1); |
| 294 | } | 396 | handheld_entry.connection_status.IsLeftJoyWired.Assign(1); |
| 295 | handheld_entry.pad_states.raw = pad_state.raw; | 397 | handheld_entry.connection_status.IsRightJoyWired.Assign(1); |
| 296 | handheld_entry.l_stick = lstick_entry; | 398 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 297 | handheld_entry.r_stick = rstick_entry; | 399 | handheld_entry.pad.l_stick = pad_state.l_stick; |
| 400 | handheld_entry.pad.r_stick = pad_state.r_stick; | ||
| 298 | break; | 401 | break; |
| 299 | case NPadControllerType::JoyDual: | 402 | case NPadControllerType::JoyDual: |
| 300 | dual_entry.connection_status.raw = 0; | 403 | dual_entry.connection_status.raw = 0; |
| @@ -307,24 +410,25 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||
| 307 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | 410 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); |
| 308 | libnx_entry.connection_status.IsConnected.Assign(1); | 411 | libnx_entry.connection_status.IsConnected.Assign(1); |
| 309 | 412 | ||
| 310 | dual_entry.pad_states.raw = pad_state.raw; | 413 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 311 | dual_entry.l_stick = lstick_entry; | 414 | dual_entry.pad.l_stick = pad_state.l_stick; |
| 312 | dual_entry.r_stick = rstick_entry; | 415 | dual_entry.pad.r_stick = pad_state.r_stick; |
| 416 | break; | ||
| 313 | case NPadControllerType::JoyLeft: | 417 | case NPadControllerType::JoyLeft: |
| 314 | left_entry.connection_status.raw = 0; | 418 | left_entry.connection_status.raw = 0; |
| 315 | 419 | ||
| 316 | left_entry.connection_status.IsConnected.Assign(1); | 420 | left_entry.connection_status.IsConnected.Assign(1); |
| 317 | left_entry.pad_states.raw = pad_state.raw; | 421 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 318 | left_entry.l_stick = lstick_entry; | 422 | left_entry.pad.l_stick = pad_state.l_stick; |
| 319 | left_entry.r_stick = rstick_entry; | 423 | left_entry.pad.r_stick = pad_state.r_stick; |
| 320 | break; | 424 | break; |
| 321 | case NPadControllerType::JoyRight: | 425 | case NPadControllerType::JoyRight: |
| 322 | right_entry.connection_status.raw = 0; | 426 | right_entry.connection_status.raw = 0; |
| 323 | 427 | ||
| 324 | right_entry.connection_status.IsConnected.Assign(1); | 428 | right_entry.connection_status.IsConnected.Assign(1); |
| 325 | right_entry.pad_states.raw = pad_state.raw; | 429 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 326 | right_entry.l_stick = lstick_entry; | 430 | right_entry.pad.l_stick = pad_state.l_stick; |
| 327 | right_entry.r_stick = rstick_entry; | 431 | right_entry.pad.r_stick = pad_state.r_stick; |
| 328 | break; | 432 | break; |
| 329 | case NPadControllerType::Pokeball: | 433 | case NPadControllerType::Pokeball: |
| 330 | pokeball_entry.connection_status.raw = 0; | 434 | pokeball_entry.connection_status.raw = 0; |
| @@ -332,30 +436,30 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||
| 332 | pokeball_entry.connection_status.IsConnected.Assign(1); | 436 | pokeball_entry.connection_status.IsConnected.Assign(1); |
| 333 | pokeball_entry.connection_status.IsWired.Assign(1); | 437 | pokeball_entry.connection_status.IsWired.Assign(1); |
| 334 | 438 | ||
| 335 | pokeball_entry.pad_states.raw = pad_state.raw; | 439 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 336 | pokeball_entry.l_stick = lstick_entry; | 440 | pokeball_entry.pad.l_stick = pad_state.l_stick; |
| 337 | pokeball_entry.r_stick = rstick_entry; | 441 | pokeball_entry.pad.r_stick = pad_state.r_stick; |
| 338 | break; | 442 | break; |
| 339 | case NPadControllerType::ProController: | 443 | case NPadControllerType::ProController: |
| 340 | main_controller.connection_status.raw = 0; | 444 | main_controller.connection_status.raw = 0; |
| 341 | 445 | ||
| 342 | main_controller.connection_status.IsConnected.Assign(1); | 446 | main_controller.connection_status.IsConnected.Assign(1); |
| 343 | main_controller.connection_status.IsWired.Assign(1); | 447 | main_controller.connection_status.IsWired.Assign(1); |
| 344 | main_controller.pad_states.raw = pad_state.raw; | 448 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; |
| 345 | main_controller.l_stick = lstick_entry; | 449 | main_controller.pad.l_stick = pad_state.l_stick; |
| 346 | main_controller.r_stick = rstick_entry; | 450 | main_controller.pad.r_stick = pad_state.r_stick; |
| 347 | break; | 451 | break; |
| 348 | } | 452 | } |
| 349 | 453 | ||
| 350 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | 454 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate |
| 351 | // any controllers. | 455 | // any controllers. |
| 352 | libnx_entry.pad_states.raw = pad_state.raw; | 456 | libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; |
| 353 | libnx_entry.l_stick = lstick_entry; | 457 | libnx_entry.pad.l_stick = pad_state.l_stick; |
| 354 | libnx_entry.r_stick = rstick_entry; | 458 | libnx_entry.pad.r_stick = pad_state.r_stick; |
| 355 | } | 459 | } |
| 356 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | 460 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), |
| 357 | shared_memory_entries.size() * sizeof(NPadEntry)); | 461 | shared_memory_entries.size() * sizeof(NPadEntry)); |
| 358 | } // namespace Service::HID | 462 | } |
| 359 | 463 | ||
| 360 | void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { | 464 | void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { |
| 361 | style.raw = style_set.raw; | 465 | style.raw = style_set.raw; |
| @@ -370,14 +474,29 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 370 | supported_npad_id_types.clear(); | 474 | supported_npad_id_types.clear(); |
| 371 | supported_npad_id_types.resize(length / sizeof(u32)); | 475 | supported_npad_id_types.resize(length / sizeof(u32)); |
| 372 | std::memcpy(supported_npad_id_types.data(), data, length); | 476 | std::memcpy(supported_npad_id_types.data(), data, length); |
| 477 | bool had_controller_update = false; | ||
| 373 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { | 478 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { |
| 374 | auto& controller = connected_controllers[i]; | 479 | auto& controller = connected_controllers[i]; |
| 375 | if (!controller.is_connected) { | 480 | if (!controller.is_connected) { |
| 376 | continue; | 481 | continue; |
| 377 | } | 482 | } |
| 378 | if (!IsControllerSupported(PREFERRED_CONTROLLER)) { | 483 | const auto requested_controller = |
| 379 | controller.type = DecideBestController(PREFERRED_CONTROLLER); | 484 | i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type) |
| 380 | InitNewlyAddedControler(i); | 485 | : NPadControllerType::Handheld; |
| 486 | if (!IsControllerSupported(requested_controller)) { | ||
| 487 | const auto is_handheld = requested_controller == NPadControllerType::Handheld; | ||
| 488 | if (is_handheld) { | ||
| 489 | controller.type = NPadControllerType::None; | ||
| 490 | controller.is_connected = false; | ||
| 491 | AddNewController(requested_controller); | ||
| 492 | } else { | ||
| 493 | controller.type = requested_controller; | ||
| 494 | InitNewlyAddedControler(i); | ||
| 495 | } | ||
| 496 | had_controller_update = true; | ||
| 497 | } | ||
| 498 | if (had_controller_update) { | ||
| 499 | styleset_changed_event.writable->Signal(); | ||
| 381 | } | 500 | } |
| 382 | } | 501 | } |
| 383 | } | 502 | } |
| @@ -392,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { | |||
| 392 | } | 511 | } |
| 393 | 512 | ||
| 394 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { | 513 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { |
| 395 | styleset_changed_event->Signal(); | 514 | styleset_changed_event.writable->Signal(); |
| 396 | hold_type = joy_hold_type; | 515 | hold_type = joy_hold_type; |
| 397 | } | 516 | } |
| 398 | 517 | ||
| @@ -401,44 +520,40 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { | |||
| 401 | } | 520 | } |
| 402 | 521 | ||
| 403 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { | 522 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { |
| 404 | ASSERT(npad_id < shared_memory_entries.size()); | 523 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 405 | shared_memory_entries[npad_id].pad_assignment = assignment_mode; | 524 | ASSERT(npad_index < shared_memory_entries.size()); |
| 525 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; | ||
| 406 | } | 526 | } |
| 407 | 527 | ||
| 408 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 528 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, |
| 409 | const std::vector<Vibration>& vibrations) { | 529 | const std::vector<Vibration>& vibrations) { |
| 530 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 531 | |||
| 410 | if (!can_controllers_vibrate) { | 532 | if (!can_controllers_vibrate) { |
| 411 | return; | 533 | return; |
| 412 | } | 534 | } |
| 413 | for (std::size_t i = 0; i < controller_ids.size(); i++) { | 535 | for (std::size_t i = 0; i < controller_ids.size(); i++) { |
| 414 | std::size_t controller_pos = i; | 536 | std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); |
| 415 | // Handheld controller conversion | ||
| 416 | if (controller_pos == NPAD_HANDHELD) { | ||
| 417 | controller_pos = 8; | ||
| 418 | } | ||
| 419 | // Unknown controller conversion | ||
| 420 | if (controller_pos == NPAD_UNKNOWN) { | ||
| 421 | controller_pos = 9; | ||
| 422 | } | ||
| 423 | if (connected_controllers[controller_pos].is_connected) { | 537 | if (connected_controllers[controller_pos].is_connected) { |
| 424 | // TODO(ogniK): Vibrate the physical controller | 538 | // TODO(ogniK): Vibrate the physical controller |
| 425 | } | 539 | } |
| 426 | } | 540 | } |
| 427 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 428 | last_processed_vibration = vibrations.back(); | 541 | last_processed_vibration = vibrations.back(); |
| 429 | } | 542 | } |
| 430 | 543 | ||
| 431 | Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { | 544 | Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const { |
| 432 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should | 545 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should |
| 433 | // be signalled at least once, and signaled after a new controller is connected? | 546 | // be signalled at least once, and signaled after a new controller is connected? |
| 434 | styleset_changed_event->Signal(); | 547 | styleset_changed_event.writable->Signal(); |
| 435 | return styleset_changed_event; | 548 | return styleset_changed_event.readable; |
| 436 | } | 549 | } |
| 437 | 550 | ||
| 438 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 551 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { |
| 439 | return last_processed_vibration; | 552 | return last_processed_vibration; |
| 440 | } | 553 | } |
| 554 | |||
| 441 | void Controller_NPad::AddNewController(NPadControllerType controller) { | 555 | void Controller_NPad::AddNewController(NPadControllerType controller) { |
| 556 | controller = DecideBestController(controller); | ||
| 442 | if (controller == NPadControllerType::Handheld) { | 557 | if (controller == NPadControllerType::Handheld) { |
| 443 | connected_controllers[8] = {controller, true}; | 558 | connected_controllers[8] = {controller, true}; |
| 444 | InitNewlyAddedControler(8); | 559 | InitNewlyAddedControler(8); |
| @@ -456,16 +571,54 @@ void Controller_NPad::AddNewController(NPadControllerType controller) { | |||
| 456 | InitNewlyAddedControler(controller_id); | 571 | InitNewlyAddedControler(controller_id); |
| 457 | } | 572 | } |
| 458 | 573 | ||
| 459 | void Controller_NPad::ConnectNPad(u32 npad_id) { | 574 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) { |
| 460 | if (npad_id >= connected_controllers.size()) | 575 | controller = DecideBestController(controller); |
| 576 | if (controller == NPadControllerType::Handheld) { | ||
| 577 | connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true}; | ||
| 578 | InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD)); | ||
| 461 | return; | 579 | return; |
| 462 | connected_controllers[npad_id].is_connected = true; | 580 | } |
| 581 | |||
| 582 | connected_controllers[NPadIdToIndex(npad_id)] = {controller, true}; | ||
| 583 | InitNewlyAddedControler(NPadIdToIndex(npad_id)); | ||
| 584 | } | ||
| 585 | |||
| 586 | void Controller_NPad::ConnectNPad(u32 npad_id) { | ||
| 587 | connected_controllers[NPadIdToIndex(npad_id)].is_connected = true; | ||
| 463 | } | 588 | } |
| 464 | 589 | ||
| 465 | void Controller_NPad::DisconnectNPad(u32 npad_id) { | 590 | void Controller_NPad::DisconnectNPad(u32 npad_id) { |
| 466 | if (npad_id >= connected_controllers.size()) | 591 | connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; |
| 467 | return; | 592 | } |
| 468 | connected_controllers[npad_id].is_connected = false; | 593 | |
| 594 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) { | ||
| 595 | if (controller == NPadControllerType::Handheld) { | ||
| 596 | // Handheld is not even a supported type, lets stop here | ||
| 597 | if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), | ||
| 598 | NPAD_HANDHELD) == supported_npad_id_types.end()) { | ||
| 599 | return false; | ||
| 600 | } | ||
| 601 | // Handheld should not be supported in docked mode | ||
| 602 | if (Settings::values.use_docked_mode) { | ||
| 603 | return false; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | switch (controller) { | ||
| 607 | case NPadControllerType::ProController: | ||
| 608 | return style.pro_controller; | ||
| 609 | case NPadControllerType::Handheld: | ||
| 610 | return style.handheld; | ||
| 611 | case NPadControllerType::JoyDual: | ||
| 612 | return style.joycon_dual; | ||
| 613 | case NPadControllerType::JoyLeft: | ||
| 614 | return style.joycon_left; | ||
| 615 | case NPadControllerType::JoyRight: | ||
| 616 | return style.joycon_right; | ||
| 617 | case NPadControllerType::Pokeball: | ||
| 618 | return style.pokeball; | ||
| 619 | default: | ||
| 620 | return false; | ||
| 621 | } | ||
| 469 | } | 622 | } |
| 470 | 623 | ||
| 471 | Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { | 624 | Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { |
| @@ -499,6 +652,36 @@ void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { | |||
| 499 | can_controllers_vibrate = can_vibrate; | 652 | can_controllers_vibrate = can_vibrate; |
| 500 | } | 653 | } |
| 501 | 654 | ||
| 655 | void Controller_NPad::ClearAllConnectedControllers() { | ||
| 656 | for (auto& controller : connected_controllers) { | ||
| 657 | if (controller.is_connected && controller.type != NPadControllerType::None) { | ||
| 658 | controller.type = NPadControllerType::None; | ||
| 659 | controller.is_connected = false; | ||
| 660 | } | ||
| 661 | } | ||
| 662 | } | ||
| 663 | void Controller_NPad::DisconnectAllConnectedControllers() { | ||
| 664 | std::for_each(connected_controllers.begin(), connected_controllers.end(), | ||
| 665 | [](ControllerHolder& controller) { controller.is_connected = false; }); | ||
| 666 | } | ||
| 667 | |||
| 668 | void Controller_NPad::ConnectAllDisconnectedControllers() { | ||
| 669 | std::for_each(connected_controllers.begin(), connected_controllers.end(), | ||
| 670 | [](ControllerHolder& controller) { | ||
| 671 | if (controller.type != NPadControllerType::None && !controller.is_connected) { | ||
| 672 | controller.is_connected = false; | ||
| 673 | } | ||
| 674 | }); | ||
| 675 | } | ||
| 676 | |||
| 677 | void Controller_NPad::ClearAllControllers() { | ||
| 678 | std::for_each(connected_controllers.begin(), connected_controllers.end(), | ||
| 679 | [](ControllerHolder& controller) { | ||
| 680 | controller.type = NPadControllerType::None; | ||
| 681 | controller.is_connected = false; | ||
| 682 | }); | ||
| 683 | } | ||
| 684 | |||
| 502 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { | 685 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { |
| 503 | const bool support_handheld = | 686 | const bool support_handheld = |
| 504 | std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != | 687 | std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index ac86985ff..29851f16a 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -5,13 +5,19 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "core/frontend/input.h" | 10 | #include "core/frontend/input.h" |
| 11 | #include "core/hle/kernel/object.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/hid/controllers/controller_base.h" | 13 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 11 | #include "core/settings.h" | 14 | #include "core/settings.h" |
| 12 | 15 | ||
| 13 | namespace Service::HID { | 16 | namespace Service::HID { |
| 14 | 17 | ||
| 18 | constexpr u32 NPAD_HANDHELD = 32; | ||
| 19 | constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? | ||
| 20 | |||
| 15 | class Controller_NPad final : public ControllerBase { | 21 | class Controller_NPad final : public ControllerBase { |
| 16 | public: | 22 | public: |
| 17 | Controller_NPad(); | 23 | Controller_NPad(); |
| @@ -75,9 +81,9 @@ public: | |||
| 75 | struct LedPattern { | 81 | struct LedPattern { |
| 76 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | 82 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { |
| 77 | position1.Assign(light1); | 83 | position1.Assign(light1); |
| 78 | position1.Assign(light2); | 84 | position2.Assign(light2); |
| 79 | position1.Assign(light3); | 85 | position3.Assign(light3); |
| 80 | position1.Assign(light4); | 86 | position4.Assign(light4); |
| 81 | } | 87 | } |
| 82 | union { | 88 | union { |
| 83 | u64 raw{}; | 89 | u64 raw{}; |
| @@ -103,15 +109,23 @@ public: | |||
| 103 | void VibrateController(const std::vector<u32>& controller_ids, | 109 | void VibrateController(const std::vector<u32>& controller_ids, |
| 104 | const std::vector<Vibration>& vibrations); | 110 | const std::vector<Vibration>& vibrations); |
| 105 | 111 | ||
| 106 | Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; | 112 | Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const; |
| 107 | Vibration GetLastVibration() const; | 113 | Vibration GetLastVibration() const; |
| 108 | 114 | ||
| 109 | void AddNewController(NPadControllerType controller); | 115 | void AddNewController(NPadControllerType controller); |
| 116 | void AddNewControllerAt(NPadControllerType controller, u32 npad_id); | ||
| 110 | 117 | ||
| 111 | void ConnectNPad(u32 npad_id); | 118 | void ConnectNPad(u32 npad_id); |
| 112 | void DisconnectNPad(u32 npad_id); | 119 | void DisconnectNPad(u32 npad_id); |
| 113 | LedPattern GetLedPattern(u32 npad_id); | 120 | LedPattern GetLedPattern(u32 npad_id); |
| 114 | void SetVibrationEnabled(bool can_vibrate); | 121 | void SetVibrationEnabled(bool can_vibrate); |
| 122 | void ClearAllConnectedControllers(); | ||
| 123 | void DisconnectAllConnectedControllers(); | ||
| 124 | void ConnectAllDisconnectedControllers(); | ||
| 125 | void ClearAllControllers(); | ||
| 126 | |||
| 127 | static std::size_t NPadIdToIndex(u32 npad_id); | ||
| 128 | static u32 IndexToNPad(std::size_t index); | ||
| 115 | 129 | ||
| 116 | private: | 130 | private: |
| 117 | struct CommonHeader { | 131 | struct CommonHeader { |
| @@ -164,8 +178,11 @@ private: | |||
| 164 | BitField<23, 1, u64_le> r_stick_down; | 178 | BitField<23, 1, u64_le> r_stick_down; |
| 165 | 179 | ||
| 166 | // Not always active? | 180 | // Not always active? |
| 167 | BitField<24, 1, u64_le> sl; | 181 | BitField<24, 1, u64_le> left_sl; |
| 168 | BitField<25, 1, u64_le> sr; | 182 | BitField<25, 1, u64_le> left_sr; |
| 183 | |||
| 184 | BitField<26, 1, u64_le> right_sl; | ||
| 185 | BitField<27, 1, u64_le> right_sr; | ||
| 169 | }; | 186 | }; |
| 170 | }; | 187 | }; |
| 171 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); | 188 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); |
| @@ -189,12 +206,17 @@ private: | |||
| 189 | }; | 206 | }; |
| 190 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | 207 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); |
| 191 | 208 | ||
| 192 | struct GenericStates { | 209 | struct ControllerPad { |
| 193 | s64_le timestamp; | ||
| 194 | s64_le timestamp2; | ||
| 195 | ControllerPadState pad_states; | 210 | ControllerPadState pad_states; |
| 196 | AnalogPosition l_stick; | 211 | AnalogPosition l_stick; |
| 197 | AnalogPosition r_stick; | 212 | AnalogPosition r_stick; |
| 213 | }; | ||
| 214 | static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size"); | ||
| 215 | |||
| 216 | struct GenericStates { | ||
| 217 | s64_le timestamp; | ||
| 218 | s64_le timestamp2; | ||
| 219 | ControllerPad pad; | ||
| 198 | ConnectionState connection_status; | 220 | ConnectionState connection_status; |
| 199 | }; | 221 | }; |
| 200 | static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); | 222 | static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); |
| @@ -266,18 +288,23 @@ private: | |||
| 266 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); | 288 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); |
| 267 | 289 | ||
| 268 | struct ControllerHolder { | 290 | struct ControllerHolder { |
| 269 | Controller_NPad::NPadControllerType type; | 291 | NPadControllerType type; |
| 270 | bool is_connected; | 292 | bool is_connected; |
| 271 | }; | 293 | }; |
| 272 | 294 | ||
| 273 | NPadType style{}; | 295 | NPadType style{}; |
| 274 | std::array<NPadEntry, 10> shared_memory_entries{}; | 296 | std::array<NPadEntry, 10> shared_memory_entries{}; |
| 275 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | 297 | std::array< |
| 298 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, | ||
| 299 | 10> | ||
| 276 | buttons; | 300 | buttons; |
| 277 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; | 301 | std::array< |
| 302 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, | ||
| 303 | 10> | ||
| 304 | sticks; | ||
| 278 | std::vector<u32> supported_npad_id_types{}; | 305 | std::vector<u32> supported_npad_id_types{}; |
| 279 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 306 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 280 | Kernel::SharedPtr<Kernel::Event> styleset_changed_event; | 307 | Kernel::EventPair styleset_changed_event; |
| 281 | Vibration last_processed_vibration{}; | 308 | Vibration last_processed_vibration{}; |
| 282 | std::array<ControllerHolder, 10> connected_controllers{}; | 309 | std::array<ControllerHolder, 10> connected_controllers{}; |
| 283 | bool can_controllers_vibrate{true}; | 310 | bool can_controllers_vibrate{true}; |
| @@ -285,5 +312,8 @@ private: | |||
| 285 | void InitNewlyAddedControler(std::size_t controller_idx); | 312 | void InitNewlyAddedControler(std::size_t controller_idx); |
| 286 | bool IsControllerSupported(NPadControllerType controller) const; | 313 | bool IsControllerSupported(NPadControllerType controller) const; |
| 287 | NPadControllerType DecideBestController(NPadControllerType priority) const; | 314 | NPadControllerType DecideBestController(NPadControllerType priority) const; |
| 315 | void RequestPadStateUpdate(u32 npad_id); | ||
| 316 | std::array<ControllerPad, 10> npad_pad_states{}; | ||
| 317 | bool IsControllerSupported(NPadControllerType controller); | ||
| 288 | }; | 318 | }; |
| 289 | } // namespace Service::HID | 319 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 43efef803..f666b1bd8 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -41,16 +41,17 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | |||
| 41 | 41 | ||
| 42 | const auto [x, y, pressed] = touch_device->GetStatus(); | 42 | const auto [x, y, pressed] = touch_device->GetStatus(); |
| 43 | auto& touch_entry = cur_entry.states[0]; | 43 | auto& touch_entry = cur_entry.states[0]; |
| 44 | if (pressed) { | 44 | touch_entry.attribute.raw = 0; |
| 45 | if (pressed && Settings::values.touchscreen.enabled) { | ||
| 45 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); | 46 | touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); |
| 46 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); | 47 | touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); |
| 47 | touch_entry.diameter_x = 15; | 48 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; |
| 48 | touch_entry.diameter_y = 15; | 49 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; |
| 49 | touch_entry.rotation_angle = 0; | 50 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; |
| 50 | const u64 tick = CoreTiming::GetTicks(); | 51 | const u64 tick = CoreTiming::GetTicks(); |
| 51 | touch_entry.delta_time = tick - last_touch; | 52 | touch_entry.delta_time = tick - last_touch; |
| 52 | last_touch = tick; | 53 | last_touch = tick; |
| 53 | touch_entry.finger = 0; | 54 | touch_entry.finger = Settings::values.touchscreen.finger; |
| 54 | cur_entry.entry_count = 1; | 55 | cur_entry.entry_count = 1; |
| 55 | } else { | 56 | } else { |
| 56 | cur_entry.entry_count = 0; | 57 | cur_entry.entry_count = 0; |
| @@ -60,6 +61,6 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | |||
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | void Controller_Touchscreen::OnLoadInputDevices() { | 63 | void Controller_Touchscreen::OnLoadInputDevices() { |
| 63 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); | 64 | touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); |
| 64 | } | 65 | } |
| 65 | } // namespace Service::HID | 66 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index e5db6e6ba..94cd0eba9 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/bit_field.h" | ||
| 7 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| @@ -29,9 +30,18 @@ public: | |||
| 29 | void OnLoadInputDevices() override; | 30 | void OnLoadInputDevices() override; |
| 30 | 31 | ||
| 31 | private: | 32 | private: |
| 33 | struct Attributes { | ||
| 34 | union { | ||
| 35 | u32 raw{}; | ||
| 36 | BitField<0, 1, u32_le> start_touch; | ||
| 37 | BitField<1, 1, u32_le> end_touch; | ||
| 38 | }; | ||
| 39 | }; | ||
| 40 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 41 | |||
| 32 | struct TouchState { | 42 | struct TouchState { |
| 33 | u64_le delta_time; | 43 | u64_le delta_time; |
| 34 | u32_le attribute; | 44 | Attributes attribute; |
| 35 | u32_le finger; | 45 | u32_le finger; |
| 36 | u32_le x; | 46 | u32_le x; |
| 37 | u32_le y; | 47 | u32_le y; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index a45fd4954..2ec38c726 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -13,8 +13,9 @@ | |||
| 13 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/client_port.h" | 14 | #include "core/hle/kernel/client_port.h" |
| 15 | #include "core/hle/kernel/client_session.h" | 15 | #include "core/hle/kernel/client_session.h" |
| 16 | #include "core/hle/kernel/event.h" | 16 | #include "core/hle/kernel/readable_event.h" |
| 17 | #include "core/hle/kernel/shared_memory.h" | 17 | #include "core/hle/kernel/shared_memory.h" |
| 18 | #include "core/hle/kernel/writable_event.h" | ||
| 18 | #include "core/hle/service/hid/hid.h" | 19 | #include "core/hle/service/hid/hid.h" |
| 19 | #include "core/hle/service/hid/irs.h" | 20 | #include "core/hle/service/hid/irs.h" |
| 20 | #include "core/hle/service/hid/xcd.h" | 21 | #include "core/hle/service/hid/xcd.h" |
| @@ -34,8 +35,8 @@ | |||
| 34 | namespace Service::HID { | 35 | namespace Service::HID { |
| 35 | 36 | ||
| 36 | // Updating period for each HID device. | 37 | // Updating period for each HID device. |
| 37 | // TODO(shinyquagsire23): These need better values. | 38 | // TODO(ogniK): Find actual polling rate of hid |
| 38 | constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 39 | constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66; |
| 39 | constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 40 | constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; |
| 40 | constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 41 | constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; |
| 41 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 42 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| @@ -124,10 +125,11 @@ public: | |||
| 124 | 125 | ||
| 125 | private: | 126 | private: |
| 126 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 127 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_DEBUG(Service_HID, "called"); | ||
| 129 | |||
| 127 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 130 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 128 | rb.Push(RESULT_SUCCESS); | 131 | rb.Push(RESULT_SUCCESS); |
| 129 | rb.PushCopyObjects(shared_mem); | 132 | rb.PushCopyObjects(shared_mem); |
| 130 | LOG_DEBUG(Service_HID, "called"); | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | void UpdateControllers(u64 userdata, int cycles_late) { | 135 | void UpdateControllers(u64 userdata, int cycles_late) { |
| @@ -163,9 +165,10 @@ public: | |||
| 163 | 165 | ||
| 164 | private: | 166 | private: |
| 165 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { | 167 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { |
| 168 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 169 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 2}; | 170 | IPC::ResponseBuilder rb{ctx, 2}; |
| 167 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| 168 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 169 | } | 172 | } |
| 170 | }; | 173 | }; |
| 171 | 174 | ||
| @@ -286,10 +289,10 @@ public: | |||
| 286 | {519, nullptr, "GetPalmaOperationResult"}, | 289 | {519, nullptr, "GetPalmaOperationResult"}, |
| 287 | {520, nullptr, "ReadPalmaPlayLog"}, | 290 | {520, nullptr, "ReadPalmaPlayLog"}, |
| 288 | {521, nullptr, "ResetPalmaPlayLog"}, | 291 | {521, nullptr, "ResetPalmaPlayLog"}, |
| 289 | {522, nullptr, "SetIsPalmaAllConnectable"}, | 292 | {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"}, |
| 290 | {523, nullptr, "SetIsPalmaPairedConnectable"}, | 293 | {523, nullptr, "SetIsPalmaPairedConnectable"}, |
| 291 | {524, nullptr, "PairPalma"}, | 294 | {524, nullptr, "PairPalma"}, |
| 292 | {525, nullptr, "SetPalmaBoostMode"}, | 295 | {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, |
| 293 | {1000, nullptr, "SetNpadCommunicationMode"}, | 296 | {1000, nullptr, "SetNpadCommunicationMode"}, |
| 294 | {1001, nullptr, "GetNpadCommunicationMode"}, | 297 | {1001, nullptr, "GetNpadCommunicationMode"}, |
| 295 | }; | 298 | }; |
| @@ -303,6 +306,8 @@ private: | |||
| 303 | std::shared_ptr<IAppletResource> applet_resource; | 306 | std::shared_ptr<IAppletResource> applet_resource; |
| 304 | 307 | ||
| 305 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { | 308 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { |
| 309 | LOG_DEBUG(Service_HID, "called"); | ||
| 310 | |||
| 306 | if (applet_resource == nullptr) { | 311 | if (applet_resource == nullptr) { |
| 307 | applet_resource = std::make_shared<IAppletResource>(); | 312 | applet_resource = std::make_shared<IAppletResource>(); |
| 308 | } | 313 | } |
| @@ -310,206 +315,228 @@ private: | |||
| 310 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 315 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 311 | rb.Push(RESULT_SUCCESS); | 316 | rb.Push(RESULT_SUCCESS); |
| 312 | rb.PushIpcInterface<IAppletResource>(applet_resource); | 317 | rb.PushIpcInterface<IAppletResource>(applet_resource); |
| 313 | LOG_DEBUG(Service_HID, "called"); | ||
| 314 | } | 318 | } |
| 315 | 319 | ||
| 316 | void ActivateXpad(Kernel::HLERequestContext& ctx) { | 320 | void ActivateXpad(Kernel::HLERequestContext& ctx) { |
| 321 | LOG_DEBUG(Service_HID, "called"); | ||
| 322 | |||
| 317 | applet_resource->ActivateController(HidController::XPad); | 323 | applet_resource->ActivateController(HidController::XPad); |
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | 324 | IPC::ResponseBuilder rb{ctx, 2}; |
| 319 | rb.Push(RESULT_SUCCESS); | 325 | rb.Push(RESULT_SUCCESS); |
| 320 | LOG_DEBUG(Service_HID, "called"); | ||
| 321 | } | 326 | } |
| 322 | 327 | ||
| 323 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { | 328 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { |
| 329 | LOG_DEBUG(Service_HID, "called"); | ||
| 330 | |||
| 324 | applet_resource->ActivateController(HidController::DebugPad); | 331 | applet_resource->ActivateController(HidController::DebugPad); |
| 325 | IPC::ResponseBuilder rb{ctx, 2}; | 332 | IPC::ResponseBuilder rb{ctx, 2}; |
| 326 | rb.Push(RESULT_SUCCESS); | 333 | rb.Push(RESULT_SUCCESS); |
| 327 | LOG_DEBUG(Service_HID, "called"); | ||
| 328 | } | 334 | } |
| 329 | 335 | ||
| 330 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { | 336 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { |
| 337 | LOG_DEBUG(Service_HID, "called"); | ||
| 338 | |||
| 331 | applet_resource->ActivateController(HidController::Touchscreen); | 339 | applet_resource->ActivateController(HidController::Touchscreen); |
| 332 | IPC::ResponseBuilder rb{ctx, 2}; | 340 | IPC::ResponseBuilder rb{ctx, 2}; |
| 333 | rb.Push(RESULT_SUCCESS); | 341 | rb.Push(RESULT_SUCCESS); |
| 334 | LOG_DEBUG(Service_HID, "called"); | ||
| 335 | } | 342 | } |
| 336 | 343 | ||
| 337 | void ActivateMouse(Kernel::HLERequestContext& ctx) { | 344 | void ActivateMouse(Kernel::HLERequestContext& ctx) { |
| 345 | LOG_DEBUG(Service_HID, "called"); | ||
| 346 | |||
| 338 | applet_resource->ActivateController(HidController::Mouse); | 347 | applet_resource->ActivateController(HidController::Mouse); |
| 339 | IPC::ResponseBuilder rb{ctx, 2}; | 348 | IPC::ResponseBuilder rb{ctx, 2}; |
| 340 | rb.Push(RESULT_SUCCESS); | 349 | rb.Push(RESULT_SUCCESS); |
| 341 | LOG_DEBUG(Service_HID, "called"); | ||
| 342 | } | 350 | } |
| 343 | 351 | ||
| 344 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { | 352 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { |
| 353 | LOG_DEBUG(Service_HID, "called"); | ||
| 354 | |||
| 345 | applet_resource->ActivateController(HidController::Keyboard); | 355 | applet_resource->ActivateController(HidController::Keyboard); |
| 346 | IPC::ResponseBuilder rb{ctx, 2}; | 356 | IPC::ResponseBuilder rb{ctx, 2}; |
| 347 | rb.Push(RESULT_SUCCESS); | 357 | rb.Push(RESULT_SUCCESS); |
| 348 | LOG_DEBUG(Service_HID, "called"); | ||
| 349 | } | 358 | } |
| 350 | 359 | ||
| 351 | void ActivateGesture(Kernel::HLERequestContext& ctx) { | 360 | void ActivateGesture(Kernel::HLERequestContext& ctx) { |
| 361 | LOG_DEBUG(Service_HID, "called"); | ||
| 362 | |||
| 352 | applet_resource->ActivateController(HidController::Gesture); | 363 | applet_resource->ActivateController(HidController::Gesture); |
| 353 | IPC::ResponseBuilder rb{ctx, 2}; | 364 | IPC::ResponseBuilder rb{ctx, 2}; |
| 354 | rb.Push(RESULT_SUCCESS); | 365 | rb.Push(RESULT_SUCCESS); |
| 355 | LOG_DEBUG(Service_HID, "called"); | ||
| 356 | } | 366 | } |
| 357 | 367 | ||
| 358 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | 368 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { |
| 359 | // Should have no effect with how our npad sets up the data | 369 | // Should have no effect with how our npad sets up the data |
| 370 | LOG_DEBUG(Service_HID, "called"); | ||
| 371 | |||
| 360 | applet_resource->ActivateController(HidController::NPad); | 372 | applet_resource->ActivateController(HidController::NPad); |
| 361 | IPC::ResponseBuilder rb{ctx, 2}; | 373 | IPC::ResponseBuilder rb{ctx, 2}; |
| 362 | rb.Push(RESULT_SUCCESS); | 374 | rb.Push(RESULT_SUCCESS); |
| 363 | LOG_DEBUG(Service_HID, "called"); | ||
| 364 | } | 375 | } |
| 365 | 376 | ||
| 366 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 377 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 367 | IPC::RequestParser rp{ctx}; | 378 | IPC::RequestParser rp{ctx}; |
| 368 | auto handle = rp.PopRaw<u32>(); | 379 | auto handle = rp.PopRaw<u32>(); |
| 380 | LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle); | ||
| 381 | |||
| 369 | IPC::ResponseBuilder rb{ctx, 2}; | 382 | IPC::ResponseBuilder rb{ctx, 2}; |
| 370 | rb.Push(RESULT_SUCCESS); | 383 | rb.Push(RESULT_SUCCESS); |
| 371 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 372 | } | 384 | } |
| 373 | 385 | ||
| 374 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 386 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 387 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 388 | |||
| 375 | IPC::ResponseBuilder rb{ctx, 2}; | 389 | IPC::ResponseBuilder rb{ctx, 2}; |
| 376 | rb.Push(RESULT_SUCCESS); | 390 | rb.Push(RESULT_SUCCESS); |
| 377 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 378 | } | 391 | } |
| 379 | 392 | ||
| 380 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | 393 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { |
| 394 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 395 | |||
| 381 | IPC::ResponseBuilder rb{ctx, 3}; | 396 | IPC::ResponseBuilder rb{ctx, 3}; |
| 382 | rb.Push(RESULT_SUCCESS); | 397 | rb.Push(RESULT_SUCCESS); |
| 383 | // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. | 398 | // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. |
| 384 | rb.Push(true); | 399 | rb.Push(true); |
| 385 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 386 | } | 400 | } |
| 387 | 401 | ||
| 388 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 402 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 389 | IPC::RequestParser rp{ctx}; | 403 | IPC::RequestParser rp{ctx}; |
| 390 | auto supported_styleset = rp.PopRaw<u32>(); | 404 | auto supported_styleset = rp.PopRaw<u32>(); |
| 405 | LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset); | ||
| 406 | |||
| 391 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 407 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 392 | .SetSupportedStyleSet({supported_styleset}); | 408 | .SetSupportedStyleSet({supported_styleset}); |
| 393 | 409 | ||
| 394 | IPC::ResponseBuilder rb{ctx, 2}; | 410 | IPC::ResponseBuilder rb{ctx, 2}; |
| 395 | rb.Push(RESULT_SUCCESS); | 411 | rb.Push(RESULT_SUCCESS); |
| 396 | |||
| 397 | LOG_DEBUG(Service_HID, "called"); | ||
| 398 | } | 412 | } |
| 399 | 413 | ||
| 400 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 414 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 415 | LOG_DEBUG(Service_HID, "called"); | ||
| 416 | |||
| 401 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 417 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 402 | 418 | ||
| 403 | IPC::ResponseBuilder rb{ctx, 3}; | 419 | IPC::ResponseBuilder rb{ctx, 3}; |
| 404 | rb.Push(RESULT_SUCCESS); | 420 | rb.Push(RESULT_SUCCESS); |
| 405 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); | 421 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); |
| 406 | LOG_DEBUG(Service_HID, "called"); | ||
| 407 | } | 422 | } |
| 408 | 423 | ||
| 409 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 424 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| 425 | LOG_DEBUG(Service_HID, "called"); | ||
| 426 | |||
| 410 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 427 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 411 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); | 428 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); |
| 412 | IPC::ResponseBuilder rb{ctx, 2}; | 429 | IPC::ResponseBuilder rb{ctx, 2}; |
| 413 | rb.Push(RESULT_SUCCESS); | 430 | rb.Push(RESULT_SUCCESS); |
| 414 | LOG_DEBUG(Service_HID, "called"); | ||
| 415 | } | 431 | } |
| 416 | 432 | ||
| 417 | void ActivateNpad(Kernel::HLERequestContext& ctx) { | 433 | void ActivateNpad(Kernel::HLERequestContext& ctx) { |
| 434 | LOG_DEBUG(Service_HID, "called"); | ||
| 435 | |||
| 418 | IPC::ResponseBuilder rb{ctx, 2}; | 436 | IPC::ResponseBuilder rb{ctx, 2}; |
| 419 | rb.Push(RESULT_SUCCESS); | 437 | rb.Push(RESULT_SUCCESS); |
| 420 | applet_resource->ActivateController(HidController::NPad); | 438 | applet_resource->ActivateController(HidController::NPad); |
| 421 | LOG_DEBUG(Service_HID, "called"); | ||
| 422 | } | 439 | } |
| 423 | 440 | ||
| 424 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 441 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 425 | IPC::RequestParser rp{ctx}; | 442 | IPC::RequestParser rp{ctx}; |
| 426 | auto npad_id = rp.PopRaw<u32>(); | 443 | auto npad_id = rp.PopRaw<u32>(); |
| 444 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 445 | |||
| 427 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 446 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 428 | rb.Push(RESULT_SUCCESS); | 447 | rb.Push(RESULT_SUCCESS); |
| 429 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 448 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 430 | .GetStyleSetChangedEvent()); | 449 | .GetStyleSetChangedEvent()); |
| 431 | LOG_DEBUG(Service_HID, "called"); | ||
| 432 | } | 450 | } |
| 433 | 451 | ||
| 434 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { | 452 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 435 | IPC::RequestParser rp{ctx}; | 453 | IPC::RequestParser rp{ctx}; |
| 436 | auto npad_id = rp.PopRaw<u32>(); | 454 | auto npad_id = rp.PopRaw<u32>(); |
| 455 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 456 | |||
| 437 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 457 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 438 | .DisconnectNPad(npad_id); | 458 | .DisconnectNPad(npad_id); |
| 439 | IPC::ResponseBuilder rb{ctx, 2}; | 459 | IPC::ResponseBuilder rb{ctx, 2}; |
| 440 | rb.Push(RESULT_SUCCESS); | 460 | rb.Push(RESULT_SUCCESS); |
| 441 | LOG_DEBUG(Service_HID, "called"); | ||
| 442 | } | 461 | } |
| 443 | 462 | ||
| 444 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 463 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 445 | IPC::RequestParser rp{ctx}; | 464 | IPC::RequestParser rp{ctx}; |
| 446 | auto npad_id = rp.PopRaw<u32>(); | 465 | auto npad_id = rp.PopRaw<u32>(); |
| 466 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 467 | |||
| 447 | IPC::ResponseBuilder rb{ctx, 4}; | 468 | IPC::ResponseBuilder rb{ctx, 4}; |
| 448 | rb.Push(RESULT_SUCCESS); | 469 | rb.Push(RESULT_SUCCESS); |
| 449 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 470 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 450 | .GetLedPattern(npad_id) | 471 | .GetLedPattern(npad_id) |
| 451 | .raw); | 472 | .raw); |
| 452 | LOG_DEBUG(Service_HID, "called"); | ||
| 453 | } | 473 | } |
| 454 | 474 | ||
| 455 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 475 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 456 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 457 | IPC::RequestParser rp{ctx}; | 476 | IPC::RequestParser rp{ctx}; |
| 458 | const auto hold_type = rp.PopRaw<u64>(); | 477 | const auto hold_type = rp.PopRaw<u64>(); |
| 478 | LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type); | ||
| 479 | |||
| 480 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 459 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); | 481 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); |
| 460 | 482 | ||
| 461 | IPC::ResponseBuilder rb{ctx, 2}; | 483 | IPC::ResponseBuilder rb{ctx, 2}; |
| 462 | rb.Push(RESULT_SUCCESS); | 484 | rb.Push(RESULT_SUCCESS); |
| 463 | LOG_DEBUG(Service_HID, "called"); | ||
| 464 | } | 485 | } |
| 465 | 486 | ||
| 466 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 487 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 488 | LOG_DEBUG(Service_HID, "called"); | ||
| 489 | |||
| 467 | const auto& controller = | 490 | const auto& controller = |
| 468 | applet_resource->GetController<Controller_NPad>(HidController::NPad); | 491 | applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 469 | IPC::ResponseBuilder rb{ctx, 4}; | 492 | IPC::ResponseBuilder rb{ctx, 4}; |
| 470 | rb.Push(RESULT_SUCCESS); | 493 | rb.Push(RESULT_SUCCESS); |
| 471 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); | 494 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); |
| 472 | LOG_DEBUG(Service_HID, "called"); | ||
| 473 | } | 495 | } |
| 474 | 496 | ||
| 475 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 497 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 476 | IPC::RequestParser rp{ctx}; | 498 | IPC::RequestParser rp{ctx}; |
| 477 | auto npad_id = rp.PopRaw<u32>(); | 499 | auto npad_id = rp.PopRaw<u32>(); |
| 500 | LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id); | ||
| 501 | |||
| 478 | IPC::ResponseBuilder rb{ctx, 2}; | 502 | IPC::ResponseBuilder rb{ctx, 2}; |
| 479 | rb.Push(RESULT_SUCCESS); | 503 | rb.Push(RESULT_SUCCESS); |
| 480 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 481 | } | 504 | } |
| 482 | 505 | ||
| 483 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 506 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { |
| 507 | LOG_DEBUG(Service_HID, "called"); | ||
| 508 | |||
| 484 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 509 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 485 | .SetVibrationEnabled(true); | 510 | .SetVibrationEnabled(true); |
| 486 | IPC::ResponseBuilder rb{ctx, 2}; | 511 | IPC::ResponseBuilder rb{ctx, 2}; |
| 487 | rb.Push(RESULT_SUCCESS); | 512 | rb.Push(RESULT_SUCCESS); |
| 488 | LOG_DEBUG(Service_HID, "called"); | ||
| 489 | } | 513 | } |
| 490 | 514 | ||
| 491 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 515 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { |
| 516 | LOG_DEBUG(Service_HID, "called"); | ||
| 517 | |||
| 492 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 518 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 493 | .SetVibrationEnabled(false); | 519 | .SetVibrationEnabled(false); |
| 494 | IPC::ResponseBuilder rb{ctx, 2}; | 520 | IPC::ResponseBuilder rb{ctx, 2}; |
| 495 | rb.Push(RESULT_SUCCESS); | 521 | rb.Push(RESULT_SUCCESS); |
| 496 | LOG_DEBUG(Service_HID, "called"); | ||
| 497 | } | 522 | } |
| 498 | 523 | ||
| 499 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { | 524 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 500 | IPC::RequestParser rp{ctx}; | 525 | IPC::RequestParser rp{ctx}; |
| 501 | const auto controller_id = rp.PopRaw<u32>(); | 526 | const auto controller_id = rp.PopRaw<u32>(); |
| 502 | const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); | 527 | const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); |
| 528 | LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id); | ||
| 503 | 529 | ||
| 504 | IPC::ResponseBuilder rb{ctx, 2}; | 530 | IPC::ResponseBuilder rb{ctx, 2}; |
| 505 | rb.Push(RESULT_SUCCESS); | 531 | rb.Push(RESULT_SUCCESS); |
| 506 | 532 | ||
| 507 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 533 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 508 | .VibrateController({controller_id}, {vibration_values}); | 534 | .VibrateController({controller_id}, {vibration_values}); |
| 509 | LOG_DEBUG(Service_HID, "called"); | ||
| 510 | } | 535 | } |
| 511 | 536 | ||
| 512 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { | 537 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| 538 | LOG_DEBUG(Service_HID, "called"); | ||
| 539 | |||
| 513 | const auto controllers = ctx.ReadBuffer(0); | 540 | const auto controllers = ctx.ReadBuffer(0); |
| 514 | const auto vibrations = ctx.ReadBuffer(1); | 541 | const auto vibrations = ctx.ReadBuffer(1); |
| 515 | 542 | ||
| @@ -527,74 +554,96 @@ private: | |||
| 527 | 554 | ||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | 555 | IPC::ResponseBuilder rb{ctx, 2}; |
| 529 | rb.Push(RESULT_SUCCESS); | 556 | rb.Push(RESULT_SUCCESS); |
| 530 | LOG_DEBUG(Service_HID, "called"); | ||
| 531 | } | 557 | } |
| 532 | 558 | ||
| 533 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 559 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 560 | LOG_DEBUG(Service_HID, "called"); | ||
| 561 | |||
| 534 | IPC::ResponseBuilder rb{ctx, 6}; | 562 | IPC::ResponseBuilder rb{ctx, 6}; |
| 535 | rb.Push(RESULT_SUCCESS); | 563 | rb.Push(RESULT_SUCCESS); |
| 536 | rb.PushRaw<Controller_NPad::Vibration>( | 564 | rb.PushRaw<Controller_NPad::Vibration>( |
| 537 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 565 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 538 | .GetLastVibration()); | 566 | .GetLastVibration()); |
| 539 | LOG_DEBUG(Service_HID, "called"); | ||
| 540 | } | 567 | } |
| 541 | 568 | ||
| 542 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 569 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 543 | IPC::RequestParser rp{ctx}; | 570 | IPC::RequestParser rp{ctx}; |
| 544 | const auto npad_id = rp.PopRaw<u32>(); | 571 | const auto npad_id = rp.PopRaw<u32>(); |
| 572 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 573 | |||
| 545 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 574 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 546 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); | 575 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); |
| 547 | 576 | ||
| 548 | IPC::ResponseBuilder rb{ctx, 2}; | 577 | IPC::ResponseBuilder rb{ctx, 2}; |
| 549 | rb.Push(RESULT_SUCCESS); | 578 | rb.Push(RESULT_SUCCESS); |
| 550 | LOG_DEBUG(Service_HID, "called"); | ||
| 551 | } | 579 | } |
| 552 | 580 | ||
| 553 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 581 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| 582 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 583 | |||
| 554 | IPC::ResponseBuilder rb{ctx, 2}; | 584 | IPC::ResponseBuilder rb{ctx, 2}; |
| 555 | rb.Push(RESULT_SUCCESS); | 585 | rb.Push(RESULT_SUCCESS); |
| 556 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 557 | } | 586 | } |
| 558 | 587 | ||
| 559 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 588 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 560 | IPC::RequestParser rp{ctx}; | 589 | IPC::RequestParser rp{ctx}; |
| 561 | auto mode = rp.PopRaw<u32>(); | 590 | auto mode = rp.PopRaw<u32>(); |
| 591 | LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode); | ||
| 592 | |||
| 562 | IPC::ResponseBuilder rb{ctx, 2}; | 593 | IPC::ResponseBuilder rb{ctx, 2}; |
| 563 | rb.Push(RESULT_SUCCESS); | 594 | rb.Push(RESULT_SUCCESS); |
| 564 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 565 | } | 595 | } |
| 566 | 596 | ||
| 567 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 597 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 598 | LOG_DEBUG(Service_HID, "called"); | ||
| 599 | |||
| 568 | IPC::ResponseBuilder rb{ctx, 4}; | 600 | IPC::ResponseBuilder rb{ctx, 4}; |
| 569 | rb.Push(RESULT_SUCCESS); | 601 | rb.Push(RESULT_SUCCESS); |
| 570 | rb.Push<u32>(1); | 602 | rb.Push<u32>(1); |
| 571 | rb.Push<u32>(0); | 603 | rb.Push<u32>(0); |
| 572 | LOG_DEBUG(Service_HID, "called"); | ||
| 573 | } | 604 | } |
| 574 | 605 | ||
| 575 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 606 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| 607 | LOG_DEBUG(Service_HID, "called"); | ||
| 608 | |||
| 576 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 609 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 577 | rb.Push(RESULT_SUCCESS); | 610 | rb.Push(RESULT_SUCCESS); |
| 578 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); | 611 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); |
| 579 | LOG_DEBUG(Service_HID, "called"); | ||
| 580 | } | 612 | } |
| 581 | 613 | ||
| 582 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 614 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 615 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 616 | |||
| 583 | IPC::ResponseBuilder rb{ctx, 2}; | 617 | IPC::ResponseBuilder rb{ctx, 2}; |
| 584 | rb.Push(RESULT_SUCCESS); | 618 | rb.Push(RESULT_SUCCESS); |
| 585 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 586 | } | 619 | } |
| 587 | 620 | ||
| 588 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 621 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 622 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 623 | |||
| 589 | IPC::ResponseBuilder rb{ctx, 2}; | 624 | IPC::ResponseBuilder rb{ctx, 2}; |
| 590 | rb.Push(RESULT_SUCCESS); | 625 | rb.Push(RESULT_SUCCESS); |
| 591 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 592 | } | 626 | } |
| 593 | 627 | ||
| 594 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | 628 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 629 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 630 | |||
| 595 | IPC::ResponseBuilder rb{ctx, 2}; | 631 | IPC::ResponseBuilder rb{ctx, 2}; |
| 596 | rb.Push(RESULT_SUCCESS); | 632 | rb.Push(RESULT_SUCCESS); |
| 633 | } | ||
| 634 | |||
| 635 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { | ||
| 597 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 636 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 637 | |||
| 638 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 639 | rb.Push(RESULT_SUCCESS); | ||
| 640 | } | ||
| 641 | |||
| 642 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { | ||
| 643 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 644 | |||
| 645 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 646 | rb.Push(RESULT_SUCCESS); | ||
| 598 | } | 647 | } |
| 599 | }; | 648 | }; |
| 600 | 649 | ||
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 872e3c344..3c7f8b1ee 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} { | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { | 46 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 47 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 48 | |||
| 47 | IPC::ResponseBuilder rb{ctx, 2}; | 49 | IPC::ResponseBuilder rb{ctx, 2}; |
| 48 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 49 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { | 53 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 54 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 55 | |||
| 53 | IPC::ResponseBuilder rb{ctx, 2}; | 56 | IPC::ResponseBuilder rb{ctx, 2}; |
| 54 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 55 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 60 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 61 | LOG_DEBUG(Service_IRS, "called"); | ||
| 62 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 63 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 60 | rb.Push(RESULT_SUCCESS); | 64 | rb.Push(RESULT_SUCCESS); |
| 61 | rb.PushCopyObjects(shared_mem); | 65 | rb.PushCopyObjects(shared_mem); |
| 62 | LOG_DEBUG(Service_IRS, "called"); | ||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | 68 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { |
| 69 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 70 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2}; | 71 | IPC::ResponseBuilder rb{ctx, 2}; |
| 67 | rb.Push(RESULT_SUCCESS); | 72 | rb.Push(RESULT_SUCCESS); |
| 68 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | 75 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { |
| 76 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 77 | |||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 78 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| 74 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 75 | } | 80 | } |
| 76 | 81 | ||
| 77 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | 82 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 84 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | 85 | IPC::ResponseBuilder rb{ctx, 2}; |
| 79 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| 80 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 81 | } | 87 | } |
| 82 | 88 | ||
| 83 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | 89 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { |
| 90 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 91 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 92 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 93 | rb.Push(RESULT_SUCCESS); |
| 86 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 87 | } | 94 | } |
| 88 | 95 | ||
| 89 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | 96 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { |
| 97 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 98 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 5}; | 99 | IPC::ResponseBuilder rb{ctx, 5}; |
| 91 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 92 | rb.PushRaw<u64>(CoreTiming::GetTicks()); | 101 | rb.PushRaw<u64>(CoreTiming::GetTicks()); |
| 93 | rb.PushRaw<u32>(0); | 102 | rb.PushRaw<u32>(0); |
| 94 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 95 | } | 103 | } |
| 96 | 104 | ||
| 97 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { | 105 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 107 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 100 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | 112 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { |
| 113 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 114 | |||
| 104 | IPC::ResponseBuilder rb{ctx, 3}; | 115 | IPC::ResponseBuilder rb{ctx, 3}; |
| 105 | rb.Push(RESULT_SUCCESS); | 116 | rb.Push(RESULT_SUCCESS); |
| 106 | rb.PushRaw<u32>(device_handle); | 117 | rb.PushRaw<u32>(device_handle); |
| 107 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 108 | } | 118 | } |
| 109 | 119 | ||
| 110 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | 120 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { |
| 121 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 122 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2}; | 123 | IPC::ResponseBuilder rb{ctx, 2}; |
| 112 | rb.Push(RESULT_SUCCESS); | 124 | rb.Push(RESULT_SUCCESS); |
| 113 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 114 | } | 125 | } |
| 115 | 126 | ||
| 116 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | 127 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 129 | |||
| 117 | IPC::ResponseBuilder rb{ctx, 2}; | 130 | IPC::ResponseBuilder rb{ctx, 2}; |
| 118 | rb.Push(RESULT_SUCCESS); | 131 | rb.Push(RESULT_SUCCESS); |
| 119 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 120 | } | 132 | } |
| 121 | 133 | ||
| 122 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | 134 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { |
| 135 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 136 | |||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | 137 | IPC::ResponseBuilder rb{ctx, 2}; |
| 124 | rb.Push(RESULT_SUCCESS); | 138 | rb.Push(RESULT_SUCCESS); |
| 125 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 126 | } | 139 | } |
| 127 | 140 | ||
| 128 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { | 141 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 142 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 143 | |||
| 129 | IPC::ResponseBuilder rb{ctx, 2}; | 144 | IPC::ResponseBuilder rb{ctx, 2}; |
| 130 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 131 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 132 | } | 146 | } |
| 133 | 147 | ||
| 134 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | 148 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { |
| 149 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 150 | |||
| 135 | IPC::ResponseBuilder rb{ctx, 2}; | 151 | IPC::ResponseBuilder rb{ctx, 2}; |
| 136 | rb.Push(RESULT_SUCCESS); | 152 | rb.Push(RESULT_SUCCESS); |
| 137 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 138 | } | 153 | } |
| 139 | 154 | ||
| 140 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | 155 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { |
| 156 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 157 | |||
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | 158 | IPC::ResponseBuilder rb{ctx, 2}; |
| 142 | rb.Push(RESULT_SUCCESS); | 159 | rb.Push(RESULT_SUCCESS); |
| 143 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 144 | } | 160 | } |
| 145 | 161 | ||
| 146 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | 162 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { |
| 163 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 164 | |||
| 147 | IPC::ResponseBuilder rb{ctx, 2}; | 165 | IPC::ResponseBuilder rb{ctx, 2}; |
| 148 | rb.Push(RESULT_SUCCESS); | 166 | rb.Push(RESULT_SUCCESS); |
| 149 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 150 | } | 167 | } |
| 151 | 168 | ||
| 152 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | 169 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 170 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 171 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2}; | 172 | IPC::ResponseBuilder rb{ctx, 2}; |
| 154 | rb.Push(RESULT_SUCCESS); | 173 | rb.Push(RESULT_SUCCESS); |
| 155 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 156 | } | 174 | } |
| 157 | 175 | ||
| 158 | IRS::~IRS() = default; | 176 | IRS::~IRS() = default; |
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index 164c57e18..e8f9f2d29 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp | |||
| @@ -55,29 +55,29 @@ public: | |||
| 55 | 55 | ||
| 56 | private: | 56 | private: |
| 57 | void EnableVrMode(Kernel::HLERequestContext& ctx) { | 57 | void EnableVrMode(Kernel::HLERequestContext& ctx) { |
| 58 | LOG_DEBUG(Service_LBL, "called"); | ||
| 59 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 2}; | 60 | IPC::ResponseBuilder rb{ctx, 2}; |
| 59 | rb.Push(RESULT_SUCCESS); | 61 | rb.Push(RESULT_SUCCESS); |
| 60 | 62 | ||
| 61 | vr_mode_enabled = true; | 63 | vr_mode_enabled = true; |
| 62 | |||
| 63 | LOG_DEBUG(Service_LBL, "called"); | ||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | void DisableVrMode(Kernel::HLERequestContext& ctx) { | 66 | void DisableVrMode(Kernel::HLERequestContext& ctx) { |
| 67 | LOG_DEBUG(Service_LBL, "called"); | ||
| 68 | |||
| 67 | IPC::ResponseBuilder rb{ctx, 2}; | 69 | IPC::ResponseBuilder rb{ctx, 2}; |
| 68 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 69 | 71 | ||
| 70 | vr_mode_enabled = false; | 72 | vr_mode_enabled = false; |
| 71 | |||
| 72 | LOG_DEBUG(Service_LBL, "called"); | ||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { | 75 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { |
| 76 | LOG_DEBUG(Service_LBL, "called"); | ||
| 77 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | 78 | IPC::ResponseBuilder rb{ctx, 3}; |
| 77 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.Push(vr_mode_enabled); | 80 | rb.Push(vr_mode_enabled); |
| 79 | |||
| 80 | LOG_DEBUG(Service_LBL, "called"); | ||
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | bool vr_mode_enabled = false; | 83 | bool vr_mode_enabled = false; |
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 167f2c66a..e250595e3 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -44,11 +44,11 @@ public: | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void CreateMonitorService(Kernel::HLERequestContext& ctx) { | 46 | void CreateMonitorService(Kernel::HLERequestContext& ctx) { |
| 47 | LOG_DEBUG(Service_LDN, "called"); | ||
| 48 | |||
| 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 48 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 49 | rb.PushIpcInterface<IMonitorService>(); | 51 | rb.PushIpcInterface<IMonitorService>(); |
| 50 | |||
| 51 | LOG_DEBUG(Service_LDN, "called"); | ||
| 52 | } | 52 | } |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| @@ -104,11 +104,11 @@ public: | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { | 106 | void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { |
| 107 | LOG_DEBUG(Service_LDN, "called"); | ||
| 108 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 109 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 108 | rb.Push(RESULT_SUCCESS); | 110 | rb.Push(RESULT_SUCCESS); |
| 109 | rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); | 111 | rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); |
| 110 | |||
| 111 | LOG_DEBUG(Service_LDN, "called"); | ||
| 112 | } | 112 | } |
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| @@ -125,11 +125,11 @@ public: | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { | 127 | void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_DEBUG(Service_LDN, "called"); | ||
| 129 | |||
| 128 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 130 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 129 | rb.Push(RESULT_SUCCESS); | 131 | rb.Push(RESULT_SUCCESS); |
| 130 | rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); | 132 | rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); |
| 131 | |||
| 132 | LOG_DEBUG(Service_LDN, "called"); | ||
| 133 | } | 133 | } |
| 134 | }; | 134 | }; |
| 135 | 135 | ||
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d607d985e..ca119dd3a 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -4,7 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <fmt/format.h> | 6 | #include <fmt/format.h> |
| 7 | #include <mbedtls/sha256.h> | ||
| 7 | 8 | ||
| 9 | #include "common/alignment.h" | ||
| 10 | #include "common/hex_util.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 10 | #include "core/hle/service/ldr/ldr.h" | 13 | #include "core/hle/service/ldr/ldr.h" |
| @@ -13,6 +16,21 @@ | |||
| 13 | 16 | ||
| 14 | namespace Service::LDR { | 17 | namespace Service::LDR { |
| 15 | 18 | ||
| 19 | constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51}; | ||
| 20 | constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52}; | ||
| 21 | constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53}; | ||
| 22 | constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54}; | ||
| 23 | constexpr ResultCode ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55}; | ||
| 24 | constexpr ResultCode ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56}; | ||
| 25 | constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57}; | ||
| 26 | constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81}; | ||
| 27 | constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82}; | ||
| 28 | constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84}; | ||
| 29 | constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85}; | ||
| 30 | constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; | ||
| 31 | |||
| 32 | constexpr u64 MAXIMUM_LOADED_RO = 0x40; | ||
| 33 | |||
| 16 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 34 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 17 | public: | 35 | public: |
| 18 | explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { | 36 | explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { |
| @@ -64,9 +82,9 @@ public: | |||
| 64 | // clang-format off | 82 | // clang-format off |
| 65 | static const FunctionInfo functions[] = { | 83 | static const FunctionInfo functions[] = { |
| 66 | {0, &RelocatableObject::LoadNro, "LoadNro"}, | 84 | {0, &RelocatableObject::LoadNro, "LoadNro"}, |
| 67 | {1, nullptr, "UnloadNro"}, | 85 | {1, &RelocatableObject::UnloadNro, "UnloadNro"}, |
| 68 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, | 86 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, |
| 69 | {3, nullptr, "UnloadNrr"}, | 87 | {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, |
| 70 | {4, &RelocatableObject::Initialize, "Initialize"}, | 88 | {4, &RelocatableObject::Initialize, "Initialize"}, |
| 71 | }; | 89 | }; |
| 72 | // clang-format on | 90 | // clang-format on |
| @@ -75,9 +93,126 @@ public: | |||
| 75 | } | 93 | } |
| 76 | 94 | ||
| 77 | void LoadNrr(Kernel::HLERequestContext& ctx) { | 95 | void LoadNrr(Kernel::HLERequestContext& ctx) { |
| 96 | IPC::RequestParser rp{ctx}; | ||
| 97 | rp.Skip(2, false); | ||
| 98 | const VAddr nrr_addr{rp.Pop<VAddr>()}; | ||
| 99 | const u64 nrr_size{rp.Pop<u64>()}; | ||
| 100 | LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr, | ||
| 101 | nrr_size); | ||
| 102 | |||
| 103 | if (!initialized) { | ||
| 104 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | ||
| 105 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 106 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | |||
| 110 | if (nrr.size() >= MAXIMUM_LOADED_RO) { | ||
| 111 | LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs " | ||
| 112 | "(0x40)! Failing..."); | ||
| 113 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 114 | rb.Push(ERROR_MAXIMUM_NRR); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | // NRR Address does not fall on 0x1000 byte boundary | ||
| 119 | if (!Common::Is4KBAligned(nrr_addr)) { | ||
| 120 | LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); | ||
| 121 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 122 | rb.Push(ERROR_INVALID_ALIGNMENT); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | // NRR Size is zero or causes overflow | ||
| 127 | if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) { | ||
| 128 | LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})", | ||
| 129 | nrr_addr, nrr_size); | ||
| 130 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 131 | rb.Push(ERROR_INVALID_SIZE); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | // Read NRR data from memory | ||
| 135 | std::vector<u8> nrr_data(nrr_size); | ||
| 136 | Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size); | ||
| 137 | NRRHeader header; | ||
| 138 | std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); | ||
| 139 | |||
| 140 | if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) { | ||
| 141 | LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic); | ||
| 142 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 143 | rb.Push(ERROR_INVALID_NRR); | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | if (header.size != nrr_size) { | ||
| 148 | LOG_ERROR(Service_LDR, | ||
| 149 | "NRR header reported size did not match LoadNrr parameter size! " | ||
| 150 | "(header_size={:016X}, loadnrr_size={:016X})", | ||
| 151 | header.size, nrr_size); | ||
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 153 | rb.Push(ERROR_INVALID_SIZE); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (Core::CurrentProcess()->GetTitleID() != header.title_id) { | ||
| 158 | LOG_ERROR(Service_LDR, | ||
| 159 | "Attempting to load NRR with title ID other than current process. (actual " | ||
| 160 | "{:016X})!", | ||
| 161 | header.title_id); | ||
| 162 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 163 | rb.Push(ERROR_INVALID_NRR); | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 167 | std::vector<SHA256Hash> hashes; | ||
| 168 | |||
| 169 | // Copy all hashes in the NRR (specified by hash count/hash offset) into vector. | ||
| 170 | for (std::size_t i = header.hash_offset; | ||
| 171 | i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) { | ||
| 172 | SHA256Hash hash; | ||
| 173 | std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash)); | ||
| 174 | hashes.emplace_back(hash); | ||
| 175 | } | ||
| 176 | |||
| 177 | nrr.insert_or_assign(nrr_addr, std::move(hashes)); | ||
| 178 | |||
| 179 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 180 | rb.Push(RESULT_SUCCESS); | ||
| 181 | } | ||
| 182 | |||
| 183 | void UnloadNrr(Kernel::HLERequestContext& ctx) { | ||
| 184 | if (!initialized) { | ||
| 185 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | ||
| 186 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 187 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | IPC::RequestParser rp{ctx}; | ||
| 192 | rp.Skip(2, false); | ||
| 193 | const auto nrr_addr{rp.Pop<VAddr>()}; | ||
| 194 | LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr); | ||
| 195 | |||
| 196 | if (!Common::Is4KBAligned(nrr_addr)) { | ||
| 197 | LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); | ||
| 198 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 199 | rb.Push(ERROR_INVALID_ALIGNMENT); | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 203 | const auto iter = nrr.find(nrr_addr); | ||
| 204 | if (iter == nrr.end()) { | ||
| 205 | LOG_ERROR(Service_LDR, | ||
| 206 | "Attempting to unload NRR which has not been loaded! (addr={:016X})", | ||
| 207 | nrr_addr); | ||
| 208 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 209 | rb.Push(ERROR_INVALID_NRR_ADDRESS); | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | |||
| 213 | nrr.erase(iter); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | 214 | IPC::ResponseBuilder rb{ctx, 2}; |
| 79 | rb.Push(RESULT_SUCCESS); | 215 | rb.Push(RESULT_SUCCESS); |
| 80 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 81 | } | 216 | } |
| 82 | 217 | ||
| 83 | void LoadNro(Kernel::HLERequestContext& ctx) { | 218 | void LoadNro(Kernel::HLERequestContext& ctx) { |
| @@ -87,33 +222,260 @@ public: | |||
| 87 | const u64 nro_size{rp.Pop<u64>()}; | 222 | const u64 nro_size{rp.Pop<u64>()}; |
| 88 | const VAddr bss_addr{rp.Pop<VAddr>()}; | 223 | const VAddr bss_addr{rp.Pop<VAddr>()}; |
| 89 | const u64 bss_size{rp.Pop<u64>()}; | 224 | const u64 bss_size{rp.Pop<u64>()}; |
| 225 | LOG_DEBUG( | ||
| 226 | Service_LDR, | ||
| 227 | "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}", | ||
| 228 | nro_addr, nro_size, bss_addr, bss_size); | ||
| 229 | |||
| 230 | if (!initialized) { | ||
| 231 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | ||
| 232 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 233 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (nro.size() >= MAXIMUM_LOADED_RO) { | ||
| 238 | LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs " | ||
| 239 | "(0x40)! Failing..."); | ||
| 240 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 241 | rb.Push(ERROR_MAXIMUM_NRO); | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | |||
| 245 | // NRO Address does not fall on 0x1000 byte boundary | ||
| 246 | if (!Common::Is4KBAligned(nro_addr)) { | ||
| 247 | LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr); | ||
| 248 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 249 | rb.Push(ERROR_INVALID_ALIGNMENT); | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | |||
| 253 | // NRO Size or BSS Size is zero or causes overflow | ||
| 254 | const auto nro_size_valid = | ||
| 255 | nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size); | ||
| 256 | const auto bss_size_valid = | ||
| 257 | nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr); | ||
| 258 | |||
| 259 | if (!nro_size_valid || !bss_size_valid) { | ||
| 260 | LOG_ERROR(Service_LDR, | ||
| 261 | "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, " | ||
| 262 | "bss_address={:016X}, bss_size={:016X})", | ||
| 263 | nro_addr, nro_size, bss_addr, bss_size); | ||
| 264 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 265 | rb.Push(ERROR_INVALID_SIZE); | ||
| 266 | return; | ||
| 267 | } | ||
| 90 | 268 | ||
| 91 | // Read NRO data from memory | 269 | // Read NRO data from memory |
| 92 | std::vector<u8> nro_data(nro_size); | 270 | std::vector<u8> nro_data(nro_size); |
| 93 | Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); | 271 | Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); |
| 94 | 272 | ||
| 273 | SHA256Hash hash{}; | ||
| 274 | mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0); | ||
| 275 | |||
| 276 | // NRO Hash is already loaded | ||
| 277 | if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) { | ||
| 278 | return info.second.hash == hash; | ||
| 279 | })) { | ||
| 280 | LOG_ERROR(Service_LDR, "NRO is already loaded!"); | ||
| 281 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 282 | rb.Push(ERROR_ALREADY_LOADED); | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | |||
| 286 | // NRO Hash is not in any loaded NRR | ||
| 287 | if (!IsValidNROHash(hash)) { | ||
| 288 | LOG_ERROR(Service_LDR, | ||
| 289 | "NRO hash is not present in any currently loaded NRRs (hash={})!", | ||
| 290 | Common::HexArrayToString(hash)); | ||
| 291 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 292 | rb.Push(ERROR_MISSING_NRR_HASH); | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | |||
| 296 | NROHeader header; | ||
| 297 | std::memcpy(&header, nro_data.data(), sizeof(NROHeader)); | ||
| 298 | |||
| 299 | if (!IsValidNRO(header, nro_size, bss_size)) { | ||
| 300 | LOG_ERROR(Service_LDR, "NRO was invalid!"); | ||
| 301 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 302 | rb.Push(ERROR_INVALID_NRO); | ||
| 303 | return; | ||
| 304 | } | ||
| 305 | |||
| 95 | // Load NRO as new executable module | 306 | // Load NRO as new executable module |
| 96 | const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; | 307 | auto* process = Core::CurrentProcess(); |
| 97 | Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); | 308 | auto& vm_manager = process->VMManager(); |
| 309 | auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size); | ||
| 310 | |||
| 311 | if (!map_address.Succeeded() || | ||
| 312 | *map_address + nro_size + bss_size > vm_manager.GetAddressSpaceEndAddress()) { | ||
| 313 | |||
| 314 | LOG_ERROR(Service_LDR, | ||
| 315 | "General error while allocation memory or no available memory to allocate!"); | ||
| 316 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 317 | rb.Push(ERROR_INVALID_MEMORY_STATE); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size, | ||
| 322 | Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); | ||
| 323 | ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS); | ||
| 324 | |||
| 325 | if (bss_size > 0) { | ||
| 326 | ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size, | ||
| 327 | Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); | ||
| 328 | ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS); | ||
| 329 | } | ||
| 98 | 330 | ||
| 99 | // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. | 331 | vm_manager.ReprotectRange(*map_address, header.text_size, |
| 100 | // It is currently missing: | 332 | Kernel::VMAPermission::ReadExecute); |
| 101 | // - Signature checks with LoadNRR | 333 | vm_manager.ReprotectRange(*map_address + header.ro_offset, header.ro_size, |
| 102 | // - Checking if a module has already been loaded | 334 | Kernel::VMAPermission::Read); |
| 103 | // - Using/validating BSS, etc. params (these are used from NRO header instead) | 335 | vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, |
| 104 | // - Error checking | 336 | Kernel::VMAPermission::ReadWrite); |
| 105 | // - ...Probably other things | 337 | |
| 338 | Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); | ||
| 339 | Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); | ||
| 340 | Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); | ||
| 341 | Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); | ||
| 342 | |||
| 343 | nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size}); | ||
| 106 | 344 | ||
| 107 | IPC::ResponseBuilder rb{ctx, 4}; | 345 | IPC::ResponseBuilder rb{ctx, 4}; |
| 108 | rb.Push(RESULT_SUCCESS); | 346 | rb.Push(RESULT_SUCCESS); |
| 109 | rb.Push(addr); | 347 | rb.Push(*map_address); |
| 110 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 111 | } | 348 | } |
| 112 | 349 | ||
| 113 | void Initialize(Kernel::HLERequestContext& ctx) { | 350 | void UnloadNro(Kernel::HLERequestContext& ctx) { |
| 351 | IPC::RequestParser rp{ctx}; | ||
| 352 | rp.Skip(2, false); | ||
| 353 | const VAddr mapped_addr{rp.PopRaw<VAddr>()}; | ||
| 354 | const VAddr heap_addr{rp.PopRaw<VAddr>()}; | ||
| 355 | LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr, | ||
| 356 | heap_addr); | ||
| 357 | |||
| 358 | if (!initialized) { | ||
| 359 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | ||
| 360 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 361 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 365 | if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) { | ||
| 366 | LOG_ERROR(Service_LDR, | ||
| 367 | "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, " | ||
| 368 | "bss_addr={:016X})!", | ||
| 369 | mapped_addr, heap_addr); | ||
| 370 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 371 | rb.Push(ERROR_INVALID_ALIGNMENT); | ||
| 372 | return; | ||
| 373 | } | ||
| 374 | |||
| 375 | const auto iter = nro.find(mapped_addr); | ||
| 376 | if (iter == nro.end()) { | ||
| 377 | LOG_ERROR(Service_LDR, | ||
| 378 | "The NRO attempting to unmap was not mapped or has an invalid address " | ||
| 379 | "(actual {:016X})!", | ||
| 380 | mapped_addr); | ||
| 381 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 382 | rb.Push(ERROR_INVALID_NRO_ADDRESS); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 386 | auto* process = Core::CurrentProcess(); | ||
| 387 | auto& vm_manager = process->VMManager(); | ||
| 388 | const auto& nro_size = iter->second.size; | ||
| 389 | |||
| 390 | ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size, | ||
| 391 | Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); | ||
| 392 | ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); | ||
| 393 | |||
| 394 | Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); | ||
| 395 | Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); | ||
| 396 | Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); | ||
| 397 | Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); | ||
| 398 | |||
| 399 | nro.erase(iter); | ||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | 400 | IPC::ResponseBuilder rb{ctx, 2}; |
| 115 | rb.Push(RESULT_SUCCESS); | 401 | rb.Push(RESULT_SUCCESS); |
| 402 | } | ||
| 403 | |||
| 404 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 116 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | 405 | LOG_WARNING(Service_LDR, "(STUBBED) called"); |
| 406 | |||
| 407 | initialized = true; | ||
| 408 | |||
| 409 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 410 | rb.Push(RESULT_SUCCESS); | ||
| 411 | } | ||
| 412 | |||
| 413 | private: | ||
| 414 | using SHA256Hash = std::array<u8, 0x20>; | ||
| 415 | |||
| 416 | struct NROHeader { | ||
| 417 | u32_le entrypoint_insn; | ||
| 418 | u32_le mod_offset; | ||
| 419 | INSERT_PADDING_WORDS(2); | ||
| 420 | u32_le magic; | ||
| 421 | INSERT_PADDING_WORDS(1); | ||
| 422 | u32_le nro_size; | ||
| 423 | INSERT_PADDING_WORDS(1); | ||
| 424 | u32_le text_offset; | ||
| 425 | u32_le text_size; | ||
| 426 | u32_le ro_offset; | ||
| 427 | u32_le ro_size; | ||
| 428 | u32_le rw_offset; | ||
| 429 | u32_le rw_size; | ||
| 430 | u32_le bss_size; | ||
| 431 | INSERT_PADDING_WORDS(1); | ||
| 432 | std::array<u8, 0x20> build_id; | ||
| 433 | INSERT_PADDING_BYTES(0x20); | ||
| 434 | }; | ||
| 435 | static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); | ||
| 436 | |||
| 437 | struct NRRHeader { | ||
| 438 | u32_le magic; | ||
| 439 | INSERT_PADDING_BYTES(0x1C); | ||
| 440 | u64_le title_id_mask; | ||
| 441 | u64_le title_id_pattern; | ||
| 442 | std::array<u8, 0x100> modulus; | ||
| 443 | std::array<u8, 0x100> signature_1; | ||
| 444 | std::array<u8, 0x100> signature_2; | ||
| 445 | u64_le title_id; | ||
| 446 | u32_le size; | ||
| 447 | INSERT_PADDING_BYTES(4); | ||
| 448 | u32_le hash_offset; | ||
| 449 | u32_le hash_count; | ||
| 450 | INSERT_PADDING_BYTES(8); | ||
| 451 | }; | ||
| 452 | static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size."); | ||
| 453 | |||
| 454 | struct NROInfo { | ||
| 455 | SHA256Hash hash; | ||
| 456 | u64 size; | ||
| 457 | }; | ||
| 458 | |||
| 459 | bool initialized = false; | ||
| 460 | |||
| 461 | std::map<VAddr, NROInfo> nro; | ||
| 462 | std::map<VAddr, std::vector<SHA256Hash>> nrr; | ||
| 463 | |||
| 464 | bool IsValidNROHash(const SHA256Hash& hash) { | ||
| 465 | return std::any_of( | ||
| 466 | nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) { | ||
| 467 | return std::find(p.second.begin(), p.second.end(), hash) != p.second.end(); | ||
| 468 | }); | ||
| 469 | } | ||
| 470 | |||
| 471 | static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { | ||
| 472 | return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && | ||
| 473 | header.nro_size == nro_size && header.bss_size == bss_size && | ||
| 474 | header.ro_offset == header.text_offset + header.text_size && | ||
| 475 | header.rw_offset == header.ro_offset + header.ro_size && | ||
| 476 | nro_size == header.rw_offset + header.rw_size && | ||
| 477 | Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && | ||
| 478 | Common::Is4KBAligned(header.rw_size); | ||
| 117 | } | 479 | } |
| 118 | }; | 480 | }; |
| 119 | 481 | ||
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index c89157a4d..1f462e087 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -18,7 +18,7 @@ public: | |||
| 18 | ILogger() : ServiceFramework("ILogger") { | 18 | ILogger() : ServiceFramework("ILogger") { |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {0x00000000, &ILogger::Initialize, "Initialize"}, | 20 | {0x00000000, &ILogger::Initialize, "Initialize"}, |
| 21 | {0x00000001, nullptr, "SetDestination"}, | 21 | {0x00000001, &ILogger::SetDestination, "SetDestination"}, |
| 22 | }; | 22 | }; |
| 23 | RegisterHandlers(functions); | 23 | RegisterHandlers(functions); |
| 24 | } | 24 | } |
| @@ -178,6 +178,17 @@ private: | |||
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | // This service function is intended to be used as a way to | ||
| 182 | // redirect logging output to different destinations, however, | ||
| 183 | // given we always want to see the logging output, it's sufficient | ||
| 184 | // to do nothing and return success here. | ||
| 185 | void SetDestination(Kernel::HLERequestContext& ctx) { | ||
| 186 | LOG_DEBUG(Service_LM, "called"); | ||
| 187 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 189 | rb.Push(RESULT_SUCCESS); | ||
| 190 | } | ||
| 191 | |||
| 181 | std::ostringstream log_stream; | 192 | std::ostringstream log_stream; |
| 182 | }; | 193 | }; |
| 183 | 194 | ||
| @@ -198,11 +209,11 @@ public: | |||
| 198 | * 0: ResultCode | 209 | * 0: ResultCode |
| 199 | */ | 210 | */ |
| 200 | void OpenLogger(Kernel::HLERequestContext& ctx) { | 211 | void OpenLogger(Kernel::HLERequestContext& ctx) { |
| 212 | LOG_DEBUG(Service_LM, "called"); | ||
| 213 | |||
| 201 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 214 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 202 | rb.Push(RESULT_SUCCESS); | 215 | rb.Push(RESULT_SUCCESS); |
| 203 | rb.PushIpcInterface<ILogger>(); | 216 | rb.PushIpcInterface<ILogger>(); |
| 204 | |||
| 205 | LOG_DEBUG(Service_LM, "called"); | ||
| 206 | } | 217 | } |
| 207 | }; | 218 | }; |
| 208 | 219 | ||
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index e1f17a926..def63dc8a 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp | |||
| @@ -31,12 +31,14 @@ public: | |||
| 31 | private: | 31 | private: |
| 32 | void Initialize(Kernel::HLERequestContext& ctx) { | 32 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 33 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 33 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 34 | |||
| 34 | IPC::ResponseBuilder rb{ctx, 2}; | 35 | IPC::ResponseBuilder rb{ctx, 2}; |
| 35 | rb.Push(RESULT_SUCCESS); | 36 | rb.Push(RESULT_SUCCESS); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | void Finalize(Kernel::HLERequestContext& ctx) { | 39 | void Finalize(Kernel::HLERequestContext& ctx) { |
| 39 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 40 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 41 | |||
| 40 | IPC::ResponseBuilder rb{ctx, 2}; | 42 | IPC::ResponseBuilder rb{ctx, 2}; |
| 41 | rb.Push(RESULT_SUCCESS); | 43 | rb.Push(RESULT_SUCCESS); |
| 42 | } | 44 | } |
| @@ -45,15 +47,16 @@ private: | |||
| 45 | IPC::RequestParser rp{ctx}; | 47 | IPC::RequestParser rp{ctx}; |
| 46 | min = rp.Pop<u32>(); | 48 | min = rp.Pop<u32>(); |
| 47 | max = rp.Pop<u32>(); | 49 | max = rp.Pop<u32>(); |
| 48 | current = min; | ||
| 49 | |||
| 50 | LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); | 50 | LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); |
| 51 | |||
| 52 | current = min; | ||
| 51 | IPC::ResponseBuilder rb{ctx, 2}; | 53 | IPC::ResponseBuilder rb{ctx, 2}; |
| 52 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | void Get(Kernel::HLERequestContext& ctx) { | 57 | void Get(Kernel::HLERequestContext& ctx) { |
| 56 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 58 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 59 | |||
| 57 | IPC::ResponseBuilder rb{ctx, 3}; | 60 | IPC::ResponseBuilder rb{ctx, 3}; |
| 58 | rb.Push(RESULT_SUCCESS); | 61 | rb.Push(RESULT_SUCCESS); |
| 59 | rb.Push(current); | 62 | rb.Push(current); |
| @@ -61,6 +64,7 @@ private: | |||
| 61 | 64 | ||
| 62 | void InitializeWithId(Kernel::HLERequestContext& ctx) { | 65 | void InitializeWithId(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 66 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 67 | |||
| 64 | IPC::ResponseBuilder rb{ctx, 3}; | 68 | IPC::ResponseBuilder rb{ctx, 3}; |
| 65 | rb.Push(RESULT_SUCCESS); | 69 | rb.Push(RESULT_SUCCESS); |
| 66 | rb.Push<u32>(id); // Any non zero value | 70 | rb.Push<u32>(id); // Any non zero value |
| @@ -68,6 +72,7 @@ private: | |||
| 68 | 72 | ||
| 69 | void FinalizeWithId(Kernel::HLERequestContext& ctx) { | 73 | void FinalizeWithId(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 74 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 75 | |||
| 71 | IPC::ResponseBuilder rb{ctx, 2}; | 76 | IPC::ResponseBuilder rb{ctx, 2}; |
| 72 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 73 | } | 78 | } |
| @@ -77,16 +82,17 @@ private: | |||
| 77 | u32 input_id = rp.Pop<u32>(); | 82 | u32 input_id = rp.Pop<u32>(); |
| 78 | min = rp.Pop<u32>(); | 83 | min = rp.Pop<u32>(); |
| 79 | max = rp.Pop<u32>(); | 84 | max = rp.Pop<u32>(); |
| 80 | current = min; | ||
| 81 | |||
| 82 | LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", | 85 | LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", |
| 83 | input_id, min, max); | 86 | input_id, min, max); |
| 87 | |||
| 88 | current = min; | ||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 89 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 86 | } | 91 | } |
| 87 | 92 | ||
| 88 | void GetWithId(Kernel::HLERequestContext& ctx) { | 93 | void GetWithId(Kernel::HLERequestContext& ctx) { |
| 89 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 94 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 95 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 3}; | 96 | IPC::ResponseBuilder rb{ctx, 3}; |
| 91 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 92 | rb.Push(current); | 98 | rb.Push(current); |
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 30e542542..5c62d42ba 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp | |||
| @@ -43,11 +43,11 @@ public: | |||
| 43 | 43 | ||
| 44 | private: | 44 | private: |
| 45 | void CreateAmInterface(Kernel::HLERequestContext& ctx) { | 45 | void CreateAmInterface(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_DEBUG(Service_NFC, "called"); | ||
| 47 | |||
| 46 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 47 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 48 | rb.PushIpcInterface<IAm>(); | 50 | rb.PushIpcInterface<IAm>(); |
| 49 | |||
| 50 | LOG_DEBUG(Service_NFC, "called"); | ||
| 51 | } | 51 | } |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| @@ -91,11 +91,11 @@ public: | |||
| 91 | 91 | ||
| 92 | private: | 92 | private: |
| 93 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { | 93 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_NFC, "called"); | ||
| 95 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 95 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 96 | rb.PushIpcInterface<MFIUser>(); | 98 | rb.PushIpcInterface<MFIUser>(); |
| 97 | |||
| 98 | LOG_DEBUG(Service_NFC, "called"); | ||
| 99 | } | 99 | } |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| @@ -138,19 +138,19 @@ private: | |||
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | void InitializeOld(Kernel::HLERequestContext& ctx) { | 140 | void InitializeOld(Kernel::HLERequestContext& ctx) { |
| 141 | LOG_DEBUG(Service_NFC, "called"); | ||
| 142 | |||
| 141 | IPC::ResponseBuilder rb{ctx, 2, 0}; | 143 | IPC::ResponseBuilder rb{ctx, 2, 0}; |
| 142 | rb.Push(RESULT_SUCCESS); | 144 | rb.Push(RESULT_SUCCESS); |
| 143 | |||
| 144 | // We don't deal with hardware initialization so we can just stub this. | 145 | // We don't deal with hardware initialization so we can just stub this. |
| 145 | LOG_DEBUG(Service_NFC, "called"); | ||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { | 148 | void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { |
| 149 | LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); | ||
| 150 | |||
| 149 | IPC::ResponseBuilder rb{ctx, 3}; | 151 | IPC::ResponseBuilder rb{ctx, 3}; |
| 150 | rb.Push(RESULT_SUCCESS); | 152 | rb.Push(RESULT_SUCCESS); |
| 151 | rb.PushRaw<u8>(Settings::values.enable_nfc); | 153 | rb.PushRaw<u8>(Settings::values.enable_nfc); |
| 152 | |||
| 153 | LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); | ||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void GetStateOld(Kernel::HLERequestContext& ctx) { | 156 | void GetStateOld(Kernel::HLERequestContext& ctx) { |
| @@ -183,11 +183,11 @@ public: | |||
| 183 | 183 | ||
| 184 | private: | 184 | private: |
| 185 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { | 185 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 186 | LOG_DEBUG(Service_NFC, "called"); | ||
| 187 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 187 | rb.Push(RESULT_SUCCESS); | 189 | rb.Push(RESULT_SUCCESS); |
| 188 | rb.PushIpcInterface<IUser>(); | 190 | rb.PushIpcInterface<IUser>(); |
| 189 | |||
| 190 | LOG_DEBUG(Service_NFC, "called"); | ||
| 191 | } | 191 | } |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| @@ -241,11 +241,11 @@ public: | |||
| 241 | 241 | ||
| 242 | private: | 242 | private: |
| 243 | void CreateSystemInterface(Kernel::HLERequestContext& ctx) { | 243 | void CreateSystemInterface(Kernel::HLERequestContext& ctx) { |
| 244 | LOG_DEBUG(Service_NFC, "called"); | ||
| 245 | |||
| 244 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 246 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 245 | rb.Push(RESULT_SUCCESS); | 247 | rb.Push(RESULT_SUCCESS); |
| 246 | rb.PushIpcInterface<ISystem>(); | 248 | rb.PushIpcInterface<ISystem>(); |
| 247 | |||
| 248 | LOG_DEBUG(Service_NFC, "called"); | ||
| 249 | } | 249 | } |
| 250 | }; | 250 | }; |
| 251 | 251 | ||
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index c1af878fe..d5df112a0 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 11 | #include "core/hle/lock.h" | 13 | #include "core/hle/lock.h" |
| 12 | #include "core/hle/service/hid/hid.h" | 14 | #include "core/hle/service/hid/hid.h" |
| 13 | #include "core/hle/service/nfp/nfp.h" | 15 | #include "core/hle/service/nfp/nfp.h" |
| @@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, | |||
| 23 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 25 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
| 24 | : ServiceFramework(name), module(std::move(module)) { | 26 | : ServiceFramework(name), module(std::move(module)) { |
| 25 | auto& kernel = Core::System::GetInstance().Kernel(); | 27 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 26 | nfc_tag_load = | 28 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, |
| 27 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); | 29 | "IUser:NFCTagDetected"); |
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | Module::Interface::~Interface() = default; | 32 | Module::Interface::~Interface() = default; |
| @@ -63,10 +65,10 @@ public: | |||
| 63 | RegisterHandlers(functions); | 65 | RegisterHandlers(functions); |
| 64 | 66 | ||
| 65 | auto& kernel = Core::System::GetInstance().Kernel(); | 67 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 66 | deactivate_event = | 68 | deactivate_event = Kernel::WritableEvent::CreateEventPair( |
| 67 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); | 69 | kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); |
| 68 | availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | 70 | availability_change_event = Kernel::WritableEvent::CreateEventPair( |
| 69 | "IUser:AvailabilityChangeEvent"); | 71 | kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent"); |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | private: | 74 | private: |
| @@ -108,30 +110,29 @@ private: | |||
| 108 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | 110 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); |
| 109 | 111 | ||
| 110 | void Initialize(Kernel::HLERequestContext& ctx) { | 112 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 113 | LOG_DEBUG(Service_NFC, "called"); | ||
| 114 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2, 0}; | 115 | IPC::ResponseBuilder rb{ctx, 2, 0}; |
| 112 | rb.Push(RESULT_SUCCESS); | 116 | rb.Push(RESULT_SUCCESS); |
| 113 | 117 | ||
| 114 | state = State::Initialized; | 118 | state = State::Initialized; |
| 115 | |||
| 116 | LOG_DEBUG(Service_NFC, "called"); | ||
| 117 | } | 119 | } |
| 118 | 120 | ||
| 119 | void GetState(Kernel::HLERequestContext& ctx) { | 121 | void GetState(Kernel::HLERequestContext& ctx) { |
| 122 | LOG_DEBUG(Service_NFC, "called"); | ||
| 123 | |||
| 120 | IPC::ResponseBuilder rb{ctx, 3, 0}; | 124 | IPC::ResponseBuilder rb{ctx, 3, 0}; |
| 121 | rb.Push(RESULT_SUCCESS); | 125 | rb.Push(RESULT_SUCCESS); |
| 122 | rb.PushRaw<u32>(static_cast<u32>(state)); | 126 | rb.PushRaw<u32>(static_cast<u32>(state)); |
| 123 | |||
| 124 | LOG_DEBUG(Service_NFC, "called"); | ||
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | void ListDevices(Kernel::HLERequestContext& ctx) { | 129 | void ListDevices(Kernel::HLERequestContext& ctx) { |
| 128 | IPC::RequestParser rp{ctx}; | 130 | IPC::RequestParser rp{ctx}; |
| 129 | const u32 array_size = rp.Pop<u32>(); | 131 | const u32 array_size = rp.Pop<u32>(); |
| 132 | LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | ||
| 130 | 133 | ||
| 131 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); | 134 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); |
| 132 | 135 | ||
| 133 | LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | ||
| 134 | |||
| 135 | IPC::ResponseBuilder rb{ctx, 3}; | 136 | IPC::ResponseBuilder rb{ctx, 3}; |
| 136 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 137 | rb.Push<u32>(1); | 138 | rb.Push<u32>(1); |
| @@ -141,6 +142,7 @@ private: | |||
| 141 | IPC::RequestParser rp{ctx}; | 142 | IPC::RequestParser rp{ctx}; |
| 142 | const u64 dev_handle = rp.Pop<u64>(); | 143 | const u64 dev_handle = rp.Pop<u64>(); |
| 143 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 144 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); |
| 145 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 3}; | 146 | IPC::ResponseBuilder rb{ctx, 3}; |
| 145 | rb.Push(RESULT_SUCCESS); | 147 | rb.Push(RESULT_SUCCESS); |
| 146 | rb.Push<u32>(npad_id); | 148 | rb.Push<u32>(npad_id); |
| @@ -150,6 +152,7 @@ private: | |||
| 150 | IPC::RequestParser rp{ctx}; | 152 | IPC::RequestParser rp{ctx}; |
| 151 | const u64 dev_handle = rp.Pop<u64>(); | 153 | const u64 dev_handle = rp.Pop<u64>(); |
| 152 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 154 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); |
| 155 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 156 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 154 | rb.Push(RESULT_SUCCESS); | 157 | rb.Push(RESULT_SUCCESS); |
| 155 | rb.PushCopyObjects(nfp_interface.GetNFCEvent()); | 158 | rb.PushCopyObjects(nfp_interface.GetNFCEvent()); |
| @@ -163,15 +166,16 @@ private: | |||
| 163 | 166 | ||
| 164 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 167 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 165 | rb.Push(RESULT_SUCCESS); | 168 | rb.Push(RESULT_SUCCESS); |
| 166 | rb.PushCopyObjects(deactivate_event); | 169 | rb.PushCopyObjects(deactivate_event.readable); |
| 167 | } | 170 | } |
| 168 | 171 | ||
| 169 | void StopDetection(Kernel::HLERequestContext& ctx) { | 172 | void StopDetection(Kernel::HLERequestContext& ctx) { |
| 170 | LOG_DEBUG(Service_NFP, "called"); | 173 | LOG_DEBUG(Service_NFP, "called"); |
| 174 | |||
| 171 | switch (device_state) { | 175 | switch (device_state) { |
| 172 | case DeviceState::TagFound: | 176 | case DeviceState::TagFound: |
| 173 | case DeviceState::TagNearby: | 177 | case DeviceState::TagNearby: |
| 174 | deactivate_event->Signal(); | 178 | deactivate_event.writable->Signal(); |
| 175 | device_state = DeviceState::Initialized; | 179 | device_state = DeviceState::Initialized; |
| 176 | break; | 180 | break; |
| 177 | case DeviceState::SearchingForTag: | 181 | case DeviceState::SearchingForTag: |
| @@ -185,6 +189,7 @@ private: | |||
| 185 | 189 | ||
| 186 | void GetDeviceState(Kernel::HLERequestContext& ctx) { | 190 | void GetDeviceState(Kernel::HLERequestContext& ctx) { |
| 187 | LOG_DEBUG(Service_NFP, "called"); | 191 | LOG_DEBUG(Service_NFP, "called"); |
| 192 | |||
| 188 | auto nfc_event = nfp_interface.GetNFCEvent(); | 193 | auto nfc_event = nfp_interface.GetNFCEvent(); |
| 189 | if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { | 194 | if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { |
| 190 | device_state = DeviceState::TagFound; | 195 | device_state = DeviceState::TagFound; |
| @@ -212,7 +217,7 @@ private: | |||
| 212 | IPC::ResponseBuilder rb{ctx, 2}; | 217 | IPC::ResponseBuilder rb{ctx, 2}; |
| 213 | auto amiibo = nfp_interface.GetAmiiboBuffer(); | 218 | auto amiibo = nfp_interface.GetAmiiboBuffer(); |
| 214 | TagInfo tag_info{}; | 219 | TagInfo tag_info{}; |
| 215 | std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size())); | 220 | tag_info.uuid = amiibo.uuid; |
| 216 | tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); | 221 | tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); |
| 217 | 222 | ||
| 218 | tag_info.protocol = 1; // TODO(ogniK): Figure out actual values | 223 | tag_info.protocol = 1; // TODO(ogniK): Figure out actual values |
| @@ -261,7 +266,7 @@ private: | |||
| 261 | 266 | ||
| 262 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 267 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 263 | rb.Push(RESULT_SUCCESS); | 268 | rb.Push(RESULT_SUCCESS); |
| 264 | rb.PushCopyObjects(availability_change_event); | 269 | rb.PushCopyObjects(availability_change_event.readable); |
| 265 | } | 270 | } |
| 266 | 271 | ||
| 267 | void GetRegisterInfo(Kernel::HLERequestContext& ctx) { | 272 | void GetRegisterInfo(Kernel::HLERequestContext& ctx) { |
| @@ -316,13 +321,14 @@ private: | |||
| 316 | const u32 npad_id{0}; // Player 1 controller | 321 | const u32 npad_id{0}; // Player 1 controller |
| 317 | State state{State::NonInitialized}; | 322 | State state{State::NonInitialized}; |
| 318 | DeviceState device_state{DeviceState::Initialized}; | 323 | DeviceState device_state{DeviceState::Initialized}; |
| 319 | Kernel::SharedPtr<Kernel::Event> deactivate_event; | 324 | Kernel::EventPair deactivate_event; |
| 320 | Kernel::SharedPtr<Kernel::Event> availability_change_event; | 325 | Kernel::EventPair availability_change_event; |
| 321 | const Module::Interface& nfp_interface; | 326 | const Module::Interface& nfp_interface; |
| 322 | }; | 327 | }; |
| 323 | 328 | ||
| 324 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | 329 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 325 | LOG_DEBUG(Service_NFP, "called"); | 330 | LOG_DEBUG(Service_NFP, "called"); |
| 331 | |||
| 326 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 332 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 327 | rb.Push(RESULT_SUCCESS); | 333 | rb.Push(RESULT_SUCCESS); |
| 328 | rb.PushIpcInterface<IUser>(*this); | 334 | rb.PushIpcInterface<IUser>(*this); |
| @@ -335,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||
| 335 | } | 341 | } |
| 336 | 342 | ||
| 337 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 343 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |
| 338 | nfc_tag_load->Signal(); | 344 | nfc_tag_load.writable->Signal(); |
| 339 | return true; | 345 | return true; |
| 340 | } | 346 | } |
| 341 | const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { | 347 | |
| 342 | return nfc_tag_load; | 348 | const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { |
| 349 | return nfc_tag_load.readable; | ||
| 343 | } | 350 | } |
| 351 | |||
| 344 | const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { | 352 | const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { |
| 345 | return amiibo; | 353 | return amiibo; |
| 346 | } | 354 | } |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 5c0ae8a54..a1817e991 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/readable_event.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 11 | 12 | ||
| 12 | namespace Service::NFP { | 13 | namespace Service::NFP { |
| @@ -33,11 +34,11 @@ public: | |||
| 33 | 34 | ||
| 34 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | 35 | void CreateUserInterface(Kernel::HLERequestContext& ctx); |
| 35 | bool LoadAmiibo(const std::vector<u8>& buffer); | 36 | bool LoadAmiibo(const std::vector<u8>& buffer); |
| 36 | const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; | 37 | const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const; |
| 37 | const AmiiboFile& GetAmiiboBuffer() const; | 38 | const AmiiboFile& GetAmiiboBuffer() const; |
| 38 | 39 | ||
| 39 | private: | 40 | private: |
| 40 | Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; | 41 | Kernel::EventPair nfc_tag_load{}; |
| 41 | AmiiboFile amiibo{}; | 42 | AmiiboFile amiibo{}; |
| 42 | 43 | ||
| 43 | protected: | 44 | protected: |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 75dcd94a3..60479bb45 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -4,7 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/event.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/readable_event.h" | ||
| 9 | #include "core/hle/kernel/writable_event.h" | ||
| 8 | #include "core/hle/service/nifm/nifm.h" | 10 | #include "core/hle/service/nifm/nifm.h" |
| 9 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 10 | 12 | ||
| @@ -56,19 +58,23 @@ public: | |||
| 56 | RegisterHandlers(functions); | 58 | RegisterHandlers(functions); |
| 57 | 59 | ||
| 58 | auto& kernel = Core::System::GetInstance().Kernel(); | 60 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 59 | event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); | 61 | event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, |
| 60 | event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); | 62 | "IRequest:Event1"); |
| 63 | event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, | ||
| 64 | "IRequest:Event2"); | ||
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | private: | 67 | private: |
| 64 | void Submit(Kernel::HLERequestContext& ctx) { | 68 | void Submit(Kernel::HLERequestContext& ctx) { |
| 65 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 69 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 70 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2}; | 71 | IPC::ResponseBuilder rb{ctx, 2}; |
| 67 | rb.Push(RESULT_SUCCESS); | 72 | rb.Push(RESULT_SUCCESS); |
| 68 | } | 73 | } |
| 69 | 74 | ||
| 70 | void GetRequestState(Kernel::HLERequestContext& ctx) { | 75 | void GetRequestState(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 76 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 77 | |||
| 72 | IPC::ResponseBuilder rb{ctx, 3}; | 78 | IPC::ResponseBuilder rb{ctx, 3}; |
| 73 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| 74 | rb.Push<u32>(0); | 80 | rb.Push<u32>(0); |
| @@ -76,30 +82,34 @@ private: | |||
| 76 | 82 | ||
| 77 | void GetResult(Kernel::HLERequestContext& ctx) { | 83 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 78 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 84 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 85 | |||
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 86 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | rb.Push(RESULT_SUCCESS); | 87 | rb.Push(RESULT_SUCCESS); |
| 81 | } | 88 | } |
| 82 | 89 | ||
| 83 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { | 90 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { |
| 84 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 91 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 92 | |||
| 85 | IPC::ResponseBuilder rb{ctx, 2, 2}; | 93 | IPC::ResponseBuilder rb{ctx, 2, 2}; |
| 86 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 87 | rb.PushCopyObjects(event1, event2); | 95 | rb.PushCopyObjects(event1.readable, event2.readable); |
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | void Cancel(Kernel::HLERequestContext& ctx) { | 98 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 99 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 100 | |||
| 92 | IPC::ResponseBuilder rb{ctx, 2}; | 101 | IPC::ResponseBuilder rb{ctx, 2}; |
| 93 | rb.Push(RESULT_SUCCESS); | 102 | rb.Push(RESULT_SUCCESS); |
| 94 | } | 103 | } |
| 95 | 104 | ||
| 96 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { | 105 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { |
| 97 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 106 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 107 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 100 | } | 110 | } |
| 101 | 111 | ||
| 102 | Kernel::SharedPtr<Kernel::Event> event1, event2; | 112 | Kernel::EventPair event1, event2; |
| 103 | }; | 113 | }; |
| 104 | 114 | ||
| 105 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { | 115 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { |
| @@ -122,32 +132,36 @@ private: | |||
| 122 | void GetClientId(Kernel::HLERequestContext& ctx) { | 132 | void GetClientId(Kernel::HLERequestContext& ctx) { |
| 123 | static constexpr u32 client_id = 1; | 133 | static constexpr u32 client_id = 1; |
| 124 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 134 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 135 | |||
| 125 | IPC::ResponseBuilder rb{ctx, 4}; | 136 | IPC::ResponseBuilder rb{ctx, 4}; |
| 126 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 127 | rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid | 138 | rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid |
| 128 | } | 139 | } |
| 129 | void CreateScanRequest(Kernel::HLERequestContext& ctx) { | 140 | void CreateScanRequest(Kernel::HLERequestContext& ctx) { |
| 141 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 142 | |||
| 130 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 143 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 131 | 144 | ||
| 132 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 133 | rb.PushIpcInterface<IScanRequest>(); | 146 | rb.PushIpcInterface<IScanRequest>(); |
| 134 | |||
| 135 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 136 | } | 147 | } |
| 137 | void CreateRequest(Kernel::HLERequestContext& ctx) { | 148 | void CreateRequest(Kernel::HLERequestContext& ctx) { |
| 149 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 150 | |||
| 138 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 151 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 139 | 152 | ||
| 140 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| 141 | rb.PushIpcInterface<IRequest>(); | 154 | rb.PushIpcInterface<IRequest>(); |
| 142 | |||
| 143 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 144 | } | 155 | } |
| 145 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 156 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 146 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 157 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 158 | |||
| 147 | IPC::ResponseBuilder rb{ctx, 2}; | 159 | IPC::ResponseBuilder rb{ctx, 2}; |
| 148 | rb.Push(RESULT_SUCCESS); | 160 | rb.Push(RESULT_SUCCESS); |
| 149 | } | 161 | } |
| 150 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { | 162 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 163 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 164 | |||
| 151 | ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); | 165 | ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); |
| 152 | u128 uuid{}; | 166 | u128 uuid{}; |
| 153 | auto buffer = ctx.ReadBuffer(); | 167 | auto buffer = ctx.ReadBuffer(); |
| @@ -158,23 +172,24 @@ private: | |||
| 158 | rb.Push(RESULT_SUCCESS); | 172 | rb.Push(RESULT_SUCCESS); |
| 159 | rb.PushIpcInterface<INetworkProfile>(); | 173 | rb.PushIpcInterface<INetworkProfile>(); |
| 160 | rb.PushRaw<u128>(uuid); | 174 | rb.PushRaw<u128>(uuid); |
| 161 | |||
| 162 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 163 | } | 175 | } |
| 164 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 176 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 177 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 178 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 3}; | 179 | IPC::ResponseBuilder rb{ctx, 3}; |
| 167 | rb.Push(RESULT_SUCCESS); | 180 | rb.Push(RESULT_SUCCESS); |
| 168 | rb.Push<u8>(0); | 181 | rb.Push<u8>(0); |
| 169 | } | 182 | } |
| 170 | void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 183 | void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| 171 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 184 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 185 | |||
| 172 | IPC::ResponseBuilder rb{ctx, 3}; | 186 | IPC::ResponseBuilder rb{ctx, 3}; |
| 173 | rb.Push(RESULT_SUCCESS); | 187 | rb.Push(RESULT_SUCCESS); |
| 174 | rb.Push<u8>(0); | 188 | rb.Push<u8>(0); |
| 175 | } | 189 | } |
| 176 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { | 190 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { |
| 177 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 191 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 192 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 3}; | 193 | IPC::ResponseBuilder rb{ctx, 3}; |
| 179 | rb.Push(RESULT_SUCCESS); | 194 | rb.Push(RESULT_SUCCESS); |
| 180 | rb.Push<u8>(0); | 195 | rb.Push<u8>(0); |
| @@ -235,17 +250,19 @@ public: | |||
| 235 | } | 250 | } |
| 236 | 251 | ||
| 237 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 252 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { |
| 253 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 254 | |||
| 238 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 255 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 239 | rb.Push(RESULT_SUCCESS); | 256 | rb.Push(RESULT_SUCCESS); |
| 240 | rb.PushIpcInterface<IGeneralService>(); | 257 | rb.PushIpcInterface<IGeneralService>(); |
| 241 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 242 | } | 258 | } |
| 243 | 259 | ||
| 244 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { | 260 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { |
| 261 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 262 | |||
| 245 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 263 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 246 | rb.Push(RESULT_SUCCESS); | 264 | rb.Push(RESULT_SUCCESS); |
| 247 | rb.PushIpcInterface<IGeneralService>(); | 265 | rb.PushIpcInterface<IGeneralService>(); |
| 248 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 249 | } | 266 | } |
| 250 | }; | 267 | }; |
| 251 | 268 | ||
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 18091c9bb..0dabcd23b 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -6,7 +6,9 @@ | |||
| 6 | #include <ctime> | 6 | #include <ctime> |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/nim/nim.h" | 12 | #include "core/hle/service/nim/nim.h" |
| 11 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 12 | #include "core/hle/service/sm/sm.h" | 14 | #include "core/hle/service/sm/sm.h" |
| @@ -138,57 +140,61 @@ public: | |||
| 138 | RegisterHandlers(functions); | 140 | RegisterHandlers(functions); |
| 139 | 141 | ||
| 140 | auto& kernel = Core::System::GetInstance().Kernel(); | 142 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 141 | finished_event = | 143 | finished_event = Kernel::WritableEvent::CreateEventPair( |
| 142 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | 144 | kernel, Kernel::ResetType::OneShot, |
| 143 | "IEnsureNetworkClockAvailabilityService:FinishEvent"); | 145 | "IEnsureNetworkClockAvailabilityService:FinishEvent"); |
| 144 | } | 146 | } |
| 145 | 147 | ||
| 146 | private: | 148 | private: |
| 147 | Kernel::SharedPtr<Kernel::Event> finished_event; | 149 | Kernel::EventPair finished_event; |
| 148 | 150 | ||
| 149 | void StartTask(Kernel::HLERequestContext& ctx) { | 151 | void StartTask(Kernel::HLERequestContext& ctx) { |
| 150 | // No need to connect to the internet, just finish the task straight away. | 152 | // No need to connect to the internet, just finish the task straight away. |
| 151 | finished_event->Signal(); | 153 | LOG_DEBUG(Service_NIM, "called"); |
| 154 | finished_event.writable->Signal(); | ||
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | 155 | IPC::ResponseBuilder rb{ctx, 2}; |
| 153 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 154 | LOG_DEBUG(Service_NIM, "called"); | ||
| 155 | } | 157 | } |
| 156 | 158 | ||
| 157 | void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { | 159 | void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { |
| 160 | LOG_DEBUG(Service_NIM, "called"); | ||
| 161 | |||
| 158 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 162 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 159 | rb.Push(RESULT_SUCCESS); | 163 | rb.Push(RESULT_SUCCESS); |
| 160 | rb.PushCopyObjects(finished_event); | 164 | rb.PushCopyObjects(finished_event.readable); |
| 161 | LOG_DEBUG(Service_NIM, "called"); | ||
| 162 | } | 165 | } |
| 163 | 166 | ||
| 164 | void GetResult(Kernel::HLERequestContext& ctx) { | 167 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 168 | LOG_DEBUG(Service_NIM, "called"); | ||
| 169 | |||
| 165 | IPC::ResponseBuilder rb{ctx, 2}; | 170 | IPC::ResponseBuilder rb{ctx, 2}; |
| 166 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| 167 | LOG_DEBUG(Service_NIM, "called"); | ||
| 168 | } | 172 | } |
| 169 | 173 | ||
| 170 | void Cancel(Kernel::HLERequestContext& ctx) { | 174 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 171 | finished_event->Clear(); | 175 | LOG_DEBUG(Service_NIM, "called"); |
| 176 | finished_event.writable->Clear(); | ||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | 177 | IPC::ResponseBuilder rb{ctx, 2}; |
| 173 | rb.Push(RESULT_SUCCESS); | 178 | rb.Push(RESULT_SUCCESS); |
| 174 | LOG_DEBUG(Service_NIM, "called"); | ||
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | void IsProcessing(Kernel::HLERequestContext& ctx) { | 181 | void IsProcessing(Kernel::HLERequestContext& ctx) { |
| 182 | LOG_DEBUG(Service_NIM, "called"); | ||
| 183 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 3}; | 184 | IPC::ResponseBuilder rb{ctx, 3}; |
| 179 | rb.Push(RESULT_SUCCESS); | 185 | rb.Push(RESULT_SUCCESS); |
| 180 | rb.PushRaw<u32>(0); // We instantly process the request | 186 | rb.PushRaw<u32>(0); // We instantly process the request |
| 181 | LOG_DEBUG(Service_NIM, "called"); | ||
| 182 | } | 187 | } |
| 183 | 188 | ||
| 184 | void GetServerTime(Kernel::HLERequestContext& ctx) { | 189 | void GetServerTime(Kernel::HLERequestContext& ctx) { |
| 190 | LOG_DEBUG(Service_NIM, "called"); | ||
| 191 | |||
| 185 | const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( | 192 | const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( |
| 186 | std::chrono::system_clock::now().time_since_epoch()) | 193 | std::chrono::system_clock::now().time_since_epoch()) |
| 187 | .count()}; | 194 | .count()}; |
| 188 | IPC::ResponseBuilder rb{ctx, 4}; | 195 | IPC::ResponseBuilder rb{ctx, 4}; |
| 189 | rb.Push(RESULT_SUCCESS); | 196 | rb.Push(RESULT_SUCCESS); |
| 190 | rb.PushRaw<s64>(server_time); | 197 | rb.PushRaw<s64>(server_time); |
| 191 | LOG_DEBUG(Service_NIM, "called"); | ||
| 192 | } | 198 | } |
| 193 | }; | 199 | }; |
| 194 | 200 | ||
| @@ -208,23 +214,26 @@ public: | |||
| 208 | 214 | ||
| 209 | private: | 215 | private: |
| 210 | void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { | 216 | void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { |
| 217 | LOG_DEBUG(Service_NIM, "called"); | ||
| 218 | |||
| 211 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 212 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 213 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); | 221 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); |
| 214 | LOG_DEBUG(Service_NIM, "called"); | ||
| 215 | } | 222 | } |
| 216 | 223 | ||
| 217 | // TODO(ogniK): Do we need these? | 224 | // TODO(ogniK): Do we need these? |
| 218 | void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { | 225 | void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { |
| 226 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 227 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2}; | 228 | IPC::ResponseBuilder rb{ctx, 2}; |
| 220 | rb.Push(RESULT_SUCCESS); | 229 | rb.Push(RESULT_SUCCESS); |
| 221 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 222 | } | 230 | } |
| 223 | 231 | ||
| 224 | void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { | 232 | void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { |
| 233 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 234 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 2}; | 235 | IPC::ResponseBuilder rb{ctx, 2}; |
| 226 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| 227 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 228 | } | 237 | } |
| 229 | }; | 238 | }; |
| 230 | 239 | ||
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 07c1381fe..2663f56b1 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/file_sys/control_metadata.h" | ||
| 7 | #include "core/file_sys/patch_manager.h" | ||
| 5 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 6 | #include "core/hle/kernel/hle_ipc.h" | 9 | #include "core/hle/kernel/hle_ipc.h" |
| 7 | #include "core/hle/service/ns/ns.h" | 10 | #include "core/hle/service/ns/ns.h" |
| @@ -118,7 +121,7 @@ public: | |||
| 118 | {305, nullptr, "TerminateSystemApplet"}, | 121 | {305, nullptr, "TerminateSystemApplet"}, |
| 119 | {306, nullptr, "LaunchOverlayApplet"}, | 122 | {306, nullptr, "LaunchOverlayApplet"}, |
| 120 | {307, nullptr, "TerminateOverlayApplet"}, | 123 | {307, nullptr, "TerminateOverlayApplet"}, |
| 121 | {400, nullptr, "GetApplicationControlData"}, | 124 | {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, |
| 122 | {401, nullptr, "InvalidateAllApplicationControlCache"}, | 125 | {401, nullptr, "InvalidateAllApplicationControlCache"}, |
| 123 | {402, nullptr, "RequestDownloadApplicationControlData"}, | 126 | {402, nullptr, "RequestDownloadApplicationControlData"}, |
| 124 | {403, nullptr, "GetMaxApplicationControlCacheCount"}, | 127 | {403, nullptr, "GetMaxApplicationControlCacheCount"}, |
| @@ -243,6 +246,65 @@ public: | |||
| 243 | 246 | ||
| 244 | RegisterHandlers(functions); | 247 | RegisterHandlers(functions); |
| 245 | } | 248 | } |
| 249 | |||
| 250 | void GetApplicationControlData(Kernel::HLERequestContext& ctx) { | ||
| 251 | IPC::RequestParser rp{ctx}; | ||
| 252 | const auto flag = rp.PopRaw<u64>(); | ||
| 253 | LOG_DEBUG(Service_NS, "called with flag={:016X}", flag); | ||
| 254 | |||
| 255 | const auto title_id = rp.PopRaw<u64>(); | ||
| 256 | |||
| 257 | const auto size = ctx.GetWriteBufferSize(); | ||
| 258 | |||
| 259 | const FileSys::PatchManager pm{title_id}; | ||
| 260 | const auto control = pm.GetControlMetadata(); | ||
| 261 | |||
| 262 | std::vector<u8> out; | ||
| 263 | |||
| 264 | if (control.first != nullptr) { | ||
| 265 | if (size < 0x4000) { | ||
| 266 | LOG_ERROR(Service_NS, | ||
| 267 | "output buffer is too small! (actual={:016X}, expected_min=0x4000)", | ||
| 268 | size); | ||
| 269 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 270 | // TODO(DarkLordZach): Find a better error code for this. | ||
| 271 | rb.Push(ResultCode(-1)); | ||
| 272 | return; | ||
| 273 | } | ||
| 274 | |||
| 275 | out.resize(0x4000); | ||
| 276 | const auto bytes = control.first->GetRawBytes(); | ||
| 277 | std::memcpy(out.data(), bytes.data(), bytes.size()); | ||
| 278 | } else { | ||
| 279 | LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.", | ||
| 280 | title_id); | ||
| 281 | out.resize(std::min<u64>(0x4000, size)); | ||
| 282 | } | ||
| 283 | |||
| 284 | if (control.second != nullptr) { | ||
| 285 | if (size < 0x4000 + control.second->GetSize()) { | ||
| 286 | LOG_ERROR(Service_NS, | ||
| 287 | "output buffer is too small! (actual={:016X}, expected_min={:016X})", | ||
| 288 | size, 0x4000 + control.second->GetSize()); | ||
| 289 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 290 | // TODO(DarkLordZach): Find a better error code for this. | ||
| 291 | rb.Push(ResultCode(-1)); | ||
| 292 | return; | ||
| 293 | } | ||
| 294 | |||
| 295 | out.resize(0x4000 + control.second->GetSize()); | ||
| 296 | control.second->Read(out.data() + 0x4000, control.second->GetSize()); | ||
| 297 | } else { | ||
| 298 | LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.", | ||
| 299 | title_id); | ||
| 300 | } | ||
| 301 | |||
| 302 | ctx.WriteBuffer(out); | ||
| 303 | |||
| 304 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 305 | rb.Push(RESULT_SUCCESS); | ||
| 306 | rb.Push<u32>(static_cast<u32>(out.size())); | ||
| 307 | } | ||
| 246 | }; | 308 | }; |
| 247 | 309 | ||
| 248 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | 310 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { |
| @@ -371,11 +433,11 @@ public: | |||
| 371 | private: | 433 | private: |
| 372 | template <typename T> | 434 | template <typename T> |
| 373 | void PushInterface(Kernel::HLERequestContext& ctx) { | 435 | void PushInterface(Kernel::HLERequestContext& ctx) { |
| 436 | LOG_DEBUG(Service_NS, "called"); | ||
| 437 | |||
| 374 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 438 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 375 | rb.Push(RESULT_SUCCESS); | 439 | rb.Push(RESULT_SUCCESS); |
| 376 | rb.PushIpcInterface<T>(); | 440 | rb.PushIpcInterface<T>(); |
| 377 | |||
| 378 | LOG_DEBUG(Service_NS, "called"); | ||
| 379 | } | 441 | } |
| 380 | }; | 442 | }; |
| 381 | 443 | ||
| @@ -464,11 +526,11 @@ public: | |||
| 464 | 526 | ||
| 465 | private: | 527 | private: |
| 466 | void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { | 528 | void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { |
| 529 | LOG_DEBUG(Service_NS, "called"); | ||
| 530 | |||
| 467 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 531 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 468 | rb.Push(RESULT_SUCCESS); | 532 | rb.Push(RESULT_SUCCESS); |
| 469 | rb.PushIpcInterface<ISystemUpdateControl>(); | 533 | rb.PushIpcInterface<ISystemUpdateControl>(); |
| 470 | |||
| 471 | LOG_DEBUG(Service_NS, "called"); | ||
| 472 | } | 534 | } |
| 473 | }; | 535 | }; |
| 474 | 536 | ||
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 44accecb7..ad176f89d 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { | |||
| 281 | const u32 shared_font_type{rp.Pop<u32>()}; | 281 | const u32 shared_font_type{rp.Pop<u32>()}; |
| 282 | // Games don't call this so all fonts should be loaded | 282 | // Games don't call this so all fonts should be loaded |
| 283 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); | 283 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); |
| 284 | |||
| 284 | IPC::ResponseBuilder rb{ctx, 2}; | 285 | IPC::ResponseBuilder rb{ctx, 2}; |
| 285 | rb.Push(RESULT_SUCCESS); | 286 | rb.Push(RESULT_SUCCESS); |
| 286 | } | 287 | } |
| @@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { | |||
| 288 | void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | 289 | void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { |
| 289 | IPC::RequestParser rp{ctx}; | 290 | IPC::RequestParser rp{ctx}; |
| 290 | const u32 font_id{rp.Pop<u32>()}; | 291 | const u32 font_id{rp.Pop<u32>()}; |
| 291 | |||
| 292 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 292 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 293 | |||
| 293 | IPC::ResponseBuilder rb{ctx, 3}; | 294 | IPC::ResponseBuilder rb{ctx, 3}; |
| 294 | rb.Push(RESULT_SUCCESS); | 295 | rb.Push(RESULT_SUCCESS); |
| 295 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); | 296 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); |
| @@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | |||
| 298 | void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | 299 | void PL_U::GetSize(Kernel::HLERequestContext& ctx) { |
| 299 | IPC::RequestParser rp{ctx}; | 300 | IPC::RequestParser rp{ctx}; |
| 300 | const u32 font_id{rp.Pop<u32>()}; | 301 | const u32 font_id{rp.Pop<u32>()}; |
| 301 | |||
| 302 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 302 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 303 | |||
| 303 | IPC::ResponseBuilder rb{ctx, 3}; | 304 | IPC::ResponseBuilder rb{ctx, 3}; |
| 304 | rb.Push(RESULT_SUCCESS); | 305 | rb.Push(RESULT_SUCCESS); |
| 305 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); | 306 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); |
| @@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | |||
| 308 | void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | 309 | void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { |
| 309 | IPC::RequestParser rp{ctx}; | 310 | IPC::RequestParser rp{ctx}; |
| 310 | const u32 font_id{rp.Pop<u32>()}; | 311 | const u32 font_id{rp.Pop<u32>()}; |
| 311 | |||
| 312 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 312 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 313 | |||
| 313 | IPC::ResponseBuilder rb{ctx, 3}; | 314 | IPC::ResponseBuilder rb{ctx, 3}; |
| 314 | rb.Push(RESULT_SUCCESS); | 315 | rb.Push(RESULT_SUCCESS); |
| 315 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); | 316 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); |
| @@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 317 | 318 | ||
| 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 319 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 319 | // Map backing memory for the font data | 320 | // Map backing memory for the font data |
| 321 | LOG_DEBUG(Service_NS, "called"); | ||
| 320 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, | 322 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, |
| 321 | SHARED_FONT_MEM_SIZE, | 323 | SHARED_FONT_MEM_SIZE, |
| 322 | Kernel::MemoryState::Shared); | 324 | Kernel::MemoryState::Shared); |
| @@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | |||
| 328 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | 330 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, |
| 329 | "PL_U:shared_font_mem"); | 331 | "PL_U:shared_font_mem"); |
| 330 | 332 | ||
| 331 | LOG_DEBUG(Service_NS, "called"); | ||
| 332 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 333 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 333 | rb.Push(RESULT_SUCCESS); | 334 | rb.Push(RESULT_SUCCESS); |
| 334 | rb.PushCopyObjects(impl->shared_font_mem); | 335 | rb.PushCopyObjects(impl->shared_font_mem); |
| @@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { | |||
| 338 | IPC::RequestParser rp{ctx}; | 339 | IPC::RequestParser rp{ctx}; |
| 339 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for | 340 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for |
| 340 | LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); | 341 | LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); |
| 342 | |||
| 341 | IPC::ResponseBuilder rb{ctx, 4}; | 343 | IPC::ResponseBuilder rb{ctx, 4}; |
| 342 | std::vector<u32> font_codes; | 344 | std::vector<u32> font_codes; |
| 343 | std::vector<u32> font_offsets; | 345 | std::vector<u32> font_offsets; |
| @@ -351,6 +353,14 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { | |||
| 351 | font_sizes.push_back(region.size); | 353 | font_sizes.push_back(region.size); |
| 352 | } | 354 | } |
| 353 | 355 | ||
| 356 | // Resize buffers if game requests smaller size output. | ||
| 357 | font_codes.resize( | ||
| 358 | std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32))); | ||
| 359 | font_offsets.resize( | ||
| 360 | std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32))); | ||
| 361 | font_sizes.resize( | ||
| 362 | std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32))); | ||
| 363 | |||
| 354 | ctx.WriteBuffer(font_codes, 0); | 364 | ctx.WriteBuffer(font_codes, 0); |
| 355 | ctx.WriteBuffer(font_offsets, 1); | 365 | ctx.WriteBuffer(font_offsets, 1); |
| 356 | ctx.WriteBuffer(font_sizes, 2); | 366 | ctx.WriteBuffer(font_sizes, 2); |
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 c41ef7058..466db7ccd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 54 | IoctlInitalizeEx params{}; | 54 | IoctlInitalizeEx params{}; |
| 55 | std::memcpy(¶ms, input.data(), input.size()); | 55 | std::memcpy(¶ms, input.data(), input.size()); |
| 56 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 56 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 57 | |||
| 57 | return 0; | 58 | return 0; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| @@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 191 | IoctlBindChannel params{}; | 192 | IoctlBindChannel params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 193 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | 194 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); |
| 195 | |||
| 194 | channel = params.fd; | 196 | channel = params.fd; |
| 195 | return 0; | 197 | return 0; |
| 196 | } | 198 | } |
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 7a88ae029..d57a54ee8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/core_timing_util.h" | ||
| 8 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" | 10 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" |
| 9 | 11 | ||
| 10 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| @@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec | |||
| 33 | return ZBCQueryTable(input, output); | 35 | return ZBCQueryTable(input, output); |
| 34 | case IoctlCommand::IocFlushL2: | 36 | case IoctlCommand::IocFlushL2: |
| 35 | return FlushL2(input, output); | 37 | return FlushL2(input, output); |
| 38 | case IoctlCommand::IocGetGpuTime: | ||
| 39 | return GetGpuTime(input, output); | ||
| 36 | } | 40 | } |
| 37 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 41 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); |
| 38 | return 0; | 42 | return 0; |
| @@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& | |||
| 99 | 103 | ||
| 100 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 104 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 101 | LOG_DEBUG(Service_NVDRV, "called"); | 105 | LOG_DEBUG(Service_NVDRV, "called"); |
| 106 | |||
| 102 | IoctlActiveSlotMask params{}; | 107 | IoctlActiveSlotMask params{}; |
| 103 | if (input.size() > 0) { | 108 | if (input.size() > 0) { |
| 104 | std::memcpy(¶ms, input.data(), input.size()); | 109 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 111 | 116 | ||
| 112 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 117 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 113 | LOG_DEBUG(Service_NVDRV, "called"); | 118 | LOG_DEBUG(Service_NVDRV, "called"); |
| 119 | |||
| 114 | IoctlZcullGetCtxSize params{}; | 120 | IoctlZcullGetCtxSize params{}; |
| 115 | if (input.size() > 0) { | 121 | if (input.size() > 0) { |
| 116 | std::memcpy(¶ms, input.data(), input.size()); | 122 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 122 | 128 | ||
| 123 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 129 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 124 | LOG_DEBUG(Service_NVDRV, "called"); | 130 | LOG_DEBUG(Service_NVDRV, "called"); |
| 131 | |||
| 125 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 132 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| 126 | 133 | ||
| 127 | if (input.size() > 0) { | 134 | if (input.size() > 0) { |
| @@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 144 | 151 | ||
| 145 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 152 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 153 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 154 | |||
| 147 | IoctlZbcSetTable params{}; | 155 | IoctlZbcSetTable params{}; |
| 148 | std::memcpy(¶ms, input.data(), input.size()); | 156 | std::memcpy(¶ms, input.data(), input.size()); |
| 149 | // TODO(ogniK): What does this even actually do? | 157 | // TODO(ogniK): What does this even actually do? |
| @@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& | |||
| 153 | 161 | ||
| 154 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 162 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 155 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 164 | |||
| 156 | IoctlZbcQueryTable params{}; | 165 | IoctlZbcQueryTable params{}; |
| 157 | std::memcpy(¶ms, input.data(), input.size()); | 166 | std::memcpy(¶ms, input.data(), input.size()); |
| 158 | // TODO : To implement properly | 167 | // TODO : To implement properly |
| @@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8> | |||
| 162 | 171 | ||
| 163 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 172 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 173 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 174 | |||
| 165 | IoctlFlushL2 params{}; | 175 | IoctlFlushL2 params{}; |
| 166 | std::memcpy(¶ms, input.data(), input.size()); | 176 | std::memcpy(¶ms, input.data(), input.size()); |
| 167 | // TODO : To implement properly | 177 | // TODO : To implement properly |
| @@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 169 | return 0; | 179 | return 0; |
| 170 | } | 180 | } |
| 171 | 181 | ||
| 182 | u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 183 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 184 | |||
| 185 | IoctlGetGpuTime params{}; | ||
| 186 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 187 | params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks()); | ||
| 188 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 172 | } // namespace Service::Nvidia::Devices | 192 | } // namespace Service::Nvidia::Devices |
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 3bbf028ad..240435eea 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -156,6 +156,11 @@ private: | |||
| 156 | }; | 156 | }; |
| 157 | static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); | 157 | static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); |
| 158 | 158 | ||
| 159 | struct IoctlGetGpuTime { | ||
| 160 | u64_le gpu_time; | ||
| 161 | }; | ||
| 162 | static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); | ||
| 163 | |||
| 159 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); | 164 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); |
| 160 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); | 165 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 161 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 166 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| @@ -164,6 +169,7 @@ private: | |||
| 164 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | 169 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); |
| 165 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | 170 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); |
| 166 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | 171 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); |
| 172 | u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 167 | }; | 173 | }; |
| 168 | 174 | ||
| 169 | } // namespace Service::Nvidia::Devices | 175 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 874d5e1c3..3bfce0110 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 11 | #include "video_core/command_processor.h" | ||
| 12 | #include "video_core/gpu.h" | 11 | #include "video_core/gpu.h" |
| 13 | #include "video_core/memory_manager.h" | 12 | #include "video_core/memory_manager.h" |
| 14 | 13 | ||
| @@ -61,12 +60,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output | |||
| 61 | IoctlSetNvmapFD params{}; | 60 | IoctlSetNvmapFD params{}; |
| 62 | std::memcpy(¶ms, input.data(), input.size()); | 61 | std::memcpy(¶ms, input.data(), input.size()); |
| 63 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 62 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 63 | |||
| 64 | nvmap_fd = params.nvmap_fd; | 64 | nvmap_fd = params.nvmap_fd; |
| 65 | return 0; | 65 | return 0; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 68 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 69 | LOG_DEBUG(Service_NVDRV, "called"); | 69 | LOG_DEBUG(Service_NVDRV, "called"); |
| 70 | |||
| 70 | IoctlClientData params{}; | 71 | IoctlClientData params{}; |
| 71 | std::memcpy(¶ms, input.data(), input.size()); | 72 | std::memcpy(¶ms, input.data(), input.size()); |
| 72 | user_data = params.data; | 73 | user_data = params.data; |
| @@ -75,6 +76,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out | |||
| 75 | 76 | ||
| 76 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 77 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 77 | LOG_DEBUG(Service_NVDRV, "called"); | 78 | LOG_DEBUG(Service_NVDRV, "called"); |
| 79 | |||
| 78 | IoctlClientData params{}; | 80 | IoctlClientData params{}; |
| 79 | std::memcpy(¶ms, input.data(), input.size()); | 81 | std::memcpy(¶ms, input.data(), input.size()); |
| 80 | params.data = user_data; | 82 | params.data = user_data; |
| @@ -86,6 +88,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 86 | std::memcpy(&zcull_params, input.data(), input.size()); | 88 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 87 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 89 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 88 | zcull_params.mode); | 90 | zcull_params.mode); |
| 91 | |||
| 89 | std::memcpy(output.data(), &zcull_params, output.size()); | 92 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 90 | return 0; | 93 | return 0; |
| 91 | } | 94 | } |
| @@ -95,6 +98,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& | |||
| 95 | std::memcpy(¶ms, input.data(), input.size()); | 98 | std::memcpy(¶ms, input.data(), input.size()); |
| 96 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 99 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 97 | params.size, params.mem); | 100 | params.size, params.mem); |
| 101 | |||
| 98 | std::memcpy(output.data(), ¶ms, output.size()); | 102 | std::memcpy(output.data(), ¶ms, output.size()); |
| 99 | return 0; | 103 | return 0; |
| 100 | } | 104 | } |
| @@ -102,6 +106,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& | |||
| 102 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 106 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 103 | std::memcpy(&channel_priority, input.data(), input.size()); | 107 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 104 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 108 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 109 | |||
| 105 | return 0; | 110 | return 0; |
| 106 | } | 111 | } |
| 107 | 112 | ||
| @@ -113,6 +118,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 113 | "unk1={:X}, unk2={:X}, unk3={:X}", | 118 | "unk1={:X}, unk2={:X}, unk3={:X}", |
| 114 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 119 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 115 | params.unk3); | 120 | params.unk3); |
| 121 | |||
| 116 | params.fence_out.id = 0; | 122 | params.fence_out.id = 0; |
| 117 | params.fence_out.value = 0; | 123 | params.fence_out.value = 0; |
| 118 | std::memcpy(output.data(), ¶ms, output.size()); | 124 | std::memcpy(output.data(), ¶ms, output.size()); |
| @@ -124,11 +130,18 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 124 | std::memcpy(¶ms, input.data(), input.size()); | 130 | std::memcpy(¶ms, input.data(), input.size()); |
| 125 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 131 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| 126 | params.flags); | 132 | params.flags); |
| 133 | |||
| 127 | params.obj_id = 0x0; | 134 | params.obj_id = 0x0; |
| 128 | std::memcpy(output.data(), ¶ms, output.size()); | 135 | std::memcpy(output.data(), ¶ms, output.size()); |
| 129 | return 0; | 136 | return 0; |
| 130 | } | 137 | } |
| 131 | 138 | ||
| 139 | static void PushGPUEntries(Tegra::CommandList&& entries) { | ||
| 140 | auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()}; | ||
| 141 | dma_pusher.Push(std::move(entries)); | ||
| 142 | dma_pusher.DispatchCalls(); | ||
| 143 | } | ||
| 144 | |||
| 132 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 145 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { |
| 133 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 146 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 134 | UNIMPLEMENTED(); | 147 | UNIMPLEMENTED(); |
| @@ -142,11 +155,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 142 | params.num_entries * sizeof(Tegra::CommandListHeader), | 155 | params.num_entries * sizeof(Tegra::CommandListHeader), |
| 143 | "Incorrect input size"); | 156 | "Incorrect input size"); |
| 144 | 157 | ||
| 145 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 158 | Tegra::CommandList entries(params.num_entries); |
| 146 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | 159 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], |
| 147 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 160 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 148 | 161 | ||
| 149 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 162 | PushGPUEntries(std::move(entries)); |
| 150 | 163 | ||
| 151 | params.fence_out.id = 0; | 164 | params.fence_out.id = 0; |
| 152 | params.fence_out.value = 0; | 165 | params.fence_out.value = 0; |
| @@ -163,11 +176,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 176 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 164 | params.address, params.num_entries, params.flags); | 177 | params.address, params.num_entries, params.flags); |
| 165 | 178 | ||
| 166 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 179 | Tegra::CommandList entries(params.num_entries); |
| 167 | Memory::ReadBlock(params.address, entries.data(), | 180 | Memory::ReadBlock(params.address, entries.data(), |
| 168 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 181 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 169 | 182 | ||
| 170 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 183 | PushGPUEntries(std::move(entries)); |
| 171 | 184 | ||
| 172 | params.fence_out.id = 0; | 185 | params.fence_out.id = 0; |
| 173 | params.fence_out.value = 0; | 186 | params.fence_out.value = 0; |
| @@ -179,6 +192,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu | |||
| 179 | IoctlGetWaitbase params{}; | 192 | IoctlGetWaitbase params{}; |
| 180 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 193 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 181 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 194 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 195 | |||
| 182 | params.value = 0; // Seems to be hard coded at 0 | 196 | params.value = 0; // Seems to be hard coded at 0 |
| 183 | std::memcpy(output.data(), ¶ms, output.size()); | 197 | std::memcpy(output.data(), ¶ms, output.size()); |
| 184 | return 0; | 198 | return 0; |
| @@ -188,6 +202,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& | |||
| 188 | IoctlChannelSetTimeout params{}; | 202 | IoctlChannelSetTimeout params{}; |
| 189 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 203 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 190 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 204 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 205 | |||
| 191 | return 0; | 206 | return 0; |
| 192 | } | 207 | } |
| 193 | 208 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 46dbbc37c..f5e8ea7c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index c67f934f6..3e0951ab0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 727b9fee4..d544f0f31 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 43651d8a6..1ec796fc6 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 54 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 54 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 55 | 55 | ||
| 56 | if (!params.size) { | 56 | if (!params.size) { |
| 57 | LOG_ERROR(Service_NVDRV, "Size is 0"); | ||
| 57 | return static_cast<u32>(NvErrCodes::InvalidValue); | 58 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 58 | } | 59 | } |
| 59 | // Create a new nvmap object and obtain a handle to it. | 60 | // Create a new nvmap object and obtain a handle to it. |
| @@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 78 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 79 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 79 | 80 | ||
| 80 | if (!params.handle) { | 81 | if (!params.handle) { |
| 82 | LOG_ERROR(Service_NVDRV, "Handle is 0"); | ||
| 81 | return static_cast<u32>(NvErrCodes::InvalidValue); | 83 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | if ((params.align - 1) & params.align) { | 86 | if ((params.align - 1) & params.align) { |
| 87 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); | ||
| 85 | return static_cast<u32>(NvErrCodes::InvalidValue); | 88 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 86 | } | 89 | } |
| 87 | 90 | ||
| @@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 92 | 95 | ||
| 93 | auto object = GetObject(params.handle); | 96 | auto object = GetObject(params.handle); |
| 94 | if (!object) { | 97 | if (!object) { |
| 98 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 95 | return static_cast<u32>(NvErrCodes::InvalidValue); | 99 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 96 | } | 100 | } |
| 97 | 101 | ||
| 98 | if (object->status == Object::Status::Allocated) { | 102 | if (object->status == Object::Status::Allocated) { |
| 103 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); | ||
| 99 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 104 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 100 | } | 105 | } |
| 101 | 106 | ||
| @@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 116 | LOG_WARNING(Service_NVDRV, "called"); | 121 | LOG_WARNING(Service_NVDRV, "called"); |
| 117 | 122 | ||
| 118 | if (!params.handle) { | 123 | if (!params.handle) { |
| 124 | LOG_ERROR(Service_NVDRV, "Handle is zero"); | ||
| 119 | return static_cast<u32>(NvErrCodes::InvalidValue); | 125 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 120 | } | 126 | } |
| 121 | 127 | ||
| 122 | auto object = GetObject(params.handle); | 128 | auto object = GetObject(params.handle); |
| 123 | if (!object) { | 129 | if (!object) { |
| 130 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 124 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 131 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 125 | } | 132 | } |
| 126 | 133 | ||
| @@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 139 | auto itr = std::find_if(handles.begin(), handles.end(), | 146 | auto itr = std::find_if(handles.begin(), handles.end(), |
| 140 | [&](const auto& entry) { return entry.second->id == params.id; }); | 147 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 141 | if (itr == handles.end()) { | 148 | if (itr == handles.end()) { |
| 149 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 142 | return static_cast<u32>(NvErrCodes::InvalidValue); | 150 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 143 | } | 151 | } |
| 144 | 152 | ||
| 145 | auto& object = itr->second; | 153 | auto& object = itr->second; |
| 146 | if (object->status != Object::Status::Allocated) { | 154 | if (object->status != Object::Status::Allocated) { |
| 155 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | ||
| 147 | return static_cast<u32>(NvErrCodes::InvalidValue); | 156 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 148 | } | 157 | } |
| 149 | 158 | ||
| @@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 166 | 175 | ||
| 167 | auto object = GetObject(params.handle); | 176 | auto object = GetObject(params.handle); |
| 168 | if (!object) { | 177 | if (!object) { |
| 178 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 169 | return static_cast<u32>(NvErrCodes::InvalidValue); | 179 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 170 | } | 180 | } |
| 171 | 181 | ||
| 172 | if (object->status != Object::Status::Allocated) { | 182 | if (object->status != Object::Status::Allocated) { |
| 183 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | ||
| 173 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 184 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 174 | } | 185 | } |
| 175 | 186 | ||
| @@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 209 | 220 | ||
| 210 | auto itr = handles.find(params.handle); | 221 | auto itr = handles.find(params.handle); |
| 211 | if (itr == handles.end()) { | 222 | if (itr == handles.end()) { |
| 223 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 212 | return static_cast<u32>(NvErrCodes::InvalidValue); | 224 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 213 | } | 225 | } |
| 214 | if (!itr->second->refcount) { | 226 | if (!itr->second->refcount) { |
| 227 | LOG_ERROR( | ||
| 228 | Service_NVDRV, | ||
| 229 | "There is no references to this object. The object is already freed. handle={:08X}", | ||
| 230 | params.handle); | ||
| 215 | return static_cast<u32>(NvErrCodes::InvalidValue); | 231 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 216 | } | 232 | } |
| 217 | 233 | ||
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index ac3859353..3b9ab4b14 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -6,7 +6,9 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/readable_event.h" | ||
| 11 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/nvdrv/interface.h" | 12 | #include "core/hle/service/nvdrv/interface.h" |
| 11 | #include "core/hle/service/nvdrv/nvdrv.h" | 13 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 12 | 14 | ||
| @@ -55,6 +57,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) { | |||
| 55 | 57 | ||
| 56 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 58 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 57 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 59 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 60 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 3}; | 61 | IPC::ResponseBuilder rb{ctx, 3}; |
| 59 | rb.Push(RESULT_SUCCESS); | 62 | rb.Push(RESULT_SUCCESS); |
| 60 | rb.Push<u32>(0); | 63 | rb.Push<u32>(0); |
| @@ -68,15 +71,15 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | |||
| 68 | 71 | ||
| 69 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 72 | IPC::ResponseBuilder rb{ctx, 3, 1}; |
| 70 | rb.Push(RESULT_SUCCESS); | 73 | rb.Push(RESULT_SUCCESS); |
| 71 | rb.PushCopyObjects(query_event); | 74 | rb.PushCopyObjects(query_event.readable); |
| 72 | rb.Push<u32>(0); | 75 | rb.Push<u32>(0); |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | 78 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { |
| 76 | IPC::RequestParser rp{ctx}; | 79 | IPC::RequestParser rp{ctx}; |
| 77 | pid = rp.Pop<u64>(); | 80 | pid = rp.Pop<u64>(); |
| 78 | |||
| 79 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); | 81 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); |
| 82 | |||
| 80 | IPC::ResponseBuilder rb{ctx, 3}; | 83 | IPC::ResponseBuilder rb{ctx, 3}; |
| 81 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 82 | rb.Push<u32>(0); | 85 | rb.Push<u32>(0); |
| @@ -84,6 +87,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | |||
| 84 | 87 | ||
| 85 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { | 88 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 89 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 90 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 92 | rb.Push(RESULT_SUCCESS); | ||
| 93 | } | ||
| 94 | |||
| 95 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { | ||
| 96 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | } | ||
| 101 | |||
| 102 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | ||
| 103 | // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on | ||
| 104 | // retail hardware. | ||
| 105 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 106 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 2}; | 107 | IPC::ResponseBuilder rb{ctx, 2}; |
| 88 | rb.Push(RESULT_SUCCESS); | 108 | rb.Push(RESULT_SUCCESS); |
| 89 | } | 109 | } |
| @@ -97,10 +117,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 97 | {3, &NVDRV::Initialize, "Initialize"}, | 117 | {3, &NVDRV::Initialize, "Initialize"}, |
| 98 | {4, &NVDRV::QueryEvent, "QueryEvent"}, | 118 | {4, &NVDRV::QueryEvent, "QueryEvent"}, |
| 99 | {5, nullptr, "MapSharedMem"}, | 119 | {5, nullptr, "MapSharedMem"}, |
| 100 | {6, nullptr, "GetStatus"}, | 120 | {6, &NVDRV::GetStatus, "GetStatus"}, |
| 101 | {7, nullptr, "ForceSetClientPID"}, | 121 | {7, nullptr, "ForceSetClientPID"}, |
| 102 | {8, &NVDRV::SetClientPID, "SetClientPID"}, | 122 | {8, &NVDRV::SetClientPID, "SetClientPID"}, |
| 103 | {9, nullptr, "DumpGraphicsMemoryInfo"}, | 123 | {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, |
| 104 | {10, nullptr, "InitializeDevtools"}, | 124 | {10, nullptr, "InitializeDevtools"}, |
| 105 | {11, &NVDRV::Ioctl, "Ioctl2"}, | 125 | {11, &NVDRV::Ioctl, "Ioctl2"}, |
| 106 | {12, nullptr, "Ioctl3"}, | 126 | {12, nullptr, "Ioctl3"}, |
| @@ -109,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 109 | RegisterHandlers(functions); | 129 | RegisterHandlers(functions); |
| 110 | 130 | ||
| 111 | auto& kernel = Core::System::GetInstance().Kernel(); | 131 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 112 | query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); | 132 | query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot, |
| 133 | "NVDRV::query_event"); | ||
| 113 | } | 134 | } |
| 114 | 135 | ||
| 115 | NVDRV::~NVDRV() = default; | 136 | NVDRV::~NVDRV() = default; |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index d340893c2..fe311b069 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -5,10 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include "core/hle/kernel/event.h" | ||
| 9 | #include "core/hle/service/nvdrv/nvdrv.h" | 8 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 10 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 11 | 10 | ||
| 11 | namespace Kernel { | ||
| 12 | class WritableEvent; | ||
| 13 | } | ||
| 14 | |||
| 12 | namespace Service::Nvidia { | 15 | namespace Service::Nvidia { |
| 13 | 16 | ||
| 14 | class NVDRV final : public ServiceFramework<NVDRV> { | 17 | class NVDRV final : public ServiceFramework<NVDRV> { |
| @@ -24,12 +27,14 @@ private: | |||
| 24 | void QueryEvent(Kernel::HLERequestContext& ctx); | 27 | void QueryEvent(Kernel::HLERequestContext& ctx); |
| 25 | void SetClientPID(Kernel::HLERequestContext& ctx); | 28 | void SetClientPID(Kernel::HLERequestContext& ctx); |
| 26 | void FinishInitialize(Kernel::HLERequestContext& ctx); | 29 | void FinishInitialize(Kernel::HLERequestContext& ctx); |
| 30 | void GetStatus(Kernel::HLERequestContext& ctx); | ||
| 31 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | ||
| 27 | 32 | ||
| 28 | std::shared_ptr<Module> nvdrv; | 33 | std::shared_ptr<Module> nvdrv; |
| 29 | 34 | ||
| 30 | u64 pid{}; | 35 | u64 pid{}; |
| 31 | 36 | ||
| 32 | Kernel::SharedPtr<Kernel::Event> query_event; | 37 | Kernel::EventPair query_event; |
| 33 | }; | 38 | }; |
| 34 | 39 | ||
| 35 | } // namespace Service::Nvidia | 40 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 630ebbfc7..fc07d9bb8 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -7,28 +7,31 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/readable_event.h" | ||
| 12 | #include "core/hle/kernel/writable_event.h" | ||
| 10 | #include "core/hle/service/nvflinger/buffer_queue.h" | 13 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 11 | 14 | ||
| 12 | namespace Service::NVFlinger { | 15 | namespace Service::NVFlinger { |
| 13 | 16 | ||
| 14 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | 17 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { |
| 15 | auto& kernel = Core::System::GetInstance().Kernel(); | 18 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 16 | buffer_wait_event = | 19 | buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, |
| 17 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); | 20 | "BufferQueue NativeHandle"); |
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | BufferQueue::~BufferQueue() = default; | 23 | BufferQueue::~BufferQueue() = default; |
| 21 | 24 | ||
| 22 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { | 25 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { |
| 26 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | ||
| 27 | |||
| 23 | Buffer buffer{}; | 28 | Buffer buffer{}; |
| 24 | buffer.slot = slot; | 29 | buffer.slot = slot; |
| 25 | buffer.igbp_buffer = igbp_buffer; | 30 | buffer.igbp_buffer = igbp_buffer; |
| 26 | buffer.status = Buffer::Status::Free; | 31 | buffer.status = Buffer::Status::Free; |
| 27 | 32 | ||
| 28 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | ||
| 29 | |||
| 30 | queue.emplace_back(buffer); | 33 | queue.emplace_back(buffer); |
| 31 | buffer_wait_event->Signal(); | 34 | buffer_wait_event.writable->Signal(); |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { | 37 | std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { |
| @@ -87,11 +90,12 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 87 | ASSERT(itr->status == Buffer::Status::Acquired); | 90 | ASSERT(itr->status == Buffer::Status::Acquired); |
| 88 | itr->status = Buffer::Status::Free; | 91 | itr->status = Buffer::Status::Free; |
| 89 | 92 | ||
| 90 | buffer_wait_event->Signal(); | 93 | buffer_wait_event.writable->Signal(); |
| 91 | } | 94 | } |
| 92 | 95 | ||
| 93 | u32 BufferQueue::Query(QueryType type) { | 96 | u32 BufferQueue::Query(QueryType type) { |
| 94 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); | 97 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); |
| 98 | |||
| 95 | switch (type) { | 99 | switch (type) { |
| 96 | case QueryType::NativeWindowFormat: | 100 | case QueryType::NativeWindowFormat: |
| 97 | // TODO(Subv): Use an enum for this | 101 | // TODO(Subv): Use an enum for this |
| @@ -103,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) { | |||
| 103 | return 0; | 107 | return 0; |
| 104 | } | 108 | } |
| 105 | 109 | ||
| 110 | Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { | ||
| 111 | return buffer_wait_event.writable; | ||
| 112 | } | ||
| 113 | |||
| 114 | Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { | ||
| 115 | return buffer_wait_event.readable; | ||
| 116 | } | ||
| 117 | |||
| 106 | } // namespace Service::NVFlinger | 118 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 8cff5eb71..b171f256c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 12 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 13 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/object.h" |
| 14 | #include "core/hle/kernel/writable_event.h" | ||
| 14 | 15 | ||
| 15 | namespace CoreTiming { | 16 | namespace CoreTiming { |
| 16 | struct EventType; | 17 | struct EventType; |
| @@ -86,16 +87,16 @@ public: | |||
| 86 | return id; | 87 | return id; |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const { | 90 | Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; |
| 90 | return buffer_wait_event; | 91 | |
| 91 | } | 92 | Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const; |
| 92 | 93 | ||
| 93 | private: | 94 | private: |
| 94 | u32 id; | 95 | u32 id; |
| 95 | u64 layer_id; | 96 | u64 layer_id; |
| 96 | 97 | ||
| 97 | std::vector<Buffer> queue; | 98 | std::vector<Buffer> queue; |
| 98 | Kernel::SharedPtr<Kernel::Event> buffer_wait_event; | 99 | Kernel::EventPair buffer_wait_event; |
| 99 | }; | 100 | }; |
| 100 | 101 | ||
| 101 | } // namespace Service::NVFlinger | 102 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 214e6d1b3..05af2d593 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -13,6 +13,9 @@ | |||
| 13 | #include "core/core.h" | 13 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 15 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| 16 | #include "core/hle/kernel/kernel.h" | ||
| 17 | #include "core/hle/kernel/readable_event.h" | ||
| 18 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 19 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" |
| 17 | #include "core/hle/service/nvdrv/nvdrv.h" | 20 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 18 | #include "core/hle/service/nvflinger/buffer_queue.h" | 21 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| @@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { | |||
| 83 | return layer.buffer_queue->GetId(); | 86 | return layer.buffer_queue->GetId(); |
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { | 89 | Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) { |
| 87 | const auto& display = GetDisplay(display_id); | 90 | return GetDisplay(display_id).vsync_event.readable; |
| 88 | return display.vsync_event; | ||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { | 93 | std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { |
| @@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { | |||
| 117 | void NVFlinger::Compose() { | 119 | void NVFlinger::Compose() { |
| 118 | for (auto& display : displays) { | 120 | for (auto& display : displays) { |
| 119 | // Trigger vsync for this display at the end of drawing | 121 | // Trigger vsync for this display at the end of drawing |
| 120 | SCOPE_EXIT({ display.vsync_event->Signal(); }); | 122 | SCOPE_EXIT({ display.vsync_event.writable->Signal(); }); |
| 121 | 123 | ||
| 122 | // Don't do anything for displays without layers. | 124 | // Don't do anything for displays without layers. |
| 123 | if (display.layers.empty()) | 125 | if (display.layers.empty()) |
| @@ -164,7 +166,8 @@ Layer::~Layer() = default; | |||
| 164 | 166 | ||
| 165 | Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { | 167 | Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { |
| 166 | auto& kernel = Core::System::GetInstance().Kernel(); | 168 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 167 | vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); | 169 | vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse, |
| 170 | fmt::format("Display VSync Event {}", id)); | ||
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | Display::~Display() = default; | 173 | Display::~Display() = default; |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 3dc69e69b..9abba555b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -10,12 +10,17 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "core/hle/kernel/event.h" | 13 | #include "core/hle/kernel/object.h" |
| 14 | 14 | ||
| 15 | namespace CoreTiming { | 15 | namespace CoreTiming { |
| 16 | struct EventType; | 16 | struct EventType; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | namespace Kernel { | ||
| 20 | class ReadableEvent; | ||
| 21 | class WritableEvent; | ||
| 22 | } // namespace Kernel | ||
| 23 | |||
| 19 | namespace Service::Nvidia { | 24 | namespace Service::Nvidia { |
| 20 | class Module; | 25 | class Module; |
| 21 | } | 26 | } |
| @@ -40,7 +45,7 @@ struct Display { | |||
| 40 | std::string name; | 45 | std::string name; |
| 41 | 46 | ||
| 42 | std::vector<Layer> layers; | 47 | std::vector<Layer> layers; |
| 43 | Kernel::SharedPtr<Kernel::Event> vsync_event; | 48 | Kernel::EventPair vsync_event; |
| 44 | }; | 49 | }; |
| 45 | 50 | ||
| 46 | class NVFlinger final { | 51 | class NVFlinger final { |
| @@ -61,7 +66,7 @@ public: | |||
| 61 | u32 GetBufferQueueId(u64 display_id, u64 layer_id); | 66 | u32 GetBufferQueueId(u64 display_id, u64 layer_id); |
| 62 | 67 | ||
| 63 | /// Gets the vsync event for the specified display. | 68 | /// Gets the vsync event for the specified display. |
| 64 | Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); | 69 | Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id); |
| 65 | 70 | ||
| 66 | /// Obtains a buffer queue identified by the id. | 71 | /// Obtains a buffer queue identified by the id. |
| 67 | std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; | 72 | std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; |
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 4fd185f69..6081f41e1 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -114,29 +114,33 @@ public: | |||
| 114 | private: | 114 | private: |
| 115 | void Initialize(Kernel::HLERequestContext& ctx) { | 115 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 116 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | 116 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); |
| 117 | |||
| 117 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 118 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 118 | rb.Push(RESULT_SUCCESS); | 119 | rb.Push(RESULT_SUCCESS); |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { | 122 | void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { |
| 122 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | 123 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); |
| 124 | |||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | 125 | IPC::ResponseBuilder rb{ctx, 2}; |
| 124 | rb.Push(RESULT_SUCCESS); | 126 | rb.Push(RESULT_SUCCESS); |
| 125 | } | 127 | } |
| 126 | }; | 128 | }; |
| 127 | 129 | ||
| 128 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | 130 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { |
| 131 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 132 | |||
| 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 133 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 130 | rb.Push(RESULT_SUCCESS); | 134 | rb.Push(RESULT_SUCCESS); |
| 131 | rb.PushIpcInterface<IParentalControlService>(); | 135 | rb.PushIpcInterface<IParentalControlService>(); |
| 132 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { | 138 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { |
| 139 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 140 | |||
| 136 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 141 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 137 | rb.Push(RESULT_SUCCESS); | 142 | rb.Push(RESULT_SUCCESS); |
| 138 | rb.PushIpcInterface<IParentalControlService>(); | 143 | rb.PushIpcInterface<IParentalControlService>(); |
| 139 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 146 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 6ec35ca60..53e7da9c3 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -20,11 +20,11 @@ public: | |||
| 20 | 20 | ||
| 21 | private: | 21 | private: |
| 22 | void GetBootMode(Kernel::HLERequestContext& ctx) { | 22 | void GetBootMode(Kernel::HLERequestContext& ctx) { |
| 23 | LOG_DEBUG(Service_PM, "called"); | ||
| 24 | |||
| 23 | IPC::ResponseBuilder rb{ctx, 3}; | 25 | IPC::ResponseBuilder rb{ctx, 3}; |
| 24 | rb.Push(RESULT_SUCCESS); | 26 | rb.Push(RESULT_SUCCESS); |
| 25 | rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode | 27 | rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode |
| 26 | |||
| 27 | LOG_DEBUG(Service_PM, "called"); | ||
| 28 | } | 28 | } |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index bbad870a2..0ba0a4076 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp | |||
| @@ -61,11 +61,11 @@ public: | |||
| 61 | 61 | ||
| 62 | private: | 62 | private: |
| 63 | void GetPmModule(Kernel::HLERequestContext& ctx) { | 63 | void GetPmModule(Kernel::HLERequestContext& ctx) { |
| 64 | LOG_DEBUG(Service_PSC, "called"); | ||
| 65 | |||
| 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 66 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 65 | rb.Push(RESULT_SUCCESS); | 67 | rb.Push(RESULT_SUCCESS); |
| 66 | rb.PushIpcInterface<IPmModule>(); | 68 | rb.PushIpcInterface<IPmModule>(); |
| 67 | |||
| 68 | LOG_DEBUG(Service_PSC, "called"); | ||
| 69 | } | 69 | } |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index a4cf45267..1ec340466 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -80,8 +80,8 @@ namespace Service { | |||
| 80 | * Creates a function string for logging, complete with the name (or header code, depending | 80 | * Creates a function string for logging, complete with the name (or header code, depending |
| 81 | * on what's passed in) the port name, and all the cmd_buff arguments. | 81 | * on what's passed in) the port name, and all the cmd_buff arguments. |
| 82 | */ | 82 | */ |
| 83 | static std::string MakeFunctionString(const char* name, const char* port_name, | 83 | [[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name, |
| 84 | const u32* cmd_buff) { | 84 | const u32* cmd_buff) { |
| 85 | // Number of params == bits 0-5 + bits 6-11 | 85 | // Number of params == bits 0-5 + bits 6-11 |
| 86 | int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); | 86 | int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); |
| 87 | 87 | ||
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 9e5af7839..1afc43f75 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{ | |||
| 35 | constexpr std::size_t pre4_0_0_max_entries = 0xF; | 35 | constexpr std::size_t pre4_0_0_max_entries = 0xF; |
| 36 | constexpr std::size_t post4_0_0_max_entries = 0x40; | 36 | constexpr std::size_t post4_0_0_max_entries = 0x40; |
| 37 | 37 | ||
| 38 | constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625}; | ||
| 39 | |||
| 38 | LanguageCode GetLanguageCodeFromIndex(std::size_t index) { | 40 | LanguageCode GetLanguageCodeFromIndex(std::size_t index) { |
| 39 | return available_language_codes.at(index); | 41 | return available_language_codes.at(index); |
| 40 | } | 42 | } |
| @@ -49,38 +51,54 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() { | |||
| 49 | static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { | 51 | static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { |
| 50 | IPC::ResponseBuilder rb{ctx, 3}; | 52 | IPC::ResponseBuilder rb{ctx, 3}; |
| 51 | rb.Push(RESULT_SUCCESS); | 53 | rb.Push(RESULT_SUCCESS); |
| 52 | if (available_language_codes.size() > max_size) | 54 | if (available_language_codes.size() > max_size) { |
| 53 | rb.Push(static_cast<u32>(max_size)); | 55 | rb.Push(static_cast<u32>(max_size)); |
| 54 | else | 56 | } else { |
| 55 | rb.Push(static_cast<u32>(available_language_codes.size())); | 57 | rb.Push(static_cast<u32>(available_language_codes.size())); |
| 58 | } | ||
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | 61 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { |
| 59 | if (available_language_codes.size() > pre4_0_0_max_entries) | 62 | LOG_DEBUG(Service_SET, "called"); |
| 63 | |||
| 64 | if (available_language_codes.size() > pre4_0_0_max_entries) { | ||
| 60 | ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); | 65 | ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); |
| 61 | else | 66 | } else { |
| 62 | ctx.WriteBuffer(available_language_codes); | 67 | ctx.WriteBuffer(available_language_codes); |
| 63 | 68 | } | |
| 64 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | 69 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); |
| 70 | } | ||
| 65 | 71 | ||
| 66 | LOG_DEBUG(Service_SET, "called"); | 72 | void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) { |
| 73 | IPC::RequestParser rp{ctx}; | ||
| 74 | const auto index = rp.Pop<u32>(); | ||
| 75 | |||
| 76 | if (index >= available_language_codes.size()) { | ||
| 77 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 78 | rb.Push(ERR_INVALID_LANGUAGE); | ||
| 79 | return; | ||
| 80 | } | ||
| 81 | |||
| 82 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 83 | rb.Push(RESULT_SUCCESS); | ||
| 84 | rb.PushEnum(available_language_codes[index]); | ||
| 67 | } | 85 | } |
| 68 | 86 | ||
| 69 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { | 87 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { |
| 70 | if (available_language_codes.size() > post4_0_0_max_entries) | 88 | LOG_DEBUG(Service_SET, "called"); |
| 89 | |||
| 90 | if (available_language_codes.size() > post4_0_0_max_entries) { | ||
| 71 | ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); | 91 | ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); |
| 72 | else | 92 | } else { |
| 73 | ctx.WriteBuffer(available_language_codes); | 93 | ctx.WriteBuffer(available_language_codes); |
| 74 | 94 | } | |
| 75 | PushResponseLanguageCode(ctx, post4_0_0_max_entries); | 95 | PushResponseLanguageCode(ctx, post4_0_0_max_entries); |
| 76 | |||
| 77 | LOG_DEBUG(Service_SET, "called"); | ||
| 78 | } | 96 | } |
| 79 | 97 | ||
| 80 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { | 98 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { |
| 81 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | ||
| 82 | |||
| 83 | LOG_DEBUG(Service_SET, "called"); | 99 | LOG_DEBUG(Service_SET, "called"); |
| 100 | |||
| 101 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | ||
| 84 | } | 102 | } |
| 85 | 103 | ||
| 86 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { | 104 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { |
| @@ -90,18 +108,18 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { | |||
| 90 | } | 108 | } |
| 91 | 109 | ||
| 92 | void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { | 110 | void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { |
| 111 | LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); | ||
| 112 | |||
| 93 | IPC::ResponseBuilder rb{ctx, 4}; | 113 | IPC::ResponseBuilder rb{ctx, 4}; |
| 94 | rb.Push(RESULT_SUCCESS); | 114 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); | 115 | rb.PushEnum(available_language_codes[Settings::values.language_index]); |
| 96 | |||
| 97 | LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); | ||
| 98 | } | 116 | } |
| 99 | 117 | ||
| 100 | SET::SET() : ServiceFramework("set") { | 118 | SET::SET() : ServiceFramework("set") { |
| 101 | static const FunctionInfo functions[] = { | 119 | static const FunctionInfo functions[] = { |
| 102 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, | 120 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, |
| 103 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, | 121 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, |
| 104 | {2, nullptr, "MakeLanguageCode"}, | 122 | {2, &SET::MakeLanguageCode, "MakeLanguageCode"}, |
| 105 | {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, | 123 | {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, |
| 106 | {4, nullptr, "GetRegionCode"}, | 124 | {4, nullptr, "GetRegionCode"}, |
| 107 | {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, | 125 | {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, |
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 266f13e46..31f9cb296 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -38,6 +38,7 @@ public: | |||
| 38 | private: | 38 | private: |
| 39 | void GetLanguageCode(Kernel::HLERequestContext& ctx); | 39 | void GetLanguageCode(Kernel::HLERequestContext& ctx); |
| 40 | void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); | 40 | void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); |
| 41 | void MakeLanguageCode(Kernel::HLERequestContext& ctx); | ||
| 41 | void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); | 42 | void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); |
| 42 | void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); | 43 | void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); |
| 43 | void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); | 44 | void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 41efca31c..c9b4da5b0 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -10,22 +10,22 @@ | |||
| 10 | namespace Service::Set { | 10 | namespace Service::Set { |
| 11 | 11 | ||
| 12 | void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { | 12 | void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { |
| 13 | LOG_DEBUG(Service_SET, "called"); | ||
| 14 | |||
| 13 | IPC::ResponseBuilder rb{ctx, 3}; | 15 | IPC::ResponseBuilder rb{ctx, 3}; |
| 14 | 16 | ||
| 15 | rb.Push(RESULT_SUCCESS); | 17 | rb.Push(RESULT_SUCCESS); |
| 16 | rb.PushEnum(color_set); | 18 | rb.PushEnum(color_set); |
| 17 | |||
| 18 | LOG_DEBUG(Service_SET, "called"); | ||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { | 21 | void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { |
| 22 | LOG_DEBUG(Service_SET, "called"); | ||
| 23 | |||
| 22 | IPC::RequestParser rp{ctx}; | 24 | IPC::RequestParser rp{ctx}; |
| 23 | color_set = rp.PopEnum<ColorSet>(); | 25 | color_set = rp.PopEnum<ColorSet>(); |
| 24 | 26 | ||
| 25 | IPC::ResponseBuilder rb{ctx, 2}; | 27 | IPC::ResponseBuilder rb{ctx, 2}; |
| 26 | rb.Push(RESULT_SUCCESS); | 28 | rb.Push(RESULT_SUCCESS); |
| 27 | |||
| 28 | LOG_DEBUG(Service_SET, "called"); | ||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | 31 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 98f6e4111..74da4d5e6 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -14,25 +14,26 @@ namespace Service::SM { | |||
| 14 | 14 | ||
| 15 | void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { | 15 | void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { |
| 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); | 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); |
| 17 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); | ||
| 17 | ctx.Session()->ConvertToDomain(); | 18 | ctx.Session()->ConvertToDomain(); |
| 18 | 19 | ||
| 19 | IPC::ResponseBuilder rb{ctx, 3}; | 20 | IPC::ResponseBuilder rb{ctx, 3}; |
| 20 | rb.Push(RESULT_SUCCESS); | 21 | rb.Push(RESULT_SUCCESS); |
| 21 | rb.Push<u32>(1); // Converted sessions start with 1 request handler | 22 | rb.Push<u32>(1); // Converted sessions start with 1 request handler |
| 22 | |||
| 23 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); | ||
| 24 | } | 23 | } |
| 25 | 24 | ||
| 26 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { | 25 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { |
| 27 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong | 26 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong |
| 28 | // and that we probably want to actually make an entirely new Session, but we still need to | 27 | // and that we probably want to actually make an entirely new Session, but we still need to |
| 29 | // verify this on hardware. | 28 | // verify this on hardware. |
| 29 | LOG_DEBUG(Service, "called"); | ||
| 30 | |||
| 30 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 31 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 31 | rb.Push(RESULT_SUCCESS); | 32 | rb.Push(RESULT_SUCCESS); |
| 32 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; | 33 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; |
| 33 | rb.PushMoveObjects(session); | 34 | rb.PushMoveObjects(session); |
| 34 | 35 | ||
| 35 | LOG_DEBUG(Service, "called, session={}", session->GetObjectId()); | 36 | LOG_DEBUG(Service, "session={}", session->GetObjectId()); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { | 39 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { |
| @@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { | |||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | 45 | void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 47 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | 48 | IPC::ResponseBuilder rb{ctx, 3}; |
| 46 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.Push<u16>(0x500); | 50 | rb.Push<u16>(0x500); |
| 48 | |||
| 49 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | Controller::Controller() : ServiceFramework("IpcController") { | 53 | Controller::Controller() : ServiceFramework("IpcController") { |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 464e79d01..0d0f63a78 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService | |||
| 63 | return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); | 63 | return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | ResultCode ServiceManager::UnregisterService(const std::string& name) { | ||
| 67 | CASCADE_CODE(ValidateServiceName(name)); | ||
| 68 | |||
| 69 | const auto iter = registered_services.find(name); | ||
| 70 | if (iter == registered_services.end()) | ||
| 71 | return ERR_SERVICE_NOT_REGISTERED; | ||
| 72 | |||
| 73 | registered_services.erase(iter); | ||
| 74 | return RESULT_SUCCESS; | ||
| 75 | } | ||
| 76 | |||
| 66 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( | 77 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( |
| 67 | const std::string& name) { | 78 | const std::string& name) { |
| 68 | 79 | ||
| @@ -92,9 +103,10 @@ SM::~SM() = default; | |||
| 92 | * 0: ResultCode | 103 | * 0: ResultCode |
| 93 | */ | 104 | */ |
| 94 | void SM::Initialize(Kernel::HLERequestContext& ctx) { | 105 | void SM::Initialize(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_DEBUG(Service_SM, "called"); | ||
| 107 | |||
| 95 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| 96 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 97 | LOG_DEBUG(Service_SM, "called"); | ||
| 98 | } | 110 | } |
| 99 | 111 | ||
| 100 | void SM::GetService(Kernel::HLERequestContext& ctx) { | 112 | void SM::GetService(Kernel::HLERequestContext& ctx) { |
| @@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 127 | } | 139 | } |
| 128 | } | 140 | } |
| 129 | 141 | ||
| 142 | void SM::RegisterService(Kernel::HLERequestContext& ctx) { | ||
| 143 | IPC::RequestParser rp{ctx}; | ||
| 144 | |||
| 145 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 146 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 147 | |||
| 148 | const std::string name(name_buf.begin(), end); | ||
| 149 | |||
| 150 | const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>()); | ||
| 151 | const auto session_count = rp.PopRaw<u32>(); | ||
| 152 | |||
| 153 | LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool); | ||
| 154 | |||
| 155 | auto handle = service_manager->RegisterService(name, session_count); | ||
| 156 | if (handle.Failed()) { | ||
| 157 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", | ||
| 158 | handle.Code().raw); | ||
| 159 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 160 | rb.Push(handle.Code()); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | ||
| 165 | rb.Push(handle.Code()); | ||
| 166 | rb.PushMoveObjects(std::move(handle).Unwrap()); | ||
| 167 | } | ||
| 168 | |||
| 169 | void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | ||
| 170 | IPC::RequestParser rp{ctx}; | ||
| 171 | |||
| 172 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 173 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 174 | |||
| 175 | const std::string name(name_buf.begin(), end); | ||
| 176 | LOG_DEBUG(Service_SM, "called with name={}", name); | ||
| 177 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 179 | rb.Push(service_manager->UnregisterService(name)); | ||
| 180 | } | ||
| 181 | |||
| 130 | SM::SM(std::shared_ptr<ServiceManager> service_manager) | 182 | SM::SM(std::shared_ptr<ServiceManager> service_manager) |
| 131 | : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { | 183 | : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { |
| 132 | static const FunctionInfo functions[] = { | 184 | static const FunctionInfo functions[] = { |
| 133 | {0x00000000, &SM::Initialize, "Initialize"}, | 185 | {0x00000000, &SM::Initialize, "Initialize"}, |
| 134 | {0x00000001, &SM::GetService, "GetService"}, | 186 | {0x00000001, &SM::GetService, "GetService"}, |
| 135 | {0x00000002, nullptr, "RegisterService"}, | 187 | {0x00000002, &SM::RegisterService, "RegisterService"}, |
| 136 | {0x00000003, nullptr, "UnregisterService"}, | 188 | {0x00000003, &SM::UnregisterService, "UnregisterService"}, |
| 137 | }; | 189 | }; |
| 138 | RegisterHandlers(functions); | 190 | RegisterHandlers(functions); |
| 139 | } | 191 | } |
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 4f8145dda..bef25433e 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -35,6 +35,8 @@ public: | |||
| 35 | private: | 35 | private: |
| 36 | void Initialize(Kernel::HLERequestContext& ctx); | 36 | void Initialize(Kernel::HLERequestContext& ctx); |
| 37 | void GetService(Kernel::HLERequestContext& ctx); | 37 | void GetService(Kernel::HLERequestContext& ctx); |
| 38 | void RegisterService(Kernel::HLERequestContext& ctx); | ||
| 39 | void UnregisterService(Kernel::HLERequestContext& ctx); | ||
| 38 | 40 | ||
| 39 | std::shared_ptr<ServiceManager> service_manager; | 41 | std::shared_ptr<ServiceManager> service_manager; |
| 40 | }; | 42 | }; |
| @@ -48,6 +50,7 @@ public: | |||
| 48 | 50 | ||
| 49 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, | 51 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, |
| 50 | unsigned int max_sessions); | 52 | unsigned int max_sessions); |
| 53 | ResultCode UnregisterService(const std::string& name); | ||
| 51 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); | 54 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); |
| 52 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); | 55 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); |
| 53 | 56 | ||
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 44a6717d0..8db0c2f13 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp | |||
| @@ -3,34 +3,41 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <chrono> | ||
| 6 | #include <cstdlib> | 7 | #include <cstdlib> |
| 8 | #include <ctime> | ||
| 9 | #include <functional> | ||
| 7 | #include <vector> | 10 | #include <vector> |
| 8 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/service/spl/csrng.h" | 13 | #include "core/hle/service/spl/csrng.h" |
| 11 | #include "core/hle/service/spl/module.h" | 14 | #include "core/hle/service/spl/module.h" |
| 12 | #include "core/hle/service/spl/spl.h" | 15 | #include "core/hle/service/spl/spl.h" |
| 16 | #include "core/settings.h" | ||
| 13 | 17 | ||
| 14 | namespace Service::SPL { | 18 | namespace Service::SPL { |
| 15 | 19 | ||
| 16 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 20 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
| 17 | : ServiceFramework(name), module(std::move(module)) {} | 21 | : ServiceFramework(name), module(std::move(module)), |
| 22 | rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {} | ||
| 18 | 23 | ||
| 19 | Module::Interface::~Interface() = default; | 24 | Module::Interface::~Interface() = default; |
| 20 | 25 | ||
| 21 | void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { | 26 | void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { |
| 27 | LOG_DEBUG(Service_SPL, "called"); | ||
| 28 | |||
| 22 | IPC::RequestParser rp{ctx}; | 29 | IPC::RequestParser rp{ctx}; |
| 23 | 30 | ||
| 24 | std::size_t size = ctx.GetWriteBufferSize(); | 31 | std::size_t size = ctx.GetWriteBufferSize(); |
| 25 | 32 | ||
| 33 | std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max()); | ||
| 26 | std::vector<u8> data(size); | 34 | std::vector<u8> data(size); |
| 27 | std::generate(data.begin(), data.end(), std::rand); | 35 | std::generate(data.begin(), data.end(), [&] { return static_cast<u8>(distribution(rng)); }); |
| 28 | 36 | ||
| 29 | ctx.WriteBuffer(data); | 37 | ctx.WriteBuffer(data); |
| 30 | 38 | ||
| 31 | IPC::ResponseBuilder rb{ctx, 2}; | 39 | IPC::ResponseBuilder rb{ctx, 2}; |
| 32 | rb.Push(RESULT_SUCCESS); | 40 | rb.Push(RESULT_SUCCESS); |
| 33 | LOG_DEBUG(Service_SPL, "called"); | ||
| 34 | } | 41 | } |
| 35 | 42 | ||
| 36 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 43 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index 48fda6099..afa1f0295 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <random> | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | 9 | ||
| 9 | namespace Service::SPL { | 10 | namespace Service::SPL { |
| @@ -19,6 +20,9 @@ public: | |||
| 19 | 20 | ||
| 20 | protected: | 21 | protected: |
| 21 | std::shared_ptr<Module> module; | 22 | std::shared_ptr<Module> module; |
| 23 | |||
| 24 | private: | ||
| 25 | std::mt19937 rng; | ||
| 22 | }; | 26 | }; |
| 23 | }; | 27 | }; |
| 24 | 28 | ||
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index bc4f7a437..af40a1815 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -69,6 +69,7 @@ public: | |||
| 69 | private: | 69 | private: |
| 70 | void SetOption(Kernel::HLERequestContext& ctx) { | 70 | void SetOption(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_WARNING(Service_SSL, "(STUBBED) called"); | 71 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 72 | |||
| 72 | IPC::RequestParser rp{ctx}; | 73 | IPC::RequestParser rp{ctx}; |
| 73 | 74 | ||
| 74 | IPC::ResponseBuilder rb{ctx, 2}; | 75 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -114,6 +115,7 @@ private: | |||
| 114 | 115 | ||
| 115 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { | 116 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { |
| 116 | LOG_DEBUG(Service_SSL, "called"); | 117 | LOG_DEBUG(Service_SSL, "called"); |
| 118 | |||
| 117 | IPC::RequestParser rp{ctx}; | 119 | IPC::RequestParser rp{ctx}; |
| 118 | ssl_version = rp.Pop<u32>(); | 120 | ssl_version = rp.Pop<u32>(); |
| 119 | 121 | ||
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 18a5d71d5..b3a196f65 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp | |||
| @@ -21,9 +21,10 @@ Time::Time(std::shared_ptr<Module> time, const char* name) | |||
| 21 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, | 21 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, |
| 22 | {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, | 22 | {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, |
| 23 | {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, | 23 | {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, |
| 24 | {400, nullptr, "GetClockSnapshot"}, | 24 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, |
| 25 | {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, | 25 | {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, |
| 26 | {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, | 26 | {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, |
| 27 | "CalculateStandardUserSystemClockDifferenceByUser"}, | ||
| 27 | {501, nullptr, "CalculateSpanBetween"}, | 28 | {501, nullptr, "CalculateSpanBetween"}, |
| 28 | }; | 29 | }; |
| 29 | RegisterHandlers(functions); | 30 | RegisterHandlers(functions); |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 28fd8debc..60b201d06 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -15,6 +15,44 @@ | |||
| 15 | 15 | ||
| 16 | namespace Service::Time { | 16 | namespace Service::Time { |
| 17 | 17 | ||
| 18 | static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | ||
| 19 | CalendarAdditionalInfo& additional_info, | ||
| 20 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { | ||
| 21 | const std::time_t time(posix_time); | ||
| 22 | const std::tm* tm = std::localtime(&time); | ||
| 23 | if (tm == nullptr) { | ||
| 24 | calendar_time = {}; | ||
| 25 | additional_info = {}; | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | calendar_time.year = tm->tm_year + 1900; | ||
| 29 | calendar_time.month = tm->tm_mon + 1; | ||
| 30 | calendar_time.day = tm->tm_mday; | ||
| 31 | calendar_time.hour = tm->tm_hour; | ||
| 32 | calendar_time.minute = tm->tm_min; | ||
| 33 | calendar_time.second = tm->tm_sec; | ||
| 34 | |||
| 35 | additional_info.day_of_week = tm->tm_wday; | ||
| 36 | additional_info.day_of_year = tm->tm_yday; | ||
| 37 | std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); | ||
| 38 | additional_info.utc_offset = 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | static u64 CalendarToPosix(const CalendarTime& calendar_time, | ||
| 42 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { | ||
| 43 | std::tm time{}; | ||
| 44 | time.tm_year = calendar_time.year - 1900; | ||
| 45 | time.tm_mon = calendar_time.month - 1; | ||
| 46 | time.tm_mday = calendar_time.day; | ||
| 47 | |||
| 48 | time.tm_hour = calendar_time.hour; | ||
| 49 | time.tm_min = calendar_time.minute; | ||
| 50 | time.tm_sec = calendar_time.second; | ||
| 51 | |||
| 52 | std::time_t epoch_time = std::mktime(&time); | ||
| 53 | return static_cast<u64>(epoch_time); | ||
| 54 | } | ||
| 55 | |||
| 18 | class ISystemClock final : public ServiceFramework<ISystemClock> { | 56 | class ISystemClock final : public ServiceFramework<ISystemClock> { |
| 19 | public: | 57 | public: |
| 20 | ISystemClock() : ServiceFramework("ISystemClock") { | 58 | ISystemClock() : ServiceFramework("ISystemClock") { |
| @@ -34,6 +72,7 @@ private: | |||
| 34 | std::chrono::system_clock::now().time_since_epoch()) | 72 | std::chrono::system_clock::now().time_since_epoch()) |
| 35 | .count()}; | 73 | .count()}; |
| 36 | LOG_DEBUG(Service_Time, "called"); | 74 | LOG_DEBUG(Service_Time, "called"); |
| 75 | |||
| 37 | IPC::ResponseBuilder rb{ctx, 4}; | 76 | IPC::ResponseBuilder rb{ctx, 4}; |
| 38 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 39 | rb.Push<u64>(time_since_epoch); | 78 | rb.Push<u64>(time_since_epoch); |
| @@ -41,6 +80,7 @@ private: | |||
| 41 | 80 | ||
| 42 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { | 81 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { |
| 43 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 82 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 83 | |||
| 44 | SystemClockContext system_clock_ontext{}; | 84 | SystemClockContext system_clock_ontext{}; |
| 45 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; | 85 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; |
| 46 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| @@ -60,6 +100,7 @@ public: | |||
| 60 | private: | 100 | private: |
| 61 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { | 101 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { |
| 62 | LOG_DEBUG(Service_Time, "called"); | 102 | LOG_DEBUG(Service_Time, "called"); |
| 103 | |||
| 63 | SteadyClockTimePoint steady_clock_time_point{ | 104 | SteadyClockTimePoint steady_clock_time_point{ |
| 64 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; | 105 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; |
| 65 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; | 106 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; |
| @@ -80,8 +121,8 @@ public: | |||
| 80 | {5, nullptr, "GetTimeZoneRuleVersion"}, | 121 | {5, nullptr, "GetTimeZoneRuleVersion"}, |
| 81 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, | 122 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, |
| 82 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | 123 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, |
| 83 | {201, nullptr, "ToPosixTime"}, | 124 | {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, |
| 84 | {202, nullptr, "ToPosixTimeWithMyRule"}, | 125 | {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, |
| 85 | }; | 126 | }; |
| 86 | RegisterHandlers(functions); | 127 | RegisterHandlers(functions); |
| 87 | } | 128 | } |
| @@ -92,6 +133,7 @@ private: | |||
| 92 | 133 | ||
| 93 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { | 134 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_Time, "called"); | 135 | LOG_DEBUG(Service_Time, "called"); |
| 136 | |||
| 95 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; | 137 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; |
| 96 | rb.Push(RESULT_SUCCESS); | 138 | rb.Push(RESULT_SUCCESS); |
| 97 | rb.PushRaw(location_name); | 139 | rb.PushRaw(location_name); |
| @@ -99,6 +141,7 @@ private: | |||
| 99 | 141 | ||
| 100 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { | 142 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { |
| 101 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 143 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 144 | |||
| 102 | IPC::ResponseBuilder rb{ctx, 3}; | 145 | IPC::ResponseBuilder rb{ctx, 3}; |
| 103 | rb.Push(RESULT_SUCCESS); | 146 | rb.Push(RESULT_SUCCESS); |
| 104 | rb.Push<u32>(0); | 147 | rb.Push<u32>(0); |
| @@ -116,7 +159,6 @@ private: | |||
| 116 | void ToCalendarTime(Kernel::HLERequestContext& ctx) { | 159 | void ToCalendarTime(Kernel::HLERequestContext& ctx) { |
| 117 | IPC::RequestParser rp{ctx}; | 160 | IPC::RequestParser rp{ctx}; |
| 118 | const u64 posix_time = rp.Pop<u64>(); | 161 | const u64 posix_time = rp.Pop<u64>(); |
| 119 | |||
| 120 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 162 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 121 | 163 | ||
| 122 | TimeZoneRule time_zone_rule{}; | 164 | TimeZoneRule time_zone_rule{}; |
| @@ -137,7 +179,6 @@ private: | |||
| 137 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { | 179 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { |
| 138 | IPC::RequestParser rp{ctx}; | 180 | IPC::RequestParser rp{ctx}; |
| 139 | const u64 posix_time = rp.Pop<u64>(); | 181 | const u64 posix_time = rp.Pop<u64>(); |
| 140 | |||
| 141 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 182 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 142 | 183 | ||
| 143 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; | 184 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; |
| @@ -151,60 +192,137 @@ private: | |||
| 151 | rb.PushRaw(additional_info); | 192 | rb.PushRaw(additional_info); |
| 152 | } | 193 | } |
| 153 | 194 | ||
| 154 | void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | 195 | void ToPosixTime(Kernel::HLERequestContext& ctx) { |
| 155 | CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) { | 196 | // TODO(ogniK): Figure out how to handle multiple times |
| 156 | std::time_t t(posix_time); | 197 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 157 | std::tm* tm = std::localtime(&t); | 198 | |
| 158 | if (!tm) { | 199 | IPC::RequestParser rp{ctx}; |
| 159 | return; | 200 | auto calendar_time = rp.PopRaw<CalendarTime>(); |
| 160 | } | 201 | auto posix_time = CalendarToPosix(calendar_time, {}); |
| 161 | calendar_time.year = tm->tm_year + 1900; | 202 | |
| 162 | calendar_time.month = tm->tm_mon + 1; | 203 | IPC::ResponseBuilder rb{ctx, 3}; |
| 163 | calendar_time.day = tm->tm_mday; | 204 | rb.Push(RESULT_SUCCESS); |
| 164 | calendar_time.hour = tm->tm_hour; | 205 | rb.PushRaw<u32>(1); // Amount of times we're returning |
| 165 | calendar_time.minute = tm->tm_min; | 206 | ctx.WriteBuffer(&posix_time, sizeof(u64)); |
| 166 | calendar_time.second = tm->tm_sec; | 207 | } |
| 167 | 208 | ||
| 168 | additional_info.day_of_week = tm->tm_wday; | 209 | void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { |
| 169 | additional_info.day_of_year = tm->tm_yday; | 210 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 170 | std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); | 211 | |
| 171 | additional_info.utc_offset = 0; | 212 | IPC::RequestParser rp{ctx}; |
| 213 | auto calendar_time = rp.PopRaw<CalendarTime>(); | ||
| 214 | auto posix_time = CalendarToPosix(calendar_time, {}); | ||
| 215 | |||
| 216 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 217 | rb.Push(RESULT_SUCCESS); | ||
| 218 | rb.PushRaw<u32>(1); // Amount of times we're returning | ||
| 219 | ctx.WriteBuffer(&posix_time, sizeof(u64)); | ||
| 172 | } | 220 | } |
| 173 | }; | 221 | }; |
| 174 | 222 | ||
| 175 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { | 223 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { |
| 224 | LOG_DEBUG(Service_Time, "called"); | ||
| 225 | |||
| 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 226 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 177 | rb.Push(RESULT_SUCCESS); | 227 | rb.Push(RESULT_SUCCESS); |
| 178 | rb.PushIpcInterface<ISystemClock>(); | 228 | rb.PushIpcInterface<ISystemClock>(); |
| 179 | LOG_DEBUG(Service_Time, "called"); | ||
| 180 | } | 229 | } |
| 181 | 230 | ||
| 182 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { | 231 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { |
| 232 | LOG_DEBUG(Service_Time, "called"); | ||
| 233 | |||
| 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 234 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 184 | rb.Push(RESULT_SUCCESS); | 235 | rb.Push(RESULT_SUCCESS); |
| 185 | rb.PushIpcInterface<ISystemClock>(); | 236 | rb.PushIpcInterface<ISystemClock>(); |
| 186 | LOG_DEBUG(Service_Time, "called"); | ||
| 187 | } | 237 | } |
| 188 | 238 | ||
| 189 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | 239 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { |
| 240 | LOG_DEBUG(Service_Time, "called"); | ||
| 241 | |||
| 190 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 242 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 191 | rb.Push(RESULT_SUCCESS); | 243 | rb.Push(RESULT_SUCCESS); |
| 192 | rb.PushIpcInterface<ISteadyClock>(); | 244 | rb.PushIpcInterface<ISteadyClock>(); |
| 193 | LOG_DEBUG(Service_Time, "called"); | ||
| 194 | } | 245 | } |
| 195 | 246 | ||
| 196 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 247 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| 248 | LOG_DEBUG(Service_Time, "called"); | ||
| 249 | |||
| 197 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 250 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 198 | rb.Push(RESULT_SUCCESS); | 251 | rb.Push(RESULT_SUCCESS); |
| 199 | rb.PushIpcInterface<ITimeZoneService>(); | 252 | rb.PushIpcInterface<ITimeZoneService>(); |
| 200 | LOG_DEBUG(Service_Time, "called"); | ||
| 201 | } | 253 | } |
| 202 | 254 | ||
| 203 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | 255 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { |
| 256 | LOG_DEBUG(Service_Time, "called"); | ||
| 257 | |||
| 204 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 258 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 205 | rb.Push(RESULT_SUCCESS); | 259 | rb.Push(RESULT_SUCCESS); |
| 206 | rb.PushIpcInterface<ISystemClock>(); | 260 | rb.PushIpcInterface<ISystemClock>(); |
| 261 | } | ||
| 262 | |||
| 263 | void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | ||
| 207 | LOG_DEBUG(Service_Time, "called"); | 264 | LOG_DEBUG(Service_Time, "called"); |
| 265 | |||
| 266 | IPC::RequestParser rp{ctx}; | ||
| 267 | auto unknown_u8 = rp.PopRaw<u8>(); | ||
| 268 | |||
| 269 | ClockSnapshot clock_snapshot{}; | ||
| 270 | |||
| 271 | const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( | ||
| 272 | std::chrono::system_clock::now().time_since_epoch()) | ||
| 273 | .count()}; | ||
| 274 | CalendarTime calendar_time{}; | ||
| 275 | const std::time_t time(time_since_epoch); | ||
| 276 | const std::tm* tm = std::localtime(&time); | ||
| 277 | if (tm == nullptr) { | ||
| 278 | LOG_ERROR(Service_Time, "tm is a nullptr"); | ||
| 279 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 280 | rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / | ||
| 284 | 1000}; | ||
| 285 | |||
| 286 | LocationName location_name{"UTC"}; | ||
| 287 | calendar_time.year = tm->tm_year + 1900; | ||
| 288 | calendar_time.month = tm->tm_mon + 1; | ||
| 289 | calendar_time.day = tm->tm_mday; | ||
| 290 | calendar_time.hour = tm->tm_hour; | ||
| 291 | calendar_time.minute = tm->tm_min; | ||
| 292 | calendar_time.second = tm->tm_sec; | ||
| 293 | clock_snapshot.system_posix_time = time_since_epoch; | ||
| 294 | clock_snapshot.network_posix_time = time_since_epoch; | ||
| 295 | clock_snapshot.system_calendar_time = calendar_time; | ||
| 296 | clock_snapshot.network_calendar_time = calendar_time; | ||
| 297 | |||
| 298 | CalendarAdditionalInfo additional_info{}; | ||
| 299 | PosixToCalendar(time_since_epoch, calendar_time, additional_info, {}); | ||
| 300 | |||
| 301 | clock_snapshot.system_calendar_info = additional_info; | ||
| 302 | clock_snapshot.network_calendar_info = additional_info; | ||
| 303 | |||
| 304 | clock_snapshot.steady_clock_timepoint = steady_clock_time_point; | ||
| 305 | clock_snapshot.location_name = location_name; | ||
| 306 | clock_snapshot.clock_auto_adjustment_enabled = 1; | ||
| 307 | clock_snapshot.ipc_u8 = unknown_u8; | ||
| 308 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 309 | rb.Push(RESULT_SUCCESS); | ||
| 310 | ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); | ||
| 311 | } | ||
| 312 | |||
| 313 | void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser( | ||
| 314 | Kernel::HLERequestContext& ctx) { | ||
| 315 | LOG_DEBUG(Service_Time, "called"); | ||
| 316 | |||
| 317 | IPC::RequestParser rp{ctx}; | ||
| 318 | const auto snapshot_a = rp.PopRaw<ClockSnapshot>(); | ||
| 319 | const auto snapshot_b = rp.PopRaw<ClockSnapshot>(); | ||
| 320 | const u64 difference = | ||
| 321 | snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset; | ||
| 322 | |||
| 323 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 324 | rb.Push(RESULT_SUCCESS); | ||
| 325 | rb.PushRaw<u64>(difference); | ||
| 208 | } | 326 | } |
| 209 | 327 | ||
| 210 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) | 328 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) |
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 5659ecad3..ea43fbea7 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/common_funcs.h" | ||
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 9 | 10 | ||
| 10 | namespace Service::Time { | 11 | namespace Service::Time { |
| @@ -53,6 +54,23 @@ struct SystemClockContext { | |||
| 53 | static_assert(sizeof(SystemClockContext) == 0x20, | 54 | static_assert(sizeof(SystemClockContext) == 0x20, |
| 54 | "SystemClockContext structure has incorrect size"); | 55 | "SystemClockContext structure has incorrect size"); |
| 55 | 56 | ||
| 57 | struct ClockSnapshot { | ||
| 58 | SystemClockContext user_clock_context; | ||
| 59 | SystemClockContext network_clock_context; | ||
| 60 | s64_le system_posix_time; | ||
| 61 | s64_le network_posix_time; | ||
| 62 | CalendarTime system_calendar_time; | ||
| 63 | CalendarTime network_calendar_time; | ||
| 64 | CalendarAdditionalInfo system_calendar_info; | ||
| 65 | CalendarAdditionalInfo network_calendar_info; | ||
| 66 | SteadyClockTimePoint steady_clock_timepoint; | ||
| 67 | LocationName location_name; | ||
| 68 | u8 clock_auto_adjustment_enabled; | ||
| 69 | u8 ipc_u8; | ||
| 70 | INSERT_PADDING_BYTES(2); | ||
| 71 | }; | ||
| 72 | static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size"); | ||
| 73 | |||
| 56 | class Module final { | 74 | class Module final { |
| 57 | public: | 75 | public: |
| 58 | class Interface : public ServiceFramework<Interface> { | 76 | class Interface : public ServiceFramework<Interface> { |
| @@ -65,6 +83,8 @@ public: | |||
| 65 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); | 83 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); |
| 66 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); | 84 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); |
| 67 | void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); | 85 | void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); |
| 86 | void GetClockSnapshot(Kernel::HLERequestContext& ctx); | ||
| 87 | void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx); | ||
| 68 | 88 | ||
| 69 | protected: | 89 | protected: |
| 70 | std::shared_ptr<Module> time; | 90 | std::shared_ptr<Module> time; |
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index f0a831d45..58a9845fc 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp | |||
| @@ -73,7 +73,7 @@ public: | |||
| 73 | {3, nullptr, "Populate"}, | 73 | {3, nullptr, "Populate"}, |
| 74 | {4, nullptr, "PostBufferAsync"}, | 74 | {4, nullptr, "PostBufferAsync"}, |
| 75 | {5, nullptr, "GetXferReport"}, | 75 | {5, nullptr, "GetXferReport"}, |
| 76 | {6, nullptr, "Unknown2"}, | 76 | {6, nullptr, "PostBufferMultiAsync"}, |
| 77 | {7, nullptr, "Unknown3"}, | 77 | {7, nullptr, "Unknown3"}, |
| 78 | {8, nullptr, "Unknown4"}, | 78 | {8, nullptr, "Unknown4"}, |
| 79 | }; | 79 | }; |
| @@ -159,11 +159,11 @@ public: | |||
| 159 | 159 | ||
| 160 | private: | 160 | private: |
| 161 | void GetPdSession(Kernel::HLERequestContext& ctx) { | 161 | void GetPdSession(Kernel::HLERequestContext& ctx) { |
| 162 | LOG_DEBUG(Service_USB, "called"); | ||
| 163 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 164 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 163 | rb.Push(RESULT_SUCCESS); | 165 | rb.Push(RESULT_SUCCESS); |
| 164 | rb.PushIpcInterface<IPdSession>(); | 166 | rb.PushIpcInterface<IPdSession>(); |
| 165 | |||
| 166 | LOG_DEBUG(Service_USB, "called"); | ||
| 167 | } | 167 | } |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index d764b2406..311b0c765 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -18,7 +18,8 @@ | |||
| 18 | #include "common/swap.h" | 18 | #include "common/swap.h" |
| 19 | #include "core/core_timing.h" | 19 | #include "core/core_timing.h" |
| 20 | #include "core/hle/ipc_helpers.h" | 20 | #include "core/hle/ipc_helpers.h" |
| 21 | #include "core/hle/kernel/event.h" | 21 | #include "core/hle/kernel/readable_event.h" |
| 22 | #include "core/hle/kernel/writable_event.h" | ||
| 22 | #include "core/hle/service/nvdrv/nvdrv.h" | 23 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 23 | #include "core/hle/service/nvflinger/buffer_queue.h" | 24 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 24 | #include "core/hle/service/nvflinger/nvflinger.h" | 25 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -237,6 +238,22 @@ private: | |||
| 237 | Data data{}; | 238 | Data data{}; |
| 238 | }; | 239 | }; |
| 239 | 240 | ||
| 241 | /// Represents a parcel containing one int '0' as its data | ||
| 242 | /// Used by DetachBuffer and Disconnect | ||
| 243 | class IGBPEmptyResponseParcel : public Parcel { | ||
| 244 | protected: | ||
| 245 | void SerializeData() override { | ||
| 246 | Write(data); | ||
| 247 | } | ||
| 248 | |||
| 249 | private: | ||
| 250 | struct Data { | ||
| 251 | u32_le unk_0; | ||
| 252 | }; | ||
| 253 | |||
| 254 | Data data{}; | ||
| 255 | }; | ||
| 256 | |||
| 240 | class IGBPSetPreallocatedBufferRequestParcel : public Parcel { | 257 | class IGBPSetPreallocatedBufferRequestParcel : public Parcel { |
| 241 | public: | 258 | public: |
| 242 | explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) | 259 | explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) |
| @@ -488,13 +505,17 @@ private: | |||
| 488 | u32 id = rp.Pop<u32>(); | 505 | u32 id = rp.Pop<u32>(); |
| 489 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); | 506 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); |
| 490 | u32 flags = rp.Pop<u32>(); | 507 | u32 flags = rp.Pop<u32>(); |
| 491 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 492 | |||
| 493 | LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); | 508 | LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); |
| 494 | 509 | ||
| 510 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 511 | |||
| 495 | if (transaction == TransactionId::Connect) { | 512 | if (transaction == TransactionId::Connect) { |
| 496 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; | 513 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; |
| 497 | IGBPConnectResponseParcel response{1280, 720}; | 514 | IGBPConnectResponseParcel response{ |
| 515 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) * | ||
| 516 | Settings::values.resolution_factor), | ||
| 517 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * | ||
| 518 | Settings::values.resolution_factor)}; | ||
| 498 | ctx.WriteBuffer(response.Serialize()); | 519 | ctx.WriteBuffer(response.Serialize()); |
| 499 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { | 520 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { |
| 500 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; | 521 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; |
| @@ -522,12 +543,14 @@ private: | |||
| 522 | // Repeat TransactParcel DequeueBuffer when a buffer is available | 543 | // Repeat TransactParcel DequeueBuffer when a buffer is available |
| 523 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | 544 | auto buffer_queue = nv_flinger->GetBufferQueue(id); |
| 524 | std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); | 545 | std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); |
| 546 | ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer."); | ||
| 547 | |||
| 525 | IGBPDequeueBufferResponseParcel response{*slot}; | 548 | IGBPDequeueBufferResponseParcel response{*slot}; |
| 526 | ctx.WriteBuffer(response.Serialize()); | 549 | ctx.WriteBuffer(response.Serialize()); |
| 527 | IPC::ResponseBuilder rb{ctx, 2}; | 550 | IPC::ResponseBuilder rb{ctx, 2}; |
| 528 | rb.Push(RESULT_SUCCESS); | 551 | rb.Push(RESULT_SUCCESS); |
| 529 | }, | 552 | }, |
| 530 | buffer_queue->GetBufferWaitEvent()); | 553 | buffer_queue->GetWritableBufferWaitEvent()); |
| 531 | } | 554 | } |
| 532 | } else if (transaction == TransactionId::RequestBuffer) { | 555 | } else if (transaction == TransactionId::RequestBuffer) { |
| 533 | IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; | 556 | IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; |
| @@ -554,6 +577,12 @@ private: | |||
| 554 | ctx.WriteBuffer(response.Serialize()); | 577 | ctx.WriteBuffer(response.Serialize()); |
| 555 | } else if (transaction == TransactionId::CancelBuffer) { | 578 | } else if (transaction == TransactionId::CancelBuffer) { |
| 556 | LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); | 579 | LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); |
| 580 | } else if (transaction == TransactionId::Disconnect || | ||
| 581 | transaction == TransactionId::DetachBuffer) { | ||
| 582 | const auto buffer = ctx.ReadBuffer(); | ||
| 583 | |||
| 584 | IGBPEmptyResponseParcel response{}; | ||
| 585 | ctx.WriteBuffer(response.Serialize()); | ||
| 557 | } else { | 586 | } else { |
| 558 | ASSERT_MSG(false, "Unimplemented"); | 587 | ASSERT_MSG(false, "Unimplemented"); |
| 559 | } | 588 | } |
| @@ -567,9 +596,9 @@ private: | |||
| 567 | u32 id = rp.Pop<u32>(); | 596 | u32 id = rp.Pop<u32>(); |
| 568 | s32 addval = rp.PopRaw<s32>(); | 597 | s32 addval = rp.PopRaw<s32>(); |
| 569 | u32 type = rp.Pop<u32>(); | 598 | u32 type = rp.Pop<u32>(); |
| 570 | |||
| 571 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, | 599 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, |
| 572 | type); | 600 | type); |
| 601 | |||
| 573 | IPC::ResponseBuilder rb{ctx, 2}; | 602 | IPC::ResponseBuilder rb{ctx, 2}; |
| 574 | rb.Push(RESULT_SUCCESS); | 603 | rb.Push(RESULT_SUCCESS); |
| 575 | } | 604 | } |
| @@ -578,12 +607,11 @@ private: | |||
| 578 | IPC::RequestParser rp{ctx}; | 607 | IPC::RequestParser rp{ctx}; |
| 579 | u32 id = rp.Pop<u32>(); | 608 | u32 id = rp.Pop<u32>(); |
| 580 | u32 unknown = rp.Pop<u32>(); | 609 | u32 unknown = rp.Pop<u32>(); |
| 610 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | ||
| 581 | 611 | ||
| 582 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | 612 | auto buffer_queue = nv_flinger->GetBufferQueue(id); |
| 583 | 613 | ||
| 584 | // TODO(Subv): Find out what this actually is. | 614 | // TODO(Subv): Find out what this actually is. |
| 585 | |||
| 586 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | ||
| 587 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 615 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 588 | rb.Push(RESULT_SUCCESS); | 616 | rb.Push(RESULT_SUCCESS); |
| 589 | rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); | 617 | rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); |
| @@ -647,6 +675,7 @@ public: | |||
| 647 | private: | 675 | private: |
| 648 | void SetLayerZ(Kernel::HLERequestContext& ctx) { | 676 | void SetLayerZ(Kernel::HLERequestContext& ctx) { |
| 649 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 677 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 678 | |||
| 650 | IPC::RequestParser rp{ctx}; | 679 | IPC::RequestParser rp{ctx}; |
| 651 | u64 layer_id = rp.Pop<u64>(); | 680 | u64 layer_id = rp.Pop<u64>(); |
| 652 | u64 z_value = rp.Pop<u64>(); | 681 | u64 z_value = rp.Pop<u64>(); |
| @@ -659,28 +688,33 @@ private: | |||
| 659 | IPC::RequestParser rp{ctx}; | 688 | IPC::RequestParser rp{ctx}; |
| 660 | u64 layer_id = rp.Pop<u64>(); | 689 | u64 layer_id = rp.Pop<u64>(); |
| 661 | bool visibility = rp.Pop<bool>(); | 690 | bool visibility = rp.Pop<bool>(); |
| 662 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 663 | rb.Push(RESULT_SUCCESS); | ||
| 664 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, | 691 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, |
| 665 | visibility); | 692 | visibility); |
| 693 | |||
| 694 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 695 | rb.Push(RESULT_SUCCESS); | ||
| 666 | } | 696 | } |
| 667 | 697 | ||
| 668 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { | 698 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { |
| 699 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 700 | |||
| 669 | IPC::ResponseBuilder rb{ctx, 6}; | 701 | IPC::ResponseBuilder rb{ctx, 6}; |
| 670 | rb.Push(RESULT_SUCCESS); | 702 | rb.Push(RESULT_SUCCESS); |
| 671 | 703 | ||
| 672 | if (Settings::values.use_docked_mode) { | 704 | if (Settings::values.use_docked_mode) { |
| 673 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | 705 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 674 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | 706 | static_cast<u32>(Settings::values.resolution_factor)); |
| 707 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | ||
| 708 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 675 | } else { | 709 | } else { |
| 676 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | 710 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * |
| 677 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | 711 | static_cast<u32>(Settings::values.resolution_factor)); |
| 712 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * | ||
| 713 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 678 | } | 714 | } |
| 679 | 715 | ||
| 680 | rb.PushRaw<float>(60.0f); | 716 | rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games. |
| 681 | rb.Push<u32>(0); | 717 | rb.Push<u32>(0); |
| 682 | |||
| 683 | LOG_DEBUG(Service_VI, "called"); | ||
| 684 | } | 718 | } |
| 685 | }; | 719 | }; |
| 686 | 720 | ||
| @@ -763,6 +797,7 @@ public: | |||
| 763 | private: | 797 | private: |
| 764 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 798 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 765 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 799 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 800 | |||
| 766 | IPC::RequestParser rp{ctx}; | 801 | IPC::RequestParser rp{ctx}; |
| 767 | u64 display = rp.Pop<u64>(); | 802 | u64 display = rp.Pop<u64>(); |
| 768 | 803 | ||
| @@ -772,6 +807,7 @@ private: | |||
| 772 | 807 | ||
| 773 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { | 808 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { |
| 774 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 809 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 810 | |||
| 775 | IPC::RequestParser rp{ctx}; | 811 | IPC::RequestParser rp{ctx}; |
| 776 | u32 unknown = rp.Pop<u32>(); | 812 | u32 unknown = rp.Pop<u32>(); |
| 777 | rp.Skip(1, false); | 813 | rp.Skip(1, false); |
| @@ -787,6 +823,7 @@ private: | |||
| 787 | 823 | ||
| 788 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { | 824 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { |
| 789 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 825 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 826 | |||
| 790 | IPC::RequestParser rp{ctx}; | 827 | IPC::RequestParser rp{ctx}; |
| 791 | u32 stack = rp.Pop<u32>(); | 828 | u32 stack = rp.Pop<u32>(); |
| 792 | u64 layer_id = rp.Pop<u64>(); | 829 | u64 layer_id = rp.Pop<u64>(); |
| @@ -799,10 +836,11 @@ private: | |||
| 799 | IPC::RequestParser rp{ctx}; | 836 | IPC::RequestParser rp{ctx}; |
| 800 | u64 layer_id = rp.Pop<u64>(); | 837 | u64 layer_id = rp.Pop<u64>(); |
| 801 | bool visibility = rp.Pop<bool>(); | 838 | bool visibility = rp.Pop<bool>(); |
| 802 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 803 | rb.Push(RESULT_SUCCESS); | ||
| 804 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, | 839 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, |
| 805 | visibility); | 840 | visibility); |
| 841 | |||
| 842 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 843 | rb.Push(RESULT_SUCCESS); | ||
| 806 | } | 844 | } |
| 807 | 845 | ||
| 808 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 846 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| @@ -848,6 +886,7 @@ private: | |||
| 848 | 886 | ||
| 849 | void OpenDisplay(Kernel::HLERequestContext& ctx) { | 887 | void OpenDisplay(Kernel::HLERequestContext& ctx) { |
| 850 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 888 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 889 | |||
| 851 | IPC::RequestParser rp{ctx}; | 890 | IPC::RequestParser rp{ctx}; |
| 852 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 891 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 853 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 892 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -863,6 +902,7 @@ private: | |||
| 863 | 902 | ||
| 864 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 903 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 865 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 904 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 905 | |||
| 866 | IPC::RequestParser rp{ctx}; | 906 | IPC::RequestParser rp{ctx}; |
| 867 | u64 display_id = rp.Pop<u64>(); | 907 | u64 display_id = rp.Pop<u64>(); |
| 868 | 908 | ||
| @@ -872,6 +912,7 @@ private: | |||
| 872 | 912 | ||
| 873 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { | 913 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { |
| 874 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 914 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 915 | |||
| 875 | IPC::RequestParser rp{ctx}; | 916 | IPC::RequestParser rp{ctx}; |
| 876 | u64 display_id = rp.Pop<u64>(); | 917 | u64 display_id = rp.Pop<u64>(); |
| 877 | 918 | ||
| @@ -879,16 +920,21 @@ private: | |||
| 879 | rb.Push(RESULT_SUCCESS); | 920 | rb.Push(RESULT_SUCCESS); |
| 880 | 921 | ||
| 881 | if (Settings::values.use_docked_mode) { | 922 | if (Settings::values.use_docked_mode) { |
| 882 | rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); | 923 | rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) * |
| 883 | rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); | 924 | static_cast<u32>(Settings::values.resolution_factor)); |
| 925 | rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) * | ||
| 926 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 884 | } else { | 927 | } else { |
| 885 | rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); | 928 | rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) * |
| 886 | rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); | 929 | static_cast<u32>(Settings::values.resolution_factor)); |
| 930 | rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) * | ||
| 931 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 887 | } | 932 | } |
| 888 | } | 933 | } |
| 889 | 934 | ||
| 890 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { | 935 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { |
| 891 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 936 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 937 | |||
| 892 | IPC::RequestParser rp{ctx}; | 938 | IPC::RequestParser rp{ctx}; |
| 893 | u32 scaling_mode = rp.Pop<u32>(); | 939 | u32 scaling_mode = rp.Pop<u32>(); |
| 894 | u64 unknown = rp.Pop<u64>(); | 940 | u64 unknown = rp.Pop<u64>(); |
| @@ -898,17 +944,21 @@ private: | |||
| 898 | } | 944 | } |
| 899 | 945 | ||
| 900 | void ListDisplays(Kernel::HLERequestContext& ctx) { | 946 | void ListDisplays(Kernel::HLERequestContext& ctx) { |
| 947 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 948 | |||
| 901 | IPC::RequestParser rp{ctx}; | 949 | IPC::RequestParser rp{ctx}; |
| 902 | DisplayInfo display_info; | 950 | DisplayInfo display_info; |
| 951 | display_info.width *= static_cast<u64>(Settings::values.resolution_factor); | ||
| 952 | display_info.height *= static_cast<u64>(Settings::values.resolution_factor); | ||
| 903 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); | 953 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); |
| 904 | IPC::ResponseBuilder rb{ctx, 4}; | 954 | IPC::ResponseBuilder rb{ctx, 4}; |
| 905 | rb.Push(RESULT_SUCCESS); | 955 | rb.Push(RESULT_SUCCESS); |
| 906 | rb.Push<u64>(1); | 956 | rb.Push<u64>(1); |
| 907 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 908 | } | 957 | } |
| 909 | 958 | ||
| 910 | void OpenLayer(Kernel::HLERequestContext& ctx) { | 959 | void OpenLayer(Kernel::HLERequestContext& ctx) { |
| 911 | LOG_DEBUG(Service_VI, "called"); | 960 | LOG_DEBUG(Service_VI, "called"); |
| 961 | |||
| 912 | IPC::RequestParser rp{ctx}; | 962 | IPC::RequestParser rp{ctx}; |
| 913 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 963 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 914 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 964 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -959,6 +1009,7 @@ private: | |||
| 959 | 1009 | ||
| 960 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { | 1010 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { |
| 961 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 1011 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 1012 | |||
| 962 | IPC::RequestParser rp{ctx}; | 1013 | IPC::RequestParser rp{ctx}; |
| 963 | u64 display_id = rp.Pop<u64>(); | 1014 | u64 display_id = rp.Pop<u64>(); |
| 964 | 1015 | ||
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 8518dddcb..ac04d72d7 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | ||
| 11 | #include "core/file_sys/content_archive.h" | 10 | #include "core/file_sys/content_archive.h" |
| 12 | #include "core/file_sys/control_metadata.h" | 11 | #include "core/file_sys/control_metadata.h" |
| 13 | #include "core/file_sys/patch_manager.h" | 12 | #include "core/file_sys/patch_manager.h" |
| @@ -146,7 +145,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 146 | const VAddr load_addr = next_load_addr; | 145 | const VAddr load_addr = next_load_addr; |
| 147 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 146 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 148 | const auto tentative_next_load_addr = | 147 | const auto tentative_next_load_addr = |
| 149 | AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm); | 148 | AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm); |
| 150 | if (!tentative_next_load_addr) { | 149 | if (!tentative_next_load_addr) { |
| 151 | return ResultStatus::ErrorLoadingNSO; | 150 | return ResultStatus::ErrorLoadingNSO; |
| 152 | } | 151 | } |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index bc8e402a8..4fad0c0dd 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -10,12 +10,13 @@ | |||
| 10 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 13 | #include "core/core.h" | ||
| 14 | #include "core/file_sys/control_metadata.h" | 13 | #include "core/file_sys/control_metadata.h" |
| 14 | #include "core/file_sys/romfs_factory.h" | ||
| 15 | #include "core/file_sys/vfs_offset.h" | 15 | #include "core/file_sys/vfs_offset.h" |
| 16 | #include "core/gdbstub/gdbstub.h" | 16 | #include "core/gdbstub/gdbstub.h" |
| 17 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/vm_manager.h" | 18 | #include "core/hle/kernel/vm_manager.h" |
| 19 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 19 | #include "core/loader/nro.h" | 20 | #include "core/loader/nro.h" |
| 20 | #include "core/loader/nso.h" | 21 | #include "core/loader/nso.h" |
| 21 | #include "core/memory.h" | 22 | #include "core/memory.h" |
| @@ -127,9 +128,8 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 127 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 128 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 128 | } | 129 | } |
| 129 | 130 | ||
| 130 | /*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, | 131 | static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, |
| 131 | VAddr load_base) { | 132 | const std::string& name, VAddr load_base) { |
| 132 | |||
| 133 | if (data.size() < sizeof(NroHeader)) { | 133 | if (data.size() < sizeof(NroHeader)) { |
| 134 | return {}; | 134 | return {}; |
| 135 | } | 135 | } |
| @@ -168,23 +168,26 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 168 | arg_data.size()); | 168 | arg_data.size()); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | // Read MOD header | ||
| 172 | ModHeader mod_header{}; | ||
| 173 | // Default .bss to NRO header bss size if MOD0 section doesn't exist | 171 | // Default .bss to NRO header bss size if MOD0 section doesn't exist |
| 174 | u32 bss_size{PageAlignSize(nro_header.bss_size)}; | 172 | u32 bss_size{PageAlignSize(nro_header.bss_size)}; |
| 173 | |||
| 174 | // Read MOD header | ||
| 175 | ModHeader mod_header{}; | ||
| 175 | std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset, | 176 | std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset, |
| 176 | sizeof(ModHeader)); | 177 | sizeof(ModHeader)); |
| 178 | |||
| 177 | const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; | 179 | const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; |
| 178 | if (has_mod_header) { | 180 | if (has_mod_header) { |
| 179 | // Resize program image to include .bss section and page align each section | 181 | // Resize program image to include .bss section and page align each section |
| 180 | bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); | 182 | bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); |
| 181 | } | 183 | } |
| 184 | |||
| 182 | codeset.DataSegment().size += bss_size; | 185 | codeset.DataSegment().size += bss_size; |
| 183 | program_image.resize(static_cast<u32>(program_image.size()) + bss_size); | 186 | program_image.resize(static_cast<u32>(program_image.size()) + bss_size); |
| 184 | 187 | ||
| 185 | // Load codeset for current process | 188 | // Load codeset for current process |
| 186 | codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 189 | codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 187 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); | 190 | process.LoadModule(std::move(codeset), load_base); |
| 188 | 191 | ||
| 189 | // Register module with GDBStub | 192 | // Register module with GDBStub |
| 190 | GDBStub::RegisterModule(name, load_base, load_base); | 193 | GDBStub::RegisterModule(name, load_base, load_base); |
| @@ -192,8 +195,9 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 192 | return true; | 195 | return true; |
| 193 | } | 196 | } |
| 194 | 197 | ||
| 195 | bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | 198 | bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, |
| 196 | return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); | 199 | VAddr load_base) { |
| 200 | return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base); | ||
| 197 | } | 201 | } |
| 198 | 202 | ||
| 199 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | 203 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { |
| @@ -204,10 +208,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | |||
| 204 | // Load NRO | 208 | // Load NRO |
| 205 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 209 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 206 | 210 | ||
| 207 | if (!LoadNro(*file, base_address)) { | 211 | if (!LoadNro(process, *file, base_address)) { |
| 208 | return ResultStatus::ErrorLoadingNRO; | 212 | return ResultStatus::ErrorLoadingNRO; |
| 209 | } | 213 | } |
| 210 | 214 | ||
| 215 | if (romfs != nullptr) | ||
| 216 | Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); | ||
| 217 | |||
| 211 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); | 218 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); |
| 212 | 219 | ||
| 213 | is_loaded = true; | 220 | is_loaded = true; |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 3e6959302..6deff3a51 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -14,6 +14,10 @@ namespace FileSys { | |||
| 14 | class NACP; | 14 | class NACP; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace Kernel { | ||
| 18 | class Process; | ||
| 19 | } | ||
| 20 | |||
| 17 | namespace Loader { | 21 | namespace Loader { |
| 18 | 22 | ||
| 19 | /// Loads an NRO file | 23 | /// Loads an NRO file |
| @@ -41,10 +45,8 @@ public: | |||
| 41 | ResultStatus ReadTitle(std::string& title) override; | 45 | ResultStatus ReadTitle(std::string& title) override; |
| 42 | bool IsRomFSUpdatable() const override; | 46 | bool IsRomFSUpdatable() const override; |
| 43 | 47 | ||
| 44 | static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base); | ||
| 45 | |||
| 46 | private: | 48 | private: |
| 47 | bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); | 49 | bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base); |
| 48 | 50 | ||
| 49 | std::vector<u8> icon_data; | 51 | std::vector<u8> icon_data; |
| 50 | std::unique_ptr<FileSys::NACP> nacp; | 52 | std::unique_ptr<FileSys::NACP> nacp; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 68efca5c0..6ded0b707 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/core.h" | ||
| 13 | #include "core/file_sys/patch_manager.h" | 12 | #include "core/file_sys/patch_manager.h" |
| 14 | #include "core/gdbstub/gdbstub.h" | 13 | #include "core/gdbstub/gdbstub.h" |
| 15 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| @@ -93,7 +92,8 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 93 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 92 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, | 95 | std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, |
| 96 | const FileSys::VfsFile& file, VAddr load_base, | ||
| 97 | bool should_pass_arguments, | 97 | bool should_pass_arguments, |
| 98 | std::optional<FileSys::PatchManager> pm) { | 98 | std::optional<FileSys::PatchManager> pm) { |
| 99 | if (file.GetSize() < sizeof(NsoHeader)) | 99 | if (file.GetSize() < sizeof(NsoHeader)) |
| @@ -154,7 +154,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd | |||
| 154 | program_image.resize(image_size); | 154 | program_image.resize(image_size); |
| 155 | 155 | ||
| 156 | // Apply patches if necessary | 156 | // Apply patches if necessary |
| 157 | if (pm && pm->HasNSOPatch(nso_header.build_id)) { | 157 | if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { |
| 158 | std::vector<u8> pi_header(program_image.size() + 0x100); | 158 | std::vector<u8> pi_header(program_image.size() + 0x100); |
| 159 | std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); | 159 | std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); |
| 160 | std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); | 160 | std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); |
| @@ -166,7 +166,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd | |||
| 166 | 166 | ||
| 167 | // Load codeset for current process | 167 | // Load codeset for current process |
| 168 | codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 168 | codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 169 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); | 169 | process.LoadModule(std::move(codeset), load_base); |
| 170 | 170 | ||
| 171 | // Register module with GDBStub | 171 | // Register module with GDBStub |
| 172 | GDBStub::RegisterModule(file.GetName(), load_base, load_base); | 172 | GDBStub::RegisterModule(file.GetName(), load_base, load_base); |
| @@ -181,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { | |||
| 181 | 181 | ||
| 182 | // Load module | 182 | // Load module |
| 183 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | 183 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 184 | if (!LoadModule(*file, base_address, true)) { | 184 | if (!LoadModule(process, *file, base_address, true)) { |
| 185 | return ResultStatus::ErrorLoadingNSO; | 185 | return ResultStatus::ErrorLoadingNSO; |
| 186 | } | 186 | } |
| 187 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); | 187 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 433306139..0c1defbb6 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include "core/loader/linker.h" | 10 | #include "core/loader/linker.h" |
| 11 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| 12 | 12 | ||
| 13 | namespace Kernel { | ||
| 14 | class Process; | ||
| 15 | } | ||
| 16 | |||
| 13 | namespace Loader { | 17 | namespace Loader { |
| 14 | 18 | ||
| 15 | constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; | 19 | constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; |
| @@ -37,8 +41,8 @@ public: | |||
| 37 | return IdentifyType(file); | 41 | return IdentifyType(file); |
| 38 | } | 42 | } |
| 39 | 43 | ||
| 40 | static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base, | 44 | static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file, |
| 41 | bool should_pass_arguments, | 45 | VAddr load_base, bool should_pass_arguments, |
| 42 | std::optional<FileSys::PatchManager> pm = {}); | 46 | std::optional<FileSys::PatchManager> pm = {}); |
| 43 | 47 | ||
| 44 | ResultStatus Load(Kernel::Process& process) override; | 48 | ResultStatus Load(Kernel::Process& process) override; |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 0da159559..26fcd3405 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -10,6 +10,56 @@ | |||
| 10 | 10 | ||
| 11 | namespace Settings { | 11 | namespace Settings { |
| 12 | 12 | ||
| 13 | namespace NativeButton { | ||
| 14 | const std::array<const char*, NumButtons> mapping = {{ | ||
| 15 | "button_a", | ||
| 16 | "button_b", | ||
| 17 | "button_x", | ||
| 18 | "button_y", | ||
| 19 | "button_lstick", | ||
| 20 | "button_rstick", | ||
| 21 | "button_l", | ||
| 22 | "button_r", | ||
| 23 | "button_zl", | ||
| 24 | "button_zr", | ||
| 25 | "button_plus", | ||
| 26 | "button_minus", | ||
| 27 | "button_dleft", | ||
| 28 | "button_dup", | ||
| 29 | "button_dright", | ||
| 30 | "button_ddown", | ||
| 31 | "button_lstick_left", | ||
| 32 | "button_lstick_up", | ||
| 33 | "button_lstick_right", | ||
| 34 | "button_lstick_down", | ||
| 35 | "button_rstick_left", | ||
| 36 | "button_rstick_up", | ||
| 37 | "button_rstick_right", | ||
| 38 | "button_rstick_down", | ||
| 39 | "button_sl", | ||
| 40 | "button_sr", | ||
| 41 | "button_home", | ||
| 42 | "button_screenshot", | ||
| 43 | }}; | ||
| 44 | } | ||
| 45 | |||
| 46 | namespace NativeAnalog { | ||
| 47 | const std::array<const char*, NumAnalogs> mapping = {{ | ||
| 48 | "lstick", | ||
| 49 | "rstick", | ||
| 50 | }}; | ||
| 51 | } | ||
| 52 | |||
| 53 | namespace NativeMouseButton { | ||
| 54 | const std::array<const char*, NumMouseButtons> mapping = {{ | ||
| 55 | "left", | ||
| 56 | "right", | ||
| 57 | "middle", | ||
| 58 | "forward", | ||
| 59 | "back", | ||
| 60 | }}; | ||
| 61 | } | ||
| 62 | |||
| 13 | Values values = {}; | 63 | Values values = {}; |
| 14 | 64 | ||
| 15 | void Apply() { | 65 | void Apply() { |
diff --git a/src/core/settings.h b/src/core/settings.h index a8954647f..a0c5fd447 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <atomic> | 8 | #include <atomic> |
| 9 | #include <optional> | ||
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| @@ -59,36 +60,7 @@ constexpr int BUTTON_NS_END = NumButtons; | |||
| 59 | constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; | 60 | constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; |
| 60 | constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; | 61 | constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; |
| 61 | 62 | ||
| 62 | static const std::array<const char*, NumButtons> mapping = {{ | 63 | extern const std::array<const char*, NumButtons> mapping; |
| 63 | "button_a", | ||
| 64 | "button_b", | ||
| 65 | "button_x", | ||
| 66 | "button_y", | ||
| 67 | "button_lstick", | ||
| 68 | "button_rstick", | ||
| 69 | "button_l", | ||
| 70 | "button_r", | ||
| 71 | "button_zl", | ||
| 72 | "button_zr", | ||
| 73 | "button_plus", | ||
| 74 | "button_minus", | ||
| 75 | "button_dleft", | ||
| 76 | "button_dup", | ||
| 77 | "button_dright", | ||
| 78 | "button_ddown", | ||
| 79 | "button_lstick_left", | ||
| 80 | "button_lstick_up", | ||
| 81 | "button_lstick_right", | ||
| 82 | "button_lstick_down", | ||
| 83 | "button_rstick_left", | ||
| 84 | "button_rstick_up", | ||
| 85 | "button_rstick_right", | ||
| 86 | "button_rstick_down", | ||
| 87 | "button_sl", | ||
| 88 | "button_sr", | ||
| 89 | "button_home", | ||
| 90 | "button_screenshot", | ||
| 91 | }}; | ||
| 92 | 64 | ||
| 93 | } // namespace NativeButton | 65 | } // namespace NativeButton |
| 94 | 66 | ||
| @@ -104,24 +76,298 @@ constexpr int STICK_HID_BEGIN = LStick; | |||
| 104 | constexpr int STICK_HID_END = NumAnalogs; | 76 | constexpr int STICK_HID_END = NumAnalogs; |
| 105 | constexpr int NUM_STICKS_HID = NumAnalogs; | 77 | constexpr int NUM_STICKS_HID = NumAnalogs; |
| 106 | 78 | ||
| 107 | static const std::array<const char*, NumAnalogs> mapping = {{ | 79 | extern const std::array<const char*, NumAnalogs> mapping; |
| 108 | "lstick", | ||
| 109 | "rstick", | ||
| 110 | }}; | ||
| 111 | } // namespace NativeAnalog | 80 | } // namespace NativeAnalog |
| 112 | 81 | ||
| 82 | namespace NativeMouseButton { | ||
| 83 | enum Values { | ||
| 84 | Left, | ||
| 85 | Right, | ||
| 86 | Middle, | ||
| 87 | Forward, | ||
| 88 | Back, | ||
| 89 | |||
| 90 | NumMouseButtons, | ||
| 91 | }; | ||
| 92 | |||
| 93 | constexpr int MOUSE_HID_BEGIN = Left; | ||
| 94 | constexpr int MOUSE_HID_END = NumMouseButtons; | ||
| 95 | constexpr int NUM_MOUSE_HID = NumMouseButtons; | ||
| 96 | |||
| 97 | extern const std::array<const char*, NumMouseButtons> mapping; | ||
| 98 | } // namespace NativeMouseButton | ||
| 99 | |||
| 100 | namespace NativeKeyboard { | ||
| 101 | enum Keys { | ||
| 102 | None, | ||
| 103 | Error, | ||
| 104 | |||
| 105 | A = 4, | ||
| 106 | B, | ||
| 107 | C, | ||
| 108 | D, | ||
| 109 | E, | ||
| 110 | F, | ||
| 111 | G, | ||
| 112 | H, | ||
| 113 | I, | ||
| 114 | J, | ||
| 115 | K, | ||
| 116 | L, | ||
| 117 | M, | ||
| 118 | N, | ||
| 119 | O, | ||
| 120 | P, | ||
| 121 | Q, | ||
| 122 | R, | ||
| 123 | S, | ||
| 124 | T, | ||
| 125 | U, | ||
| 126 | V, | ||
| 127 | W, | ||
| 128 | X, | ||
| 129 | Y, | ||
| 130 | Z, | ||
| 131 | N1, | ||
| 132 | N2, | ||
| 133 | N3, | ||
| 134 | N4, | ||
| 135 | N5, | ||
| 136 | N6, | ||
| 137 | N7, | ||
| 138 | N8, | ||
| 139 | N9, | ||
| 140 | N0, | ||
| 141 | Enter, | ||
| 142 | Escape, | ||
| 143 | Backspace, | ||
| 144 | Tab, | ||
| 145 | Space, | ||
| 146 | Minus, | ||
| 147 | Equal, | ||
| 148 | LeftBrace, | ||
| 149 | RightBrace, | ||
| 150 | Backslash, | ||
| 151 | Tilde, | ||
| 152 | Semicolon, | ||
| 153 | Apostrophe, | ||
| 154 | Grave, | ||
| 155 | Comma, | ||
| 156 | Dot, | ||
| 157 | Slash, | ||
| 158 | CapsLockKey, | ||
| 159 | |||
| 160 | F1, | ||
| 161 | F2, | ||
| 162 | F3, | ||
| 163 | F4, | ||
| 164 | F5, | ||
| 165 | F6, | ||
| 166 | F7, | ||
| 167 | F8, | ||
| 168 | F9, | ||
| 169 | F10, | ||
| 170 | F11, | ||
| 171 | F12, | ||
| 172 | |||
| 173 | SystemRequest, | ||
| 174 | ScrollLockKey, | ||
| 175 | Pause, | ||
| 176 | Insert, | ||
| 177 | Home, | ||
| 178 | PageUp, | ||
| 179 | Delete, | ||
| 180 | End, | ||
| 181 | PageDown, | ||
| 182 | Right, | ||
| 183 | Left, | ||
| 184 | Down, | ||
| 185 | Up, | ||
| 186 | |||
| 187 | NumLockKey, | ||
| 188 | KPSlash, | ||
| 189 | KPAsterisk, | ||
| 190 | KPMinus, | ||
| 191 | KPPlus, | ||
| 192 | KPEnter, | ||
| 193 | KP1, | ||
| 194 | KP2, | ||
| 195 | KP3, | ||
| 196 | KP4, | ||
| 197 | KP5, | ||
| 198 | KP6, | ||
| 199 | KP7, | ||
| 200 | KP8, | ||
| 201 | KP9, | ||
| 202 | KP0, | ||
| 203 | KPDot, | ||
| 204 | |||
| 205 | Key102, | ||
| 206 | Compose, | ||
| 207 | Power, | ||
| 208 | KPEqual, | ||
| 209 | |||
| 210 | F13, | ||
| 211 | F14, | ||
| 212 | F15, | ||
| 213 | F16, | ||
| 214 | F17, | ||
| 215 | F18, | ||
| 216 | F19, | ||
| 217 | F20, | ||
| 218 | F21, | ||
| 219 | F22, | ||
| 220 | F23, | ||
| 221 | F24, | ||
| 222 | |||
| 223 | Open, | ||
| 224 | Help, | ||
| 225 | Properties, | ||
| 226 | Front, | ||
| 227 | Stop, | ||
| 228 | Repeat, | ||
| 229 | Undo, | ||
| 230 | Cut, | ||
| 231 | Copy, | ||
| 232 | Paste, | ||
| 233 | Find, | ||
| 234 | Mute, | ||
| 235 | VolumeUp, | ||
| 236 | VolumeDown, | ||
| 237 | CapsLockActive, | ||
| 238 | NumLockActive, | ||
| 239 | ScrollLockActive, | ||
| 240 | KPComma, | ||
| 241 | |||
| 242 | KPLeftParenthesis, | ||
| 243 | KPRightParenthesis, | ||
| 244 | |||
| 245 | LeftControlKey = 0xE0, | ||
| 246 | LeftShiftKey, | ||
| 247 | LeftAltKey, | ||
| 248 | LeftMetaKey, | ||
| 249 | RightControlKey, | ||
| 250 | RightShiftKey, | ||
| 251 | RightAltKey, | ||
| 252 | RightMetaKey, | ||
| 253 | |||
| 254 | MediaPlayPause, | ||
| 255 | MediaStopCD, | ||
| 256 | MediaPrevious, | ||
| 257 | MediaNext, | ||
| 258 | MediaEject, | ||
| 259 | MediaVolumeUp, | ||
| 260 | MediaVolumeDown, | ||
| 261 | MediaMute, | ||
| 262 | MediaWebsite, | ||
| 263 | MediaBack, | ||
| 264 | MediaForward, | ||
| 265 | MediaStop, | ||
| 266 | MediaFind, | ||
| 267 | MediaScrollUp, | ||
| 268 | MediaScrollDown, | ||
| 269 | MediaEdit, | ||
| 270 | MediaSleep, | ||
| 271 | MediaCoffee, | ||
| 272 | MediaRefresh, | ||
| 273 | MediaCalculator, | ||
| 274 | |||
| 275 | NumKeyboardKeys, | ||
| 276 | }; | ||
| 277 | |||
| 278 | static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys."); | ||
| 279 | |||
| 280 | enum Modifiers { | ||
| 281 | LeftControl, | ||
| 282 | LeftShift, | ||
| 283 | LeftAlt, | ||
| 284 | LeftMeta, | ||
| 285 | RightControl, | ||
| 286 | RightShift, | ||
| 287 | RightAlt, | ||
| 288 | RightMeta, | ||
| 289 | CapsLock, | ||
| 290 | ScrollLock, | ||
| 291 | NumLock, | ||
| 292 | |||
| 293 | NumKeyboardMods, | ||
| 294 | }; | ||
| 295 | |||
| 296 | constexpr int KEYBOARD_KEYS_HID_BEGIN = None; | ||
| 297 | constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys; | ||
| 298 | constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys; | ||
| 299 | |||
| 300 | constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl; | ||
| 301 | constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods; | ||
| 302 | constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods; | ||
| 303 | |||
| 304 | } // namespace NativeKeyboard | ||
| 305 | |||
| 306 | using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>; | ||
| 307 | using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>; | ||
| 308 | using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>; | ||
| 309 | using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>; | ||
| 310 | using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>; | ||
| 311 | |||
| 312 | constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; | ||
| 313 | constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; | ||
| 314 | constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; | ||
| 315 | constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E; | ||
| 316 | |||
| 317 | enum class ControllerType { | ||
| 318 | ProController, | ||
| 319 | DualJoycon, | ||
| 320 | RightJoycon, | ||
| 321 | LeftJoycon, | ||
| 322 | }; | ||
| 323 | |||
| 324 | struct PlayerInput { | ||
| 325 | bool connected; | ||
| 326 | ControllerType type; | ||
| 327 | ButtonsRaw buttons; | ||
| 328 | AnalogsRaw analogs; | ||
| 329 | |||
| 330 | u32 body_color_right; | ||
| 331 | u32 button_color_right; | ||
| 332 | u32 body_color_left; | ||
| 333 | u32 button_color_left; | ||
| 334 | }; | ||
| 335 | |||
| 336 | struct TouchscreenInput { | ||
| 337 | bool enabled; | ||
| 338 | std::string device; | ||
| 339 | |||
| 340 | u32 finger; | ||
| 341 | u32 diameter_x; | ||
| 342 | u32 diameter_y; | ||
| 343 | u32 rotation_angle; | ||
| 344 | }; | ||
| 345 | |||
| 113 | struct Values { | 346 | struct Values { |
| 114 | // System | 347 | // System |
| 115 | bool use_docked_mode; | 348 | bool use_docked_mode; |
| 116 | bool enable_nfc; | 349 | bool enable_nfc; |
| 350 | std::optional<u32> rng_seed; | ||
| 117 | s32 current_user; | 351 | s32 current_user; |
| 118 | s32 language_index; | 352 | s32 language_index; |
| 119 | 353 | ||
| 120 | // Controls | 354 | // Controls |
| 121 | std::array<std::string, NativeButton::NumButtons> buttons; | 355 | std::array<PlayerInput, 10> players; |
| 122 | std::array<std::string, NativeAnalog::NumAnalogs> analogs; | 356 | |
| 357 | bool mouse_enabled; | ||
| 358 | std::string mouse_device; | ||
| 359 | MouseButtonsRaw mouse_buttons; | ||
| 360 | |||
| 361 | bool keyboard_enabled; | ||
| 362 | KeyboardKeysRaw keyboard_keys; | ||
| 363 | KeyboardModsRaw keyboard_mods; | ||
| 364 | |||
| 365 | bool debug_pad_enabled; | ||
| 366 | ButtonsRaw debug_pad_buttons; | ||
| 367 | AnalogsRaw debug_pad_analogs; | ||
| 368 | |||
| 123 | std::string motion_device; | 369 | std::string motion_device; |
| 124 | std::string touch_device; | 370 | TouchscreenInput touchscreen; |
| 125 | std::atomic_bool is_device_reload_pending{true}; | 371 | std::atomic_bool is_device_reload_pending{true}; |
| 126 | 372 | ||
| 127 | // Core | 373 | // Core |
| @@ -157,6 +403,8 @@ struct Values { | |||
| 157 | bool use_gdbstub; | 403 | bool use_gdbstub; |
| 158 | u16 gdbstub_port; | 404 | u16 gdbstub_port; |
| 159 | std::string program_args; | 405 | std::string program_args; |
| 406 | bool dump_exefs; | ||
| 407 | bool dump_nso; | ||
| 160 | 408 | ||
| 161 | // WebService | 409 | // WebService |
| 162 | bool enable_telemetry; | 410 | bool enable_telemetry; |