diff options
| author | 2021-01-10 22:09:56 -0700 | |
|---|---|---|
| committer | 2021-01-10 22:09:56 -0700 | |
| commit | 7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch) | |
| tree | 5056f9406dec188439cb0deb87603498243a9412 /src/core | |
| parent | More forgetting... duh (diff) | |
| parent | Merge pull request #5229 from Morph1984/fullscreen-opt (diff) | |
| download | yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip | |
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/core')
408 files changed, 10451 insertions, 8483 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d0c405ec7..893df433a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,9 +1,3 @@ | |||
| 1 | if (YUZU_ENABLE_BOXCAT) | ||
| 2 | set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h) | ||
| 3 | else() | ||
| 4 | set(BCAT_BOXCAT_ADDITIONAL_SOURCES) | ||
| 5 | endif() | ||
| 6 | |||
| 7 | add_library(core STATIC | 1 | add_library(core STATIC |
| 8 | arm/arm_interface.h | 2 | arm/arm_interface.h |
| 9 | arm/arm_interface.cpp | 3 | arm/arm_interface.cpp |
| @@ -19,8 +13,6 @@ add_library(core STATIC | |||
| 19 | arm/dynarmic/arm_exclusive_monitor.h | 13 | arm/dynarmic/arm_exclusive_monitor.h |
| 20 | arm/exclusive_monitor.cpp | 14 | arm/exclusive_monitor.cpp |
| 21 | arm/exclusive_monitor.h | 15 | arm/exclusive_monitor.h |
| 22 | arm/unicorn/arm_unicorn.cpp | ||
| 23 | arm/unicorn/arm_unicorn.h | ||
| 24 | constants.cpp | 16 | constants.cpp |
| 25 | constants.h | 17 | constants.h |
| 26 | core.cpp | 18 | core.cpp |
| @@ -49,6 +41,7 @@ add_library(core STATIC | |||
| 49 | file_sys/bis_factory.h | 41 | file_sys/bis_factory.h |
| 50 | file_sys/card_image.cpp | 42 | file_sys/card_image.cpp |
| 51 | file_sys/card_image.h | 43 | file_sys/card_image.h |
| 44 | file_sys/common_funcs.h | ||
| 52 | file_sys/content_archive.cpp | 45 | file_sys/content_archive.cpp |
| 53 | file_sys/content_archive.h | 46 | file_sys/content_archive.h |
| 54 | file_sys/control_metadata.cpp | 47 | file_sys/control_metadata.cpp |
| @@ -142,9 +135,9 @@ add_library(core STATIC | |||
| 142 | frontend/emu_window.h | 135 | frontend/emu_window.h |
| 143 | frontend/framebuffer_layout.cpp | 136 | frontend/framebuffer_layout.cpp |
| 144 | frontend/framebuffer_layout.h | 137 | frontend/framebuffer_layout.h |
| 138 | frontend/input_interpreter.cpp | ||
| 139 | frontend/input_interpreter.h | ||
| 145 | frontend/input.h | 140 | frontend/input.h |
| 146 | gdbstub/gdbstub.cpp | ||
| 147 | gdbstub/gdbstub.h | ||
| 148 | hardware_interrupt_manager.cpp | 141 | hardware_interrupt_manager.cpp |
| 149 | hardware_interrupt_manager.h | 142 | hardware_interrupt_manager.h |
| 150 | hle/ipc.h | 143 | hle/ipc.h |
| @@ -158,10 +151,19 @@ add_library(core STATIC | |||
| 158 | hle/kernel/code_set.cpp | 151 | hle/kernel/code_set.cpp |
| 159 | hle/kernel/code_set.h | 152 | hle/kernel/code_set.h |
| 160 | hle/kernel/errors.h | 153 | hle/kernel/errors.h |
| 154 | hle/kernel/global_scheduler_context.cpp | ||
| 155 | hle/kernel/global_scheduler_context.h | ||
| 161 | hle/kernel/handle_table.cpp | 156 | hle/kernel/handle_table.cpp |
| 162 | hle/kernel/handle_table.h | 157 | hle/kernel/handle_table.h |
| 163 | hle/kernel/hle_ipc.cpp | 158 | hle/kernel/hle_ipc.cpp |
| 164 | hle/kernel/hle_ipc.h | 159 | hle/kernel/hle_ipc.h |
| 160 | hle/kernel/k_affinity_mask.h | ||
| 161 | hle/kernel/k_priority_queue.h | ||
| 162 | hle/kernel/k_scheduler.cpp | ||
| 163 | hle/kernel/k_scheduler.h | ||
| 164 | hle/kernel/k_scheduler_lock.h | ||
| 165 | hle/kernel/k_scoped_lock.h | ||
| 166 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h | ||
| 165 | hle/kernel/kernel.cpp | 167 | hle/kernel/kernel.cpp |
| 166 | hle/kernel/kernel.h | 168 | hle/kernel/kernel.h |
| 167 | hle/kernel/memory/address_space_info.cpp | 169 | hle/kernel/memory/address_space_info.cpp |
| @@ -196,12 +198,12 @@ add_library(core STATIC | |||
| 196 | hle/kernel/readable_event.h | 198 | hle/kernel/readable_event.h |
| 197 | hle/kernel/resource_limit.cpp | 199 | hle/kernel/resource_limit.cpp |
| 198 | hle/kernel/resource_limit.h | 200 | hle/kernel/resource_limit.h |
| 199 | hle/kernel/scheduler.cpp | ||
| 200 | hle/kernel/scheduler.h | ||
| 201 | hle/kernel/server_port.cpp | 201 | hle/kernel/server_port.cpp |
| 202 | hle/kernel/server_port.h | 202 | hle/kernel/server_port.h |
| 203 | hle/kernel/server_session.cpp | 203 | hle/kernel/server_session.cpp |
| 204 | hle/kernel/server_session.h | 204 | hle/kernel/server_session.h |
| 205 | hle/kernel/service_thread.cpp | ||
| 206 | hle/kernel/service_thread.h | ||
| 205 | hle/kernel/session.cpp | 207 | hle/kernel/session.cpp |
| 206 | hle/kernel/session.h | 208 | hle/kernel/session.h |
| 207 | hle/kernel/shared_memory.cpp | 209 | hle/kernel/shared_memory.cpp |
| @@ -303,7 +305,6 @@ add_library(core STATIC | |||
| 303 | hle/service/audio/hwopus.h | 305 | hle/service/audio/hwopus.h |
| 304 | hle/service/bcat/backend/backend.cpp | 306 | hle/service/bcat/backend/backend.cpp |
| 305 | hle/service/bcat/backend/backend.h | 307 | hle/service/bcat/backend/backend.h |
| 306 | ${BCAT_BOXCAT_ADDITIONAL_SOURCES} | ||
| 307 | hle/service/bcat/bcat.cpp | 308 | hle/service/bcat/bcat.cpp |
| 308 | hle/service/bcat/bcat.h | 309 | hle/service/bcat/bcat.h |
| 309 | hle/service/bcat/module.cpp | 310 | hle/service/bcat/module.cpp |
| @@ -446,6 +447,8 @@ add_library(core STATIC | |||
| 446 | hle/service/nvdrv/devices/nvhost_gpu.h | 447 | hle/service/nvdrv/devices/nvhost_gpu.h |
| 447 | hle/service/nvdrv/devices/nvhost_nvdec.cpp | 448 | hle/service/nvdrv/devices/nvhost_nvdec.cpp |
| 448 | hle/service/nvdrv/devices/nvhost_nvdec.h | 449 | hle/service/nvdrv/devices/nvhost_nvdec.h |
| 450 | hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | ||
| 451 | hle/service/nvdrv/devices/nvhost_nvdec_common.h | ||
| 449 | hle/service/nvdrv/devices/nvhost_nvjpg.cpp | 452 | hle/service/nvdrv/devices/nvhost_nvjpg.cpp |
| 450 | hle/service/nvdrv/devices/nvhost_nvjpg.h | 453 | hle/service/nvdrv/devices/nvhost_nvjpg.h |
| 451 | hle/service/nvdrv/devices/nvhost_vic.cpp | 454 | hle/service/nvdrv/devices/nvhost_vic.cpp |
| @@ -459,10 +462,14 @@ add_library(core STATIC | |||
| 459 | hle/service/nvdrv/nvdrv.h | 462 | hle/service/nvdrv/nvdrv.h |
| 460 | hle/service/nvdrv/nvmemp.cpp | 463 | hle/service/nvdrv/nvmemp.cpp |
| 461 | hle/service/nvdrv/nvmemp.h | 464 | hle/service/nvdrv/nvmemp.h |
| 465 | hle/service/nvdrv/syncpoint_manager.cpp | ||
| 466 | hle/service/nvdrv/syncpoint_manager.h | ||
| 462 | hle/service/nvflinger/buffer_queue.cpp | 467 | hle/service/nvflinger/buffer_queue.cpp |
| 463 | hle/service/nvflinger/buffer_queue.h | 468 | hle/service/nvflinger/buffer_queue.h |
| 464 | hle/service/nvflinger/nvflinger.cpp | 469 | hle/service/nvflinger/nvflinger.cpp |
| 465 | hle/service/nvflinger/nvflinger.h | 470 | hle/service/nvflinger/nvflinger.h |
| 471 | hle/service/olsc/olsc.cpp | ||
| 472 | hle/service/olsc/olsc.h | ||
| 466 | hle/service/pcie/pcie.cpp | 473 | hle/service/pcie/pcie.cpp |
| 467 | hle/service/pcie/pcie.h | 474 | hle/service/pcie/pcie.h |
| 468 | hle/service/pctl/module.cpp | 475 | hle/service/pctl/module.cpp |
| @@ -495,7 +502,6 @@ add_library(core STATIC | |||
| 495 | hle/service/sm/controller.h | 502 | hle/service/sm/controller.h |
| 496 | hle/service/sm/sm.cpp | 503 | hle/service/sm/sm.cpp |
| 497 | hle/service/sm/sm.h | 504 | hle/service/sm/sm.h |
| 498 | hle/service/sockets/blocking_worker.h | ||
| 499 | hle/service/sockets/bsd.cpp | 505 | hle/service/sockets/bsd.cpp |
| 500 | hle/service/sockets/bsd.h | 506 | hle/service/sockets/bsd.h |
| 501 | hle/service/sockets/ethc.cpp | 507 | hle/service/sockets/ethc.cpp |
| @@ -608,6 +614,13 @@ add_library(core STATIC | |||
| 608 | tools/freezer.h | 614 | tools/freezer.h |
| 609 | ) | 615 | ) |
| 610 | 616 | ||
| 617 | if (YUZU_ENABLE_BOXCAT) | ||
| 618 | target_sources(core PRIVATE | ||
| 619 | hle/service/bcat/backend/boxcat.cpp | ||
| 620 | hle/service/bcat/backend/boxcat.h | ||
| 621 | ) | ||
| 622 | endif() | ||
| 623 | |||
| 611 | if (MSVC) | 624 | if (MSVC) |
| 612 | target_compile_options(core PRIVATE | 625 | target_compile_options(core PRIVATE |
| 613 | # 'expression' : signed/unsigned mismatch | 626 | # 'expression' : signed/unsigned mismatch |
| @@ -622,13 +635,29 @@ if (MSVC) | |||
| 622 | /we4267 | 635 | /we4267 |
| 623 | # 'context' : truncation from 'type1' to 'type2' | 636 | # 'context' : truncation from 'type1' to 'type2' |
| 624 | /we4305 | 637 | /we4305 |
| 638 | # 'function' : not all control paths return a value | ||
| 639 | /we4715 | ||
| 640 | ) | ||
| 641 | else() | ||
| 642 | target_compile_options(core PRIVATE | ||
| 643 | -Werror=conversion | ||
| 644 | -Werror=ignored-qualifiers | ||
| 645 | -Werror=implicit-fallthrough | ||
| 646 | -Werror=reorder | ||
| 647 | -Werror=sign-compare | ||
| 648 | -Werror=unused-variable | ||
| 649 | |||
| 650 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> | ||
| 651 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | ||
| 652 | |||
| 653 | -Wno-sign-conversion | ||
| 625 | ) | 654 | ) |
| 626 | endif() | 655 | endif() |
| 627 | 656 | ||
| 628 | create_target_directory_groups(core) | 657 | create_target_directory_groups(core) |
| 629 | 658 | ||
| 630 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 659 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 631 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip) | 660 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip) |
| 632 | 661 | ||
| 633 | if (YUZU_ENABLE_BOXCAT) | 662 | if (YUZU_ENABLE_BOXCAT) |
| 634 | target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) | 663 | target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) |
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index d2295ed90..0951e1976 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex | |||
| 147 | auto fp = ctx.cpu_registers[29]; | 147 | auto fp = ctx.cpu_registers[29]; |
| 148 | auto lr = ctx.cpu_registers[30]; | 148 | auto lr = ctx.cpu_registers[30]; |
| 149 | while (true) { | 149 | while (true) { |
| 150 | out.push_back({"", 0, lr, 0}); | 150 | out.push_back({ |
| 151 | if (!fp) { | 151 | .module = "", |
| 152 | .address = 0, | ||
| 153 | .original_address = lr, | ||
| 154 | .offset = 0, | ||
| 155 | .name = {}, | ||
| 156 | }); | ||
| 157 | |||
| 158 | if (fp == 0) { | ||
| 152 | break; | 159 | break; |
| 153 | } | 160 | } |
| 161 | |||
| 154 | lr = memory.Read64(fp + 8) - 4; | 162 | lr = memory.Read64(fp + 8) - 4; |
| 155 | fp = memory.Read64(fp); | 163 | fp = memory.Read64(fp); |
| 156 | } | 164 | } |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 1f24051e4..70098c526 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -64,15 +64,25 @@ public: | |||
| 64 | /// Step CPU by one instruction | 64 | /// Step CPU by one instruction |
| 65 | virtual void Step() = 0; | 65 | virtual void Step() = 0; |
| 66 | 66 | ||
| 67 | /// Exits execution from a callback, the callback must rewind the stack | ||
| 68 | virtual void ExceptionalExit() = 0; | ||
| 69 | |||
| 67 | /// Clear all instruction cache | 70 | /// Clear all instruction cache |
| 68 | virtual void ClearInstructionCache() = 0; | 71 | virtual void ClearInstructionCache() = 0; |
| 69 | 72 | ||
| 70 | /// Notifies CPU emulation that the current page table has changed. | 73 | /** |
| 71 | /// | 74 | * Clear instruction cache range |
| 72 | /// @param new_page_table The new page table. | 75 | * @param addr Start address of the cache range to clear |
| 73 | /// @param new_address_space_size_in_bits The new usable size of the address space in bits. | 76 | * @param size Size of the cache range to clear, starting at addr |
| 74 | /// This can be either 32, 36, or 39 on official software. | 77 | */ |
| 75 | /// | 78 | virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0; |
| 79 | |||
| 80 | /** | ||
| 81 | * Notifies CPU emulation that the current page table has changed. | ||
| 82 | * @param new_page_table The new page table. | ||
| 83 | * @param new_address_space_size_in_bits The new usable size of the address space in bits. | ||
| 84 | * This can be either 32, 36, or 39 on official software. | ||
| 85 | */ | ||
| 76 | virtual void PageTableChanged(Common::PageTable& new_page_table, | 86 | virtual void PageTableChanged(Common::PageTable& new_page_table, |
| 77 | std::size_t new_address_space_size_in_bits) = 0; | 87 | std::size_t new_address_space_size_in_bits) = 0; |
| 78 | 88 | ||
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h index 71e582f79..c20c280f1 100644 --- a/src/core/arm/cpu_interrupt_handler.h +++ b/src/core/arm/cpu_interrupt_handler.h | |||
| @@ -21,8 +21,8 @@ public: | |||
| 21 | CPUInterruptHandler(const CPUInterruptHandler&) = delete; | 21 | CPUInterruptHandler(const CPUInterruptHandler&) = delete; |
| 22 | CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete; | 22 | CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete; |
| 23 | 23 | ||
| 24 | CPUInterruptHandler(CPUInterruptHandler&&) = default; | 24 | CPUInterruptHandler(CPUInterruptHandler&&) = delete; |
| 25 | CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; | 25 | CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete; |
| 26 | 26 | ||
| 27 | bool IsInterrupted() const { | 27 | bool IsInterrupted() const { |
| 28 | return is_interrupted; | 28 | return is_interrupted; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index b5f28a86e..6c4c8e9e4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <dynarmic/A32/a32.h> | 7 | #include <dynarmic/A32/a32.h> |
| 8 | #include <dynarmic/A32/config.h> | 8 | #include <dynarmic/A32/config.h> |
| 9 | #include <dynarmic/A32/context.h> | 9 | #include <dynarmic/A32/context.h> |
| 10 | #include "common/assert.h" | ||
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 11 | #include "common/page_table.h" | 12 | #include "common/page_table.h" |
| 12 | #include "core/arm/cpu_interrupt_handler.h" | 13 | #include "core/arm/cpu_interrupt_handler.h" |
| @@ -70,15 +71,8 @@ public: | |||
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 73 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 73 | switch (exception) { | ||
| 74 | case Dynarmic::A32::Exception::UndefinedInstruction: | ||
| 75 | case Dynarmic::A32::Exception::UnpredictableInstruction: | ||
| 76 | break; | ||
| 77 | case Dynarmic::A32::Exception::Breakpoint: | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", | 74 | LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", |
| 81 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); | 75 | exception, pc, MemoryReadCode(pc)); |
| 82 | UNIMPLEMENTED(); | 76 | UNIMPLEMENTED(); |
| 83 | } | 77 | } |
| 84 | 78 | ||
| @@ -132,6 +126,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& | |||
| 132 | config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( | 126 | config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( |
| 133 | page_table.pointers.data()); | 127 | page_table.pointers.data()); |
| 134 | config.absolute_offset_page_table = true; | 128 | config.absolute_offset_page_table = true; |
| 129 | config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; | ||
| 135 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; | 130 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; |
| 136 | config.only_detect_misalignment_via_page_table_on_page_boundary = true; | 131 | config.only_detect_misalignment_via_page_table_on_page_boundary = true; |
| 137 | 132 | ||
| @@ -179,6 +174,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& | |||
| 179 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { | 174 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { |
| 180 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; | 175 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; |
| 181 | } | 176 | } |
| 177 | if (Settings::values.cpuopt_unsafe_inaccurate_nan) { | ||
| 178 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; | ||
| 179 | } | ||
| 182 | } | 180 | } |
| 183 | 181 | ||
| 184 | return std::make_unique<Dynarmic::A32::Jit>(config); | 182 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| @@ -188,6 +186,10 @@ void ARM_Dynarmic_32::Run() { | |||
| 188 | jit->Run(); | 186 | jit->Run(); |
| 189 | } | 187 | } |
| 190 | 188 | ||
| 189 | void ARM_Dynarmic_32::ExceptionalExit() { | ||
| 190 | jit->ExceptionalExit(); | ||
| 191 | } | ||
| 192 | |||
| 191 | void ARM_Dynarmic_32::Step() { | 193 | void ARM_Dynarmic_32::Step() { |
| 192 | jit->Step(); | 194 | jit->Step(); |
| 193 | } | 195 | } |
| @@ -281,7 +283,17 @@ void ARM_Dynarmic_32::ClearInstructionCache() { | |||
| 281 | jit->ClearCache(); | 283 | jit->ClearCache(); |
| 282 | } | 284 | } |
| 283 | 285 | ||
| 286 | void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) { | ||
| 287 | if (!jit) { | ||
| 288 | return; | ||
| 289 | } | ||
| 290 | jit->InvalidateCacheRange(static_cast<u32>(addr), size); | ||
| 291 | } | ||
| 292 | |||
| 284 | void ARM_Dynarmic_32::ClearExclusiveState() { | 293 | void ARM_Dynarmic_32::ClearExclusiveState() { |
| 294 | if (!jit) { | ||
| 295 | return; | ||
| 296 | } | ||
| 285 | jit->ClearExclusiveState(); | 297 | jit->ClearExclusiveState(); |
| 286 | } | 298 | } |
| 287 | 299 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 2bab31b92..35e9ced48 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -42,6 +42,7 @@ public: | |||
| 42 | u32 GetPSTATE() const override; | 42 | u32 GetPSTATE() const override; |
| 43 | void SetPSTATE(u32 pstate) override; | 43 | void SetPSTATE(u32 pstate) override; |
| 44 | void Run() override; | 44 | void Run() override; |
| 45 | void ExceptionalExit() override; | ||
| 45 | void Step() override; | 46 | void Step() override; |
| 46 | VAddr GetTlsAddress() const override; | 47 | VAddr GetTlsAddress() const override; |
| 47 | void SetTlsAddress(VAddr address) override; | 48 | void SetTlsAddress(VAddr address) override; |
| @@ -58,6 +59,7 @@ public: | |||
| 58 | void ClearExclusiveState() override; | 59 | void ClearExclusiveState() override; |
| 59 | 60 | ||
| 60 | void ClearInstructionCache() override; | 61 | void ClearInstructionCache() override; |
| 62 | void InvalidateCacheRange(VAddr addr, std::size_t size) override; | ||
| 61 | void PageTableChanged(Common::PageTable& new_page_table, | 63 | void PageTableChanged(Common::PageTable& new_page_table, |
| 62 | std::size_t new_address_space_size_in_bits) override; | 64 | std::size_t new_address_space_size_in_bits) override; |
| 63 | 65 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index ce9968724..4c5ebca22 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <dynarmic/A64/a64.h> | 7 | #include <dynarmic/A64/a64.h> |
| 8 | #include <dynarmic/A64/config.h> | 8 | #include <dynarmic/A64/config.h> |
| 9 | #include "common/assert.h" | ||
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "common/page_table.h" | 11 | #include "common/page_table.h" |
| 11 | #include "core/arm/cpu_interrupt_handler.h" | 12 | #include "core/arm/cpu_interrupt_handler.h" |
| @@ -13,11 +14,9 @@ | |||
| 13 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" | 14 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" |
| 14 | #include "core/core.h" | 15 | #include "core/core.h" |
| 15 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 16 | #include "core/core_timing_util.h" | ||
| 17 | #include "core/gdbstub/gdbstub.h" | ||
| 18 | #include "core/hardware_properties.h" | 17 | #include "core/hardware_properties.h" |
| 18 | #include "core/hle/kernel/k_scheduler.h" | ||
| 19 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/scheduler.h" | ||
| 21 | #include "core/hle/kernel/svc.h" | 20 | #include "core/hle/kernel/svc.h" |
| 22 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| 23 | #include "core/settings.h" | 22 | #include "core/settings.h" |
| @@ -82,16 +81,9 @@ public: | |||
| 82 | } | 81 | } |
| 83 | 82 | ||
| 84 | void InterpreterFallback(u64 pc, std::size_t num_instructions) override { | 83 | void InterpreterFallback(u64 pc, std::size_t num_instructions) override { |
| 85 | LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, | 84 | LOG_ERROR(Core_ARM, |
| 86 | num_instructions, MemoryReadCode(pc)); | 85 | "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, |
| 87 | 86 | num_instructions, MemoryReadCode(pc)); | |
| 88 | ARM_Interface::ThreadContext64 ctx; | ||
| 89 | parent.SaveContext(ctx); | ||
| 90 | parent.inner_unicorn.LoadContext(ctx); | ||
| 91 | parent.inner_unicorn.ExecuteInstructions(num_instructions); | ||
| 92 | parent.inner_unicorn.SaveContext(ctx); | ||
| 93 | parent.LoadContext(ctx); | ||
| 94 | num_interpreted_instructions += num_instructions; | ||
| 95 | } | 87 | } |
| 96 | 88 | ||
| 97 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { | 89 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { |
| @@ -103,16 +95,6 @@ public: | |||
| 103 | case Dynarmic::A64::Exception::Yield: | 95 | case Dynarmic::A64::Exception::Yield: |
| 104 | return; | 96 | return; |
| 105 | case Dynarmic::A64::Exception::Breakpoint: | 97 | case Dynarmic::A64::Exception::Breakpoint: |
| 106 | if (GDBStub::IsServerEnabled()) { | ||
| 107 | parent.jit->HaltExecution(); | ||
| 108 | parent.SetPC(pc); | ||
| 109 | Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); | ||
| 110 | parent.SaveContext(thread->GetContext64()); | ||
| 111 | GDBStub::Break(); | ||
| 112 | GDBStub::SendTrap(thread, 5); | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | [[fallthrough]]; | ||
| 116 | default: | 98 | default: |
| 117 | ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", | 99 | ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", |
| 118 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); | 100 | static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); |
| @@ -127,18 +109,17 @@ public: | |||
| 127 | if (parent.uses_wall_clock) { | 109 | if (parent.uses_wall_clock) { |
| 128 | return; | 110 | return; |
| 129 | } | 111 | } |
| 112 | |||
| 130 | // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a | 113 | // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a |
| 131 | // rough approximation of the amount of executed ticks in the system, it may be thrown off | 114 | // rough approximation of the amount of executed ticks in the system, it may be thrown off |
| 132 | // if not all cores are doing a similar amount of work. Instead of doing this, we should | 115 | // if not all cores are doing a similar amount of work. Instead of doing this, we should |
| 133 | // device a way so that timing is consistent across all cores without increasing the ticks 4 | 116 | // device a way so that timing is consistent across all cores without increasing the ticks 4 |
| 134 | // times. | 117 | // times. |
| 135 | u64 amortized_ticks = | 118 | u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES; |
| 136 | (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES; | ||
| 137 | // Always execute at least one tick. | 119 | // Always execute at least one tick. |
| 138 | amortized_ticks = std::max<u64>(amortized_ticks, 1); | 120 | amortized_ticks = std::max<u64>(amortized_ticks, 1); |
| 139 | 121 | ||
| 140 | parent.system.CoreTiming().AddTicks(amortized_ticks); | 122 | parent.system.CoreTiming().AddTicks(amortized_ticks); |
| 141 | num_interpreted_instructions = 0; | ||
| 142 | } | 123 | } |
| 143 | 124 | ||
| 144 | u64 GetTicksRemaining() override { | 125 | u64 GetTicksRemaining() override { |
| @@ -156,7 +137,6 @@ public: | |||
| 156 | } | 137 | } |
| 157 | 138 | ||
| 158 | ARM_Dynarmic_64& parent; | 139 | ARM_Dynarmic_64& parent; |
| 159 | std::size_t num_interpreted_instructions = 0; | ||
| 160 | u64 tpidrro_el0 = 0; | 140 | u64 tpidrro_el0 = 0; |
| 161 | u64 tpidr_el0 = 0; | 141 | u64 tpidr_el0 = 0; |
| 162 | static constexpr u64 minimum_run_cycles = 1000U; | 142 | static constexpr u64 minimum_run_cycles = 1000U; |
| @@ -172,6 +152,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& | |||
| 172 | // Memory | 152 | // Memory |
| 173 | config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); | 153 | config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); |
| 174 | config.page_table_address_space_bits = address_space_bits; | 154 | config.page_table_address_space_bits = address_space_bits; |
| 155 | config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; | ||
| 175 | config.silently_mirror_page_table = false; | 156 | config.silently_mirror_page_table = false; |
| 176 | config.absolute_offset_page_table = true; | 157 | config.absolute_offset_page_table = true; |
| 177 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; | 158 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; |
| @@ -231,6 +212,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& | |||
| 231 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { | 212 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { |
| 232 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; | 213 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; |
| 233 | } | 214 | } |
| 215 | if (Settings::values.cpuopt_unsafe_inaccurate_nan) { | ||
| 216 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; | ||
| 217 | } | ||
| 234 | } | 218 | } |
| 235 | 219 | ||
| 236 | return std::make_shared<Dynarmic::A64::Jit>(config); | 220 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| @@ -240,6 +224,10 @@ void ARM_Dynarmic_64::Run() { | |||
| 240 | jit->Run(); | 224 | jit->Run(); |
| 241 | } | 225 | } |
| 242 | 226 | ||
| 227 | void ARM_Dynarmic_64::ExceptionalExit() { | ||
| 228 | jit->ExceptionalExit(); | ||
| 229 | } | ||
| 230 | |||
| 243 | void ARM_Dynarmic_64::Step() { | 231 | void ARM_Dynarmic_64::Step() { |
| 244 | cb->InterpreterFallback(jit->GetPC(), 1); | 232 | cb->InterpreterFallback(jit->GetPC(), 1); |
| 245 | } | 233 | } |
| @@ -248,12 +236,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle | |||
| 248 | bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, | 236 | bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, |
| 249 | std::size_t core_index) | 237 | std::size_t core_index) |
| 250 | : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, | 238 | : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, |
| 251 | cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers, | 239 | cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index}, |
| 252 | uses_wall_clock, | 240 | exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} |
| 253 | ARM_Unicorn::Arch::AArch64, | ||
| 254 | core_index}, | ||
| 255 | core_index{core_index}, exclusive_monitor{ | ||
| 256 | dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} | ||
| 257 | 241 | ||
| 258 | ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; | 242 | ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; |
| 259 | 243 | ||
| @@ -342,7 +326,17 @@ void ARM_Dynarmic_64::ClearInstructionCache() { | |||
| 342 | jit->ClearCache(); | 326 | jit->ClearCache(); |
| 343 | } | 327 | } |
| 344 | 328 | ||
| 329 | void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) { | ||
| 330 | if (!jit) { | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | jit->InvalidateCacheRange(addr, size); | ||
| 334 | } | ||
| 335 | |||
| 345 | void ARM_Dynarmic_64::ClearExclusiveState() { | 336 | void ARM_Dynarmic_64::ClearExclusiveState() { |
| 337 | if (!jit) { | ||
| 338 | return; | ||
| 339 | } | ||
| 346 | jit->ClearExclusiveState(); | 340 | jit->ClearExclusiveState(); |
| 347 | } | 341 | } |
| 348 | 342 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 403c55961..329b59a32 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include "common/hash.h" | 12 | #include "common/hash.h" |
| 13 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 14 | #include "core/arm/exclusive_monitor.h" | 14 | #include "core/arm/exclusive_monitor.h" |
| 15 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 16 | 15 | ||
| 17 | namespace Core::Memory { | 16 | namespace Core::Memory { |
| 18 | class Memory; | 17 | class Memory; |
| @@ -41,6 +40,7 @@ public: | |||
| 41 | void SetPSTATE(u32 pstate) override; | 40 | void SetPSTATE(u32 pstate) override; |
| 42 | void Run() override; | 41 | void Run() override; |
| 43 | void Step() override; | 42 | void Step() override; |
| 43 | void ExceptionalExit() override; | ||
| 44 | VAddr GetTlsAddress() const override; | 44 | VAddr GetTlsAddress() const override; |
| 45 | void SetTlsAddress(VAddr address) override; | 45 | void SetTlsAddress(VAddr address) override; |
| 46 | void SetTPIDR_EL0(u64 value) override; | 46 | void SetTPIDR_EL0(u64 value) override; |
| @@ -56,6 +56,7 @@ public: | |||
| 56 | void ClearExclusiveState() override; | 56 | void ClearExclusiveState() override; |
| 57 | 57 | ||
| 58 | void ClearInstructionCache() override; | 58 | void ClearInstructionCache() override; |
| 59 | void InvalidateCacheRange(VAddr addr, std::size_t size) override; | ||
| 59 | void PageTableChanged(Common::PageTable& new_page_table, | 60 | void PageTableChanged(Common::PageTable& new_page_table, |
| 60 | std::size_t new_address_space_size_in_bits) override; | 61 | std::size_t new_address_space_size_in_bits) override; |
| 61 | 62 | ||
| @@ -71,7 +72,6 @@ private: | |||
| 71 | std::unique_ptr<DynarmicCallbacks64> cb; | 72 | std::unique_ptr<DynarmicCallbacks64> cb; |
| 72 | JitCacheType jit_cache; | 73 | JitCacheType jit_cache; |
| 73 | std::shared_ptr<Dynarmic::A64::Jit> jit; | 74 | std::shared_ptr<Dynarmic::A64::Jit> jit; |
| 74 | ARM_Unicorn inner_unicorn; | ||
| 75 | 75 | ||
| 76 | std::size_t core_index; | 76 | std::size_t core_index; |
| 77 | DynarmicExclusiveMonitor& exclusive_monitor; | 77 | DynarmicExclusiveMonitor& exclusive_monitor; |
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp deleted file mode 100644 index 1df3f3ed1..000000000 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ /dev/null | |||
| @@ -1,295 +0,0 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <unicorn/arm64.h> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/microprofile.h" | ||
| 9 | #include "core/arm/cpu_interrupt_handler.h" | ||
| 10 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "core/core_timing.h" | ||
| 13 | #include "core/hle/kernel/scheduler.h" | ||
| 14 | #include "core/hle/kernel/svc.h" | ||
| 15 | #include "core/memory.h" | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | |||
| 19 | // Load Unicorn DLL once on Windows using RAII | ||
| 20 | #ifdef _MSC_VER | ||
| 21 | #include <unicorn_dynload.h> | ||
| 22 | struct LoadDll { | ||
| 23 | private: | ||
| 24 | LoadDll() { | ||
| 25 | ASSERT(uc_dyn_load(NULL, 0)); | ||
| 26 | } | ||
| 27 | ~LoadDll() { | ||
| 28 | ASSERT(uc_dyn_free()); | ||
| 29 | } | ||
| 30 | static LoadDll g_load_dll; | ||
| 31 | }; | ||
| 32 | LoadDll LoadDll::g_load_dll; | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #define CHECKED(expr) \ | ||
| 36 | do { \ | ||
| 37 | if (auto _cerr = (expr)) { \ | ||
| 38 | ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \ | ||
| 39 | uc_strerror(_cerr)); \ | ||
| 40 | } \ | ||
| 41 | } while (0) | ||
| 42 | |||
| 43 | static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { | ||
| 44 | GDBStub::BreakpointAddress bkpt = | ||
| 45 | GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); | ||
| 46 | if (GDBStub::IsMemoryBreak() || | ||
| 47 | (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { | ||
| 48 | auto core = static_cast<ARM_Unicorn*>(user_data); | ||
| 49 | core->RecordBreak(bkpt); | ||
| 50 | uc_emu_stop(uc); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value, | ||
| 55 | void* user_data) { | ||
| 56 | auto* const system = static_cast<System*>(user_data); | ||
| 57 | |||
| 58 | ARM_Interface::ThreadContext64 ctx{}; | ||
| 59 | system->CurrentArmInterface().SaveContext(ctx); | ||
| 60 | ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr, | ||
| 61 | ctx.pc, ctx.cpu_registers[30]); | ||
| 62 | |||
| 63 | return false; | ||
| 64 | } | ||
| 65 | |||
| 66 | ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, | ||
| 67 | Arch architecture, std::size_t core_index) | ||
| 68 | : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} { | ||
| 69 | const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; | ||
| 70 | CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); | ||
| 71 | |||
| 72 | auto fpv = 3 << 20; | ||
| 73 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv)); | ||
| 74 | |||
| 75 | uc_hook hook{}; | ||
| 76 | CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX)); | ||
| 77 | CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0, | ||
| 78 | UINT64_MAX)); | ||
| 79 | if (GDBStub::IsServerEnabled()) { | ||
| 80 | CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX)); | ||
| 81 | last_bkpt_hit = false; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | ARM_Unicorn::~ARM_Unicorn() { | ||
| 86 | CHECKED(uc_close(uc)); | ||
| 87 | } | ||
| 88 | |||
| 89 | void ARM_Unicorn::SetPC(u64 pc) { | ||
| 90 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc)); | ||
| 91 | } | ||
| 92 | |||
| 93 | u64 ARM_Unicorn::GetPC() const { | ||
| 94 | u64 val{}; | ||
| 95 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val)); | ||
| 96 | return val; | ||
| 97 | } | ||
| 98 | |||
| 99 | u64 ARM_Unicorn::GetReg(int regn) const { | ||
| 100 | u64 val{}; | ||
| 101 | auto treg = UC_ARM64_REG_SP; | ||
| 102 | if (regn <= 28) { | ||
| 103 | treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn); | ||
| 104 | } else if (regn < 31) { | ||
| 105 | treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29); | ||
| 106 | } | ||
| 107 | CHECKED(uc_reg_read(uc, treg, &val)); | ||
| 108 | return val; | ||
| 109 | } | ||
| 110 | |||
| 111 | void ARM_Unicorn::SetReg(int regn, u64 val) { | ||
| 112 | auto treg = UC_ARM64_REG_SP; | ||
| 113 | if (regn <= 28) { | ||
| 114 | treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn); | ||
| 115 | } else if (regn < 31) { | ||
| 116 | treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29); | ||
| 117 | } | ||
| 118 | CHECKED(uc_reg_write(uc, treg, &val)); | ||
| 119 | } | ||
| 120 | |||
| 121 | u128 ARM_Unicorn::GetVectorReg(int /*index*/) const { | ||
| 122 | UNIMPLEMENTED(); | ||
| 123 | static constexpr u128 res{}; | ||
| 124 | return res; | ||
| 125 | } | ||
| 126 | |||
| 127 | void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) { | ||
| 128 | UNIMPLEMENTED(); | ||
| 129 | } | ||
| 130 | |||
| 131 | u32 ARM_Unicorn::GetPSTATE() const { | ||
| 132 | u64 nzcv{}; | ||
| 133 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv)); | ||
| 134 | return static_cast<u32>(nzcv); | ||
| 135 | } | ||
| 136 | |||
| 137 | void ARM_Unicorn::SetPSTATE(u32 pstate) { | ||
| 138 | u64 nzcv = pstate; | ||
| 139 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv)); | ||
| 140 | } | ||
| 141 | |||
| 142 | VAddr ARM_Unicorn::GetTlsAddress() const { | ||
| 143 | u64 base{}; | ||
| 144 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base)); | ||
| 145 | return base; | ||
| 146 | } | ||
| 147 | |||
| 148 | void ARM_Unicorn::SetTlsAddress(VAddr base) { | ||
| 149 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base)); | ||
| 150 | } | ||
| 151 | |||
| 152 | u64 ARM_Unicorn::GetTPIDR_EL0() const { | ||
| 153 | u64 value{}; | ||
| 154 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value)); | ||
| 155 | return value; | ||
| 156 | } | ||
| 157 | |||
| 158 | void ARM_Unicorn::SetTPIDR_EL0(u64 value) { | ||
| 159 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); | ||
| 160 | } | ||
| 161 | |||
| 162 | void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) { | ||
| 163 | core_index = new_core_id; | ||
| 164 | } | ||
| 165 | |||
| 166 | void ARM_Unicorn::Run() { | ||
| 167 | if (GDBStub::IsServerEnabled()) { | ||
| 168 | ExecuteInstructions(std::max(4000000U, 0U)); | ||
| 169 | } else { | ||
| 170 | while (true) { | ||
| 171 | if (interrupt_handlers[core_index].IsInterrupted()) { | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | ExecuteInstructions(10); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | void ARM_Unicorn::Step() { | ||
| 180 | ExecuteInstructions(1); | ||
| 181 | } | ||
| 182 | |||
| 183 | MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64)); | ||
| 184 | |||
| 185 | void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { | ||
| 186 | MICROPROFILE_SCOPE(ARM_Jit_Unicorn); | ||
| 187 | |||
| 188 | // Temporarily map the code page for Unicorn | ||
| 189 | u64 map_addr{GetPC() & ~Memory::PAGE_MASK}; | ||
| 190 | std::vector<u8> page_buffer(Memory::PAGE_SIZE); | ||
| 191 | system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size()); | ||
| 192 | |||
| 193 | CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(), | ||
| 194 | UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data())); | ||
| 195 | CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); | ||
| 196 | CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size())); | ||
| 197 | if (GDBStub::IsServerEnabled()) { | ||
| 198 | if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) { | ||
| 199 | uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); | ||
| 200 | } | ||
| 201 | |||
| 202 | Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread(); | ||
| 203 | SaveContext(thread->GetContext64()); | ||
| 204 | if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { | ||
| 205 | last_bkpt_hit = false; | ||
| 206 | GDBStub::Break(); | ||
| 207 | GDBStub::SendTrap(thread, 5); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | void ARM_Unicorn::SaveContext(ThreadContext64& ctx) { | ||
| 213 | int uregs[32]; | ||
| 214 | void* tregs[32]; | ||
| 215 | |||
| 216 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp)); | ||
| 217 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc)); | ||
| 218 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); | ||
| 219 | |||
| 220 | for (auto i = 0; i < 29; ++i) { | ||
| 221 | uregs[i] = UC_ARM64_REG_X0 + i; | ||
| 222 | tregs[i] = &ctx.cpu_registers[i]; | ||
| 223 | } | ||
| 224 | uregs[29] = UC_ARM64_REG_X29; | ||
| 225 | tregs[29] = (void*)&ctx.cpu_registers[29]; | ||
| 226 | uregs[30] = UC_ARM64_REG_X30; | ||
| 227 | tregs[30] = (void*)&ctx.cpu_registers[30]; | ||
| 228 | |||
| 229 | CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31)); | ||
| 230 | |||
| 231 | for (int i = 0; i < 32; ++i) { | ||
| 232 | uregs[i] = UC_ARM64_REG_Q0 + i; | ||
| 233 | tregs[i] = &ctx.vector_registers[i]; | ||
| 234 | } | ||
| 235 | |||
| 236 | CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32)); | ||
| 237 | } | ||
| 238 | |||
| 239 | void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) { | ||
| 240 | int uregs[32]; | ||
| 241 | void* tregs[32]; | ||
| 242 | |||
| 243 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp)); | ||
| 244 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc)); | ||
| 245 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate)); | ||
| 246 | |||
| 247 | for (int i = 0; i < 29; ++i) { | ||
| 248 | uregs[i] = UC_ARM64_REG_X0 + i; | ||
| 249 | tregs[i] = (void*)&ctx.cpu_registers[i]; | ||
| 250 | } | ||
| 251 | uregs[29] = UC_ARM64_REG_X29; | ||
| 252 | tregs[29] = (void*)&ctx.cpu_registers[29]; | ||
| 253 | uregs[30] = UC_ARM64_REG_X30; | ||
| 254 | tregs[30] = (void*)&ctx.cpu_registers[30]; | ||
| 255 | |||
| 256 | CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31)); | ||
| 257 | |||
| 258 | for (auto i = 0; i < 32; ++i) { | ||
| 259 | uregs[i] = UC_ARM64_REG_Q0 + i; | ||
| 260 | tregs[i] = (void*)&ctx.vector_registers[i]; | ||
| 261 | } | ||
| 262 | |||
| 263 | CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32)); | ||
| 264 | } | ||
| 265 | |||
| 266 | void ARM_Unicorn::PrepareReschedule() { | ||
| 267 | CHECKED(uc_emu_stop(uc)); | ||
| 268 | } | ||
| 269 | |||
| 270 | void ARM_Unicorn::ClearExclusiveState() {} | ||
| 271 | |||
| 272 | void ARM_Unicorn::ClearInstructionCache() {} | ||
| 273 | |||
| 274 | void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) { | ||
| 275 | last_bkpt = bkpt; | ||
| 276 | last_bkpt_hit = true; | ||
| 277 | } | ||
| 278 | |||
| 279 | void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) { | ||
| 280 | u32 esr{}; | ||
| 281 | CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr)); | ||
| 282 | |||
| 283 | const auto ec = esr >> 26; | ||
| 284 | const auto iss = esr & 0xFFFFFF; | ||
| 285 | |||
| 286 | auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data); | ||
| 287 | |||
| 288 | switch (ec) { | ||
| 289 | case 0x15: // SVC | ||
| 290 | Kernel::Svc::Call(arm_instance->system, iss); | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | } // namespace Core | ||
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h deleted file mode 100644 index 810aff311..000000000 --- a/src/core/arm/unicorn/arm_unicorn.h +++ /dev/null | |||
| @@ -1,63 +0,0 @@ | |||
| 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 <unicorn/unicorn.h> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/arm/arm_interface.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | class System; | ||
| 15 | |||
| 16 | class ARM_Unicorn final : public ARM_Interface { | ||
| 17 | public: | ||
| 18 | enum class Arch { | ||
| 19 | AArch32, // 32-bit ARM | ||
| 20 | AArch64, // 64-bit ARM | ||
| 21 | }; | ||
| 22 | |||
| 23 | explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, | ||
| 24 | Arch architecture, std::size_t core_index); | ||
| 25 | ~ARM_Unicorn() override; | ||
| 26 | |||
| 27 | void SetPC(u64 pc) override; | ||
| 28 | u64 GetPC() const override; | ||
| 29 | u64 GetReg(int index) const override; | ||
| 30 | void SetReg(int index, u64 value) override; | ||
| 31 | u128 GetVectorReg(int index) const override; | ||
| 32 | void SetVectorReg(int index, u128 value) override; | ||
| 33 | u32 GetPSTATE() const override; | ||
| 34 | void SetPSTATE(u32 pstate) override; | ||
| 35 | VAddr GetTlsAddress() const override; | ||
| 36 | void SetTlsAddress(VAddr address) override; | ||
| 37 | void SetTPIDR_EL0(u64 value) override; | ||
| 38 | u64 GetTPIDR_EL0() const override; | ||
| 39 | void ChangeProcessorID(std::size_t new_core_id) override; | ||
| 40 | void PrepareReschedule() override; | ||
| 41 | void ClearExclusiveState() override; | ||
| 42 | void ExecuteInstructions(std::size_t num_instructions); | ||
| 43 | void Run() override; | ||
| 44 | void Step() override; | ||
| 45 | void ClearInstructionCache() override; | ||
| 46 | void PageTableChanged(Common::PageTable&, std::size_t) override {} | ||
| 47 | void RecordBreak(GDBStub::BreakpointAddress bkpt); | ||
| 48 | |||
| 49 | void SaveContext(ThreadContext32& ctx) override {} | ||
| 50 | void SaveContext(ThreadContext64& ctx) override; | ||
| 51 | void LoadContext(const ThreadContext32& ctx) override {} | ||
| 52 | void LoadContext(const ThreadContext64& ctx) override; | ||
| 53 | |||
| 54 | private: | ||
| 55 | static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data); | ||
| 56 | |||
| 57 | uc_engine* uc{}; | ||
| 58 | GDBStub::BreakpointAddress last_bkpt{}; | ||
| 59 | bool last_bkpt_hit = false; | ||
| 60 | std::size_t core_index; | ||
| 61 | }; | ||
| 62 | |||
| 63 | } // namespace Core | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index 81e8cc338..1a2002dec 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -25,13 +25,12 @@ | |||
| 25 | #include "core/file_sys/sdmc_factory.h" | 25 | #include "core/file_sys/sdmc_factory.h" |
| 26 | #include "core/file_sys/vfs_concat.h" | 26 | #include "core/file_sys/vfs_concat.h" |
| 27 | #include "core/file_sys/vfs_real.h" | 27 | #include "core/file_sys/vfs_real.h" |
| 28 | #include "core/gdbstub/gdbstub.h" | ||
| 29 | #include "core/hardware_interrupt_manager.h" | 28 | #include "core/hardware_interrupt_manager.h" |
| 30 | #include "core/hle/kernel/client_port.h" | 29 | #include "core/hle/kernel/client_port.h" |
| 30 | #include "core/hle/kernel/k_scheduler.h" | ||
| 31 | #include "core/hle/kernel/kernel.h" | 31 | #include "core/hle/kernel/kernel.h" |
| 32 | #include "core/hle/kernel/physical_core.h" | 32 | #include "core/hle/kernel/physical_core.h" |
| 33 | #include "core/hle/kernel/process.h" | 33 | #include "core/hle/kernel/process.h" |
| 34 | #include "core/hle/kernel/scheduler.h" | ||
| 35 | #include "core/hle/kernel/thread.h" | 34 | #include "core/hle/kernel/thread.h" |
| 36 | #include "core/hle/service/am/applets/applets.h" | 35 | #include "core/hle/service/am/applets/applets.h" |
| 37 | #include "core/hle/service/apm/controller.h" | 36 | #include "core/hle/service/apm/controller.h" |
| @@ -40,6 +39,7 @@ | |||
| 40 | #include "core/hle/service/lm/manager.h" | 39 | #include "core/hle/service/lm/manager.h" |
| 41 | #include "core/hle/service/service.h" | 40 | #include "core/hle/service/service.h" |
| 42 | #include "core/hle/service/sm/sm.h" | 41 | #include "core/hle/service/sm/sm.h" |
| 42 | #include "core/hle/service/time/time_manager.h" | ||
| 43 | #include "core/loader/loader.h" | 43 | #include "core/loader/loader.h" |
| 44 | #include "core/memory.h" | 44 | #include "core/memory.h" |
| 45 | #include "core/memory/cheat_engine.h" | 45 | #include "core/memory/cheat_engine.h" |
| @@ -91,37 +91,47 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 91 | std::string dir_name; | 91 | std::string dir_name; |
| 92 | std::string filename; | 92 | std::string filename; |
| 93 | Common::SplitPath(path, &dir_name, &filename, nullptr); | 93 | Common::SplitPath(path, &dir_name, &filename, nullptr); |
| 94 | |||
| 94 | if (filename == "00") { | 95 | if (filename == "00") { |
| 95 | const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); | 96 | const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); |
| 96 | std::vector<FileSys::VirtualFile> concat; | 97 | std::vector<FileSys::VirtualFile> concat; |
| 97 | for (u8 i = 0; i < 0x10; ++i) { | 98 | |
| 98 | auto next = dir->GetFile(fmt::format("{:02X}", i)); | 99 | for (u32 i = 0; i < 0x10; ++i) { |
| 99 | if (next != nullptr) | 100 | const auto file_name = fmt::format("{:02X}", i); |
| 101 | auto next = dir->GetFile(file_name); | ||
| 102 | |||
| 103 | if (next != nullptr) { | ||
| 100 | concat.push_back(std::move(next)); | 104 | concat.push_back(std::move(next)); |
| 101 | else { | 105 | } else { |
| 102 | next = dir->GetFile(fmt::format("{:02x}", i)); | 106 | next = dir->GetFile(file_name); |
| 103 | if (next != nullptr) | 107 | |
| 104 | concat.push_back(std::move(next)); | 108 | if (next == nullptr) { |
| 105 | else | ||
| 106 | break; | 109 | break; |
| 110 | } | ||
| 111 | |||
| 112 | concat.push_back(std::move(next)); | ||
| 107 | } | 113 | } |
| 108 | } | 114 | } |
| 109 | 115 | ||
| 110 | if (concat.empty()) | 116 | if (concat.empty()) { |
| 111 | return nullptr; | 117 | return nullptr; |
| 118 | } | ||
| 112 | 119 | ||
| 113 | return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName()); | 120 | return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(std::move(concat), |
| 121 | dir->GetName()); | ||
| 114 | } | 122 | } |
| 115 | 123 | ||
| 116 | if (Common::FS::IsDirectory(path)) | 124 | if (Common::FS::IsDirectory(path)) { |
| 117 | return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read); | 125 | return vfs->OpenFile(path + "/main", FileSys::Mode::Read); |
| 126 | } | ||
| 118 | 127 | ||
| 119 | return vfs->OpenFile(path, FileSys::Mode::Read); | 128 | return vfs->OpenFile(path, FileSys::Mode::Read); |
| 120 | } | 129 | } |
| 130 | |||
| 121 | struct System::Impl { | 131 | struct System::Impl { |
| 122 | explicit Impl(System& system) | 132 | explicit Impl(System& system) |
| 123 | : kernel{system}, fs_controller{system}, memory{system}, | 133 | : kernel{system}, fs_controller{system}, memory{system}, |
| 124 | cpu_manager{system}, reporter{system}, applet_manager{system} {} | 134 | cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} |
| 125 | 135 | ||
| 126 | ResultStatus Run() { | 136 | ResultStatus Run() { |
| 127 | status = ResultStatus::Success; | 137 | status = ResultStatus::Success; |
| @@ -144,12 +154,12 @@ struct System::Impl { | |||
| 144 | } | 154 | } |
| 145 | 155 | ||
| 146 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 156 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 147 | LOG_DEBUG(HW_Memory, "initialized OK"); | 157 | LOG_DEBUG(Core, "initialized OK"); |
| 148 | 158 | ||
| 149 | device_memory = std::make_unique<Core::DeviceMemory>(); | 159 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| 150 | 160 | ||
| 151 | is_multicore = Settings::values.use_multi_core.GetValue(); | 161 | is_multicore = Settings::values.use_multi_core.GetValue(); |
| 152 | is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue(); | 162 | is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); |
| 153 | 163 | ||
| 154 | kernel.SetMulticore(is_multicore); | 164 | kernel.SetMulticore(is_multicore); |
| 155 | cpu_manager.SetMulticore(is_multicore); | 165 | cpu_manager.SetMulticore(is_multicore); |
| @@ -178,17 +188,19 @@ struct System::Impl { | |||
| 178 | arp_manager.ResetAll(); | 188 | arp_manager.ResetAll(); |
| 179 | 189 | ||
| 180 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 190 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 181 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | ||
| 182 | 191 | ||
| 183 | Service::Init(service_manager, system); | ||
| 184 | GDBStub::DeferStart(); | ||
| 185 | |||
| 186 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); | ||
| 187 | gpu_core = VideoCore::CreateGPU(emu_window, system); | 192 | gpu_core = VideoCore::CreateGPU(emu_window, system); |
| 188 | if (!gpu_core) { | 193 | if (!gpu_core) { |
| 189 | return ResultStatus::ErrorVideoCore; | 194 | return ResultStatus::ErrorVideoCore; |
| 190 | } | 195 | } |
| 191 | 196 | ||
| 197 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | ||
| 198 | services = std::make_unique<Service::Services>(service_manager, system); | ||
| 199 | interrupt_manager = std::make_unique<Hardware::InterruptManager>(system); | ||
| 200 | |||
| 201 | // Initialize time manager, which must happen after kernel is created | ||
| 202 | time_manager.Initialize(); | ||
| 203 | |||
| 192 | is_powered_on = true; | 204 | is_powered_on = true; |
| 193 | exit_lock = false; | 205 | exit_lock = false; |
| 194 | 206 | ||
| @@ -202,9 +214,11 @@ struct System::Impl { | |||
| 202 | return ResultStatus::Success; | 214 | return ResultStatus::Success; |
| 203 | } | 215 | } |
| 204 | 216 | ||
| 205 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, | 217 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 206 | const std::string& filepath) { | 218 | std::size_t program_index) { |
| 207 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); | 219 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), |
| 220 | program_index); | ||
| 221 | |||
| 208 | if (!app_loader) { | 222 | if (!app_loader) { |
| 209 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 223 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| 210 | return ResultStatus::ErrorGetLoader; | 224 | return ResultStatus::ErrorGetLoader; |
| @@ -218,12 +232,12 @@ struct System::Impl { | |||
| 218 | return init_result; | 232 | return init_result; |
| 219 | } | 233 | } |
| 220 | 234 | ||
| 221 | telemetry_session->AddInitialInfo(*app_loader); | 235 | telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); |
| 222 | auto main_process = | 236 | auto main_process = |
| 223 | Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); | 237 | Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); |
| 224 | const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); | 238 | const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); |
| 225 | if (load_result != Loader::ResultStatus::Success) { | 239 | if (load_result != Loader::ResultStatus::Success) { |
| 226 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); | 240 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); |
| 227 | Shutdown(); | 241 | Shutdown(); |
| 228 | 242 | ||
| 229 | return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + | 243 | return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + |
| @@ -231,6 +245,7 @@ struct System::Impl { | |||
| 231 | } | 245 | } |
| 232 | AddGlueRegistrationForProcess(*app_loader, *main_process); | 246 | AddGlueRegistrationForProcess(*app_loader, *main_process); |
| 233 | kernel.MakeCurrentProcess(main_process.get()); | 247 | kernel.MakeCurrentProcess(main_process.get()); |
| 248 | kernel.InitializeCores(); | ||
| 234 | 249 | ||
| 235 | // Initialize cheat engine | 250 | // Initialize cheat engine |
| 236 | if (cheat_engine) { | 251 | if (cheat_engine) { |
| @@ -252,8 +267,7 @@ struct System::Impl { | |||
| 252 | 267 | ||
| 253 | u64 title_id{0}; | 268 | u64 title_id{0}; |
| 254 | if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { | 269 | if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { |
| 255 | LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", | 270 | LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); |
| 256 | static_cast<u32>(load_result)); | ||
| 257 | } | 271 | } |
| 258 | perf_stats = std::make_unique<PerfStats>(title_id); | 272 | perf_stats = std::make_unique<PerfStats>(title_id); |
| 259 | // Reset counters and set time origin to current frame | 273 | // Reset counters and set time origin to current frame |
| @@ -289,19 +303,17 @@ struct System::Impl { | |||
| 289 | } | 303 | } |
| 290 | 304 | ||
| 291 | // Shutdown emulation session | 305 | // Shutdown emulation session |
| 292 | GDBStub::Shutdown(); | 306 | services.reset(); |
| 293 | Service::Shutdown(); | ||
| 294 | service_manager.reset(); | 307 | service_manager.reset(); |
| 295 | cheat_engine.reset(); | 308 | cheat_engine.reset(); |
| 296 | telemetry_session.reset(); | 309 | telemetry_session.reset(); |
| 297 | device_memory.reset(); | ||
| 298 | 310 | ||
| 299 | // Close all CPU/threading state | 311 | // Close all CPU/threading state |
| 300 | cpu_manager.Shutdown(); | 312 | cpu_manager.Shutdown(); |
| 301 | 313 | ||
| 302 | // Shutdown kernel and core timing | 314 | // Shutdown kernel and core timing |
| 303 | kernel.Shutdown(); | ||
| 304 | core_timing.Shutdown(); | 315 | core_timing.Shutdown(); |
| 316 | kernel.Shutdown(); | ||
| 305 | 317 | ||
| 306 | // Close app loader | 318 | // Close app loader |
| 307 | app_loader.reset(); | 319 | app_loader.reset(); |
| @@ -332,7 +344,7 @@ struct System::Impl { | |||
| 332 | Service::Glue::ApplicationLaunchProperty launch{}; | 344 | Service::Glue::ApplicationLaunchProperty launch{}; |
| 333 | launch.title_id = process.GetTitleID(); | 345 | launch.title_id = process.GetTitleID(); |
| 334 | 346 | ||
| 335 | FileSys::PatchManager pm{launch.title_id}; | 347 | FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider}; |
| 336 | launch.version = pm.GetGameVersion().value_or(0); | 348 | launch.version = pm.GetGameVersion().value_or(0); |
| 337 | 349 | ||
| 338 | // TODO(DarkLordZach): When FSController/Game Card Support is added, if | 350 | // TODO(DarkLordZach): When FSController/Game Card Support is added, if |
| @@ -387,10 +399,14 @@ struct System::Impl { | |||
| 387 | /// Service State | 399 | /// Service State |
| 388 | Service::Glue::ARPManager arp_manager; | 400 | Service::Glue::ARPManager arp_manager; |
| 389 | Service::LM::Manager lm_manager{reporter}; | 401 | Service::LM::Manager lm_manager{reporter}; |
| 402 | Service::Time::TimeManager time_manager; | ||
| 390 | 403 | ||
| 391 | /// Service manager | 404 | /// Service manager |
| 392 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 405 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| 393 | 406 | ||
| 407 | /// Services | ||
| 408 | std::unique_ptr<Service::Services> services; | ||
| 409 | |||
| 394 | /// Telemetry session for this emulation session | 410 | /// Telemetry session for this emulation session |
| 395 | std::unique_ptr<Core::TelemetrySession> telemetry_session; | 411 | std::unique_ptr<Core::TelemetrySession> telemetry_session; |
| 396 | 412 | ||
| @@ -406,6 +422,8 @@ struct System::Impl { | |||
| 406 | bool is_multicore{}; | 422 | bool is_multicore{}; |
| 407 | bool is_async_gpu{}; | 423 | bool is_async_gpu{}; |
| 408 | 424 | ||
| 425 | ExecuteProgramCallback execute_program_callback; | ||
| 426 | |||
| 409 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; | 427 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
| 410 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; | 428 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; |
| 411 | }; | 429 | }; |
| @@ -437,8 +455,17 @@ void System::InvalidateCpuInstructionCaches() { | |||
| 437 | impl->kernel.InvalidateAllInstructionCaches(); | 455 | impl->kernel.InvalidateAllInstructionCaches(); |
| 438 | } | 456 | } |
| 439 | 457 | ||
| 440 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 458 | void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { |
| 441 | return impl->Load(*this, emu_window, filepath); | 459 | impl->kernel.InvalidateCpuInstructionCacheRange(addr, size); |
| 460 | } | ||
| 461 | |||
| 462 | void System::Shutdown() { | ||
| 463 | impl->Shutdown(); | ||
| 464 | } | ||
| 465 | |||
| 466 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | ||
| 467 | std::size_t program_index) { | ||
| 468 | return impl->Load(*this, emu_window, filepath, program_index); | ||
| 442 | } | 469 | } |
| 443 | 470 | ||
| 444 | bool System::IsPoweredOn() const { | 471 | bool System::IsPoweredOn() const { |
| @@ -466,11 +493,11 @@ const TelemetrySession& System::TelemetrySession() const { | |||
| 466 | } | 493 | } |
| 467 | 494 | ||
| 468 | ARM_Interface& System::CurrentArmInterface() { | 495 | ARM_Interface& System::CurrentArmInterface() { |
| 469 | return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); | 496 | return impl->kernel.CurrentPhysicalCore().ArmInterface(); |
| 470 | } | 497 | } |
| 471 | 498 | ||
| 472 | const ARM_Interface& System::CurrentArmInterface() const { | 499 | const ARM_Interface& System::CurrentArmInterface() const { |
| 473 | return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); | 500 | return impl->kernel.CurrentPhysicalCore().ArmInterface(); |
| 474 | } | 501 | } |
| 475 | 502 | ||
| 476 | std::size_t System::CurrentCoreIndex() const { | 503 | std::size_t System::CurrentCoreIndex() const { |
| @@ -479,14 +506,6 @@ std::size_t System::CurrentCoreIndex() const { | |||
| 479 | return core; | 506 | return core; |
| 480 | } | 507 | } |
| 481 | 508 | ||
| 482 | Kernel::Scheduler& System::CurrentScheduler() { | ||
| 483 | return impl->kernel.CurrentScheduler(); | ||
| 484 | } | ||
| 485 | |||
| 486 | const Kernel::Scheduler& System::CurrentScheduler() const { | ||
| 487 | return impl->kernel.CurrentScheduler(); | ||
| 488 | } | ||
| 489 | |||
| 490 | Kernel::PhysicalCore& System::CurrentPhysicalCore() { | 509 | Kernel::PhysicalCore& System::CurrentPhysicalCore() { |
| 491 | return impl->kernel.CurrentPhysicalCore(); | 510 | return impl->kernel.CurrentPhysicalCore(); |
| 492 | } | 511 | } |
| @@ -495,22 +514,14 @@ const Kernel::PhysicalCore& System::CurrentPhysicalCore() const { | |||
| 495 | return impl->kernel.CurrentPhysicalCore(); | 514 | return impl->kernel.CurrentPhysicalCore(); |
| 496 | } | 515 | } |
| 497 | 516 | ||
| 498 | Kernel::Scheduler& System::Scheduler(std::size_t core_index) { | ||
| 499 | return impl->kernel.Scheduler(core_index); | ||
| 500 | } | ||
| 501 | |||
| 502 | const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { | ||
| 503 | return impl->kernel.Scheduler(core_index); | ||
| 504 | } | ||
| 505 | |||
| 506 | /// Gets the global scheduler | 517 | /// Gets the global scheduler |
| 507 | Kernel::GlobalScheduler& System::GlobalScheduler() { | 518 | Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() { |
| 508 | return impl->kernel.GlobalScheduler(); | 519 | return impl->kernel.GlobalSchedulerContext(); |
| 509 | } | 520 | } |
| 510 | 521 | ||
| 511 | /// Gets the global scheduler | 522 | /// Gets the global scheduler |
| 512 | const Kernel::GlobalScheduler& System::GlobalScheduler() const { | 523 | const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const { |
| 513 | return impl->kernel.GlobalScheduler(); | 524 | return impl->kernel.GlobalSchedulerContext(); |
| 514 | } | 525 | } |
| 515 | 526 | ||
| 516 | Kernel::Process* System::CurrentProcess() { | 527 | Kernel::Process* System::CurrentProcess() { |
| @@ -530,15 +541,11 @@ const Kernel::Process* System::CurrentProcess() const { | |||
| 530 | } | 541 | } |
| 531 | 542 | ||
| 532 | ARM_Interface& System::ArmInterface(std::size_t core_index) { | 543 | ARM_Interface& System::ArmInterface(std::size_t core_index) { |
| 533 | auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); | 544 | return impl->kernel.PhysicalCore(core_index).ArmInterface(); |
| 534 | ASSERT(thread && !thread->IsHLEThread()); | ||
| 535 | return thread->ArmInterface(); | ||
| 536 | } | 545 | } |
| 537 | 546 | ||
| 538 | const ARM_Interface& System::ArmInterface(std::size_t core_index) const { | 547 | const ARM_Interface& System::ArmInterface(std::size_t core_index) const { |
| 539 | auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); | 548 | return impl->kernel.PhysicalCore(core_index).ArmInterface(); |
| 540 | ASSERT(thread && !thread->IsHLEThread()); | ||
| 541 | return thread->ArmInterface(); | ||
| 542 | } | 549 | } |
| 543 | 550 | ||
| 544 | ExclusiveMonitor& System::Monitor() { | 551 | ExclusiveMonitor& System::Monitor() { |
| @@ -625,7 +632,11 @@ const std::string& System::GetStatusDetails() const { | |||
| 625 | return impl->status_details; | 632 | return impl->status_details; |
| 626 | } | 633 | } |
| 627 | 634 | ||
| 628 | Loader::AppLoader& System::GetAppLoader() const { | 635 | Loader::AppLoader& System::GetAppLoader() { |
| 636 | return *impl->app_loader; | ||
| 637 | } | ||
| 638 | |||
| 639 | const Loader::AppLoader& System::GetAppLoader() const { | ||
| 629 | return *impl->app_loader; | 640 | return *impl->app_loader; |
| 630 | } | 641 | } |
| 631 | 642 | ||
| @@ -717,6 +728,14 @@ const Service::LM::Manager& System::GetLogManager() const { | |||
| 717 | return impl->lm_manager; | 728 | return impl->lm_manager; |
| 718 | } | 729 | } |
| 719 | 730 | ||
| 731 | Service::Time::TimeManager& System::GetTimeManager() { | ||
| 732 | return impl->time_manager; | ||
| 733 | } | ||
| 734 | |||
| 735 | const Service::Time::TimeManager& System::GetTimeManager() const { | ||
| 736 | return impl->time_manager; | ||
| 737 | } | ||
| 738 | |||
| 720 | void System::SetExitLock(bool locked) { | 739 | void System::SetExitLock(bool locked) { |
| 721 | impl->exit_lock = locked; | 740 | impl->exit_lock = locked; |
| 722 | } | 741 | } |
| @@ -733,14 +752,6 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const { | |||
| 733 | return impl->build_id; | 752 | return impl->build_id; |
| 734 | } | 753 | } |
| 735 | 754 | ||
| 736 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||
| 737 | return impl->Init(*this, emu_window); | ||
| 738 | } | ||
| 739 | |||
| 740 | void System::Shutdown() { | ||
| 741 | impl->Shutdown(); | ||
| 742 | } | ||
| 743 | |||
| 744 | Service::SM::ServiceManager& System::ServiceManager() { | 755 | Service::SM::ServiceManager& System::ServiceManager() { |
| 745 | return *impl->service_manager; | 756 | return *impl->service_manager; |
| 746 | } | 757 | } |
| @@ -771,4 +782,16 @@ bool System::IsMulticore() const { | |||
| 771 | return impl->is_multicore; | 782 | return impl->is_multicore; |
| 772 | } | 783 | } |
| 773 | 784 | ||
| 785 | void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { | ||
| 786 | impl->execute_program_callback = std::move(callback); | ||
| 787 | } | ||
| 788 | |||
| 789 | void System::ExecuteProgram(std::size_t program_index) { | ||
| 790 | if (impl->execute_program_callback) { | ||
| 791 | impl->execute_program_callback(program_index); | ||
| 792 | } else { | ||
| 793 | LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend"); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 774 | } // namespace Core | 797 | } // namespace Core |
diff --git a/src/core/core.h b/src/core/core.h index 83ded63a5..579a774e4 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <functional> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <vector> | 11 | #include <vector> |
| @@ -25,11 +26,11 @@ class VfsFilesystem; | |||
| 25 | } // namespace FileSys | 26 | } // namespace FileSys |
| 26 | 27 | ||
| 27 | namespace Kernel { | 28 | namespace Kernel { |
| 28 | class GlobalScheduler; | 29 | class GlobalSchedulerContext; |
| 29 | class KernelCore; | 30 | class KernelCore; |
| 30 | class PhysicalCore; | 31 | class PhysicalCore; |
| 31 | class Process; | 32 | class Process; |
| 32 | class Scheduler; | 33 | class KScheduler; |
| 33 | } // namespace Kernel | 34 | } // namespace Kernel |
| 34 | 35 | ||
| 35 | namespace Loader { | 36 | namespace Loader { |
| @@ -69,6 +70,10 @@ namespace SM { | |||
| 69 | class ServiceManager; | 70 | class ServiceManager; |
| 70 | } // namespace SM | 71 | } // namespace SM |
| 71 | 72 | ||
| 73 | namespace Time { | ||
| 74 | class TimeManager; | ||
| 75 | } // namespace Time | ||
| 76 | |||
| 72 | } // namespace Service | 77 | } // namespace Service |
| 73 | 78 | ||
| 74 | namespace Tegra { | 79 | namespace Tegra { |
| @@ -120,7 +125,7 @@ public: | |||
| 120 | * Gets the instance of the System singleton class. | 125 | * Gets the instance of the System singleton class. |
| 121 | * @returns Reference to the instance of the System singleton class. | 126 | * @returns Reference to the instance of the System singleton class. |
| 122 | */ | 127 | */ |
| 123 | static System& GetInstance() { | 128 | [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() { |
| 124 | return s_instance; | 129 | return s_instance; |
| 125 | } | 130 | } |
| 126 | 131 | ||
| @@ -140,19 +145,19 @@ public: | |||
| 140 | * Run the OS and Application | 145 | * Run the OS and Application |
| 141 | * This function will start emulation and run the relevant devices | 146 | * This function will start emulation and run the relevant devices |
| 142 | */ | 147 | */ |
| 143 | ResultStatus Run(); | 148 | [[nodiscard]] ResultStatus Run(); |
| 144 | 149 | ||
| 145 | /** | 150 | /** |
| 146 | * Pause the OS and Application | 151 | * Pause the OS and Application |
| 147 | * This function will pause emulation and stop the relevant devices | 152 | * This function will pause emulation and stop the relevant devices |
| 148 | */ | 153 | */ |
| 149 | ResultStatus Pause(); | 154 | [[nodiscard]] ResultStatus Pause(); |
| 150 | 155 | ||
| 151 | /** | 156 | /** |
| 152 | * Step the CPU one instruction | 157 | * Step the CPU one instruction |
| 153 | * @return Result status, indicating whether or not the operation succeeded. | 158 | * @return Result status, indicating whether or not the operation succeeded. |
| 154 | */ | 159 | */ |
| 155 | ResultStatus SingleStep(); | 160 | [[nodiscard]] ResultStatus SingleStep(); |
| 156 | 161 | ||
| 157 | /** | 162 | /** |
| 158 | * Invalidate the CPU instruction caches | 163 | * Invalidate the CPU instruction caches |
| @@ -161,6 +166,8 @@ public: | |||
| 161 | */ | 166 | */ |
| 162 | void InvalidateCpuInstructionCaches(); | 167 | void InvalidateCpuInstructionCaches(); |
| 163 | 168 | ||
| 169 | void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); | ||
| 170 | |||
| 164 | /// Shutdown the emulated system. | 171 | /// Shutdown the emulated system. |
| 165 | void Shutdown(); | 172 | void Shutdown(); |
| 166 | 173 | ||
| @@ -169,22 +176,24 @@ public: | |||
| 169 | * @param emu_window Reference to the host-system window used for video output and keyboard | 176 | * @param emu_window Reference to the host-system window used for video output and keyboard |
| 170 | * input. | 177 | * input. |
| 171 | * @param filepath String path to the executable application to load on the host file system. | 178 | * @param filepath String path to the executable application to load on the host file system. |
| 179 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 172 | * @returns ResultStatus code, indicating if the operation succeeded. | 180 | * @returns ResultStatus code, indicating if the operation succeeded. |
| 173 | */ | 181 | */ |
| 174 | ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath); | 182 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 183 | std::size_t program_index = 0); | ||
| 175 | 184 | ||
| 176 | /** | 185 | /** |
| 177 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an | 186 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an |
| 178 | * application). | 187 | * application). |
| 179 | * @returns True if the emulated system is powered on, otherwise false. | 188 | * @returns True if the emulated system is powered on, otherwise false. |
| 180 | */ | 189 | */ |
| 181 | bool IsPoweredOn() const; | 190 | [[nodiscard]] bool IsPoweredOn() const; |
| 182 | 191 | ||
| 183 | /// Gets a reference to the telemetry session for this emulation session. | 192 | /// Gets a reference to the telemetry session for this emulation session. |
| 184 | Core::TelemetrySession& TelemetrySession(); | 193 | [[nodiscard]] Core::TelemetrySession& TelemetrySession(); |
| 185 | 194 | ||
| 186 | /// Gets a reference to the telemetry session for this emulation session. | 195 | /// Gets a reference to the telemetry session for this emulation session. |
| 187 | const Core::TelemetrySession& TelemetrySession() const; | 196 | [[nodiscard]] const Core::TelemetrySession& TelemetrySession() const; |
| 188 | 197 | ||
| 189 | /// Prepare the core emulation for a reschedule | 198 | /// Prepare the core emulation for a reschedule |
| 190 | void PrepareReschedule(); | 199 | void PrepareReschedule(); |
| @@ -193,181 +202,166 @@ public: | |||
| 193 | void PrepareReschedule(u32 core_index); | 202 | void PrepareReschedule(u32 core_index); |
| 194 | 203 | ||
| 195 | /// Gets and resets core performance statistics | 204 | /// Gets and resets core performance statistics |
| 196 | PerfStatsResults GetAndResetPerfStats(); | 205 | [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); |
| 197 | 206 | ||
| 198 | /// Gets an ARM interface to the CPU core that is currently running | 207 | /// Gets an ARM interface to the CPU core that is currently running |
| 199 | ARM_Interface& CurrentArmInterface(); | 208 | [[nodiscard]] ARM_Interface& CurrentArmInterface(); |
| 200 | 209 | ||
| 201 | /// Gets an ARM interface to the CPU core that is currently running | 210 | /// Gets an ARM interface to the CPU core that is currently running |
| 202 | const ARM_Interface& CurrentArmInterface() const; | 211 | [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; |
| 203 | 212 | ||
| 204 | /// Gets the index of the currently running CPU core | 213 | /// Gets the index of the currently running CPU core |
| 205 | std::size_t CurrentCoreIndex() const; | 214 | [[nodiscard]] std::size_t CurrentCoreIndex() const; |
| 206 | |||
| 207 | /// Gets the scheduler for the CPU core that is currently running | ||
| 208 | Kernel::Scheduler& CurrentScheduler(); | ||
| 209 | |||
| 210 | /// Gets the scheduler for the CPU core that is currently running | ||
| 211 | const Kernel::Scheduler& CurrentScheduler() const; | ||
| 212 | 215 | ||
| 213 | /// Gets the physical core for the CPU core that is currently running | 216 | /// Gets the physical core for the CPU core that is currently running |
| 214 | Kernel::PhysicalCore& CurrentPhysicalCore(); | 217 | [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); |
| 215 | 218 | ||
| 216 | /// Gets the physical core for the CPU core that is currently running | 219 | /// Gets the physical core for the CPU core that is currently running |
| 217 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; | 220 | [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const; |
| 218 | 221 | ||
| 219 | /// Gets a reference to an ARM interface for the CPU core with the specified index | 222 | /// Gets a reference to an ARM interface for the CPU core with the specified index |
| 220 | ARM_Interface& ArmInterface(std::size_t core_index); | 223 | [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index); |
| 221 | 224 | ||
| 222 | /// Gets a const reference to an ARM interface from the CPU core with the specified index | 225 | /// Gets a const reference to an ARM interface from the CPU core with the specified index |
| 223 | const ARM_Interface& ArmInterface(std::size_t core_index) const; | 226 | [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const; |
| 224 | 227 | ||
| 225 | CpuManager& GetCpuManager(); | 228 | /// Gets a reference to the underlying CPU manager. |
| 229 | [[nodiscard]] CpuManager& GetCpuManager(); | ||
| 226 | 230 | ||
| 227 | const CpuManager& GetCpuManager() const; | 231 | /// Gets a const reference to the underlying CPU manager |
| 232 | [[nodiscard]] const CpuManager& GetCpuManager() const; | ||
| 228 | 233 | ||
| 229 | /// Gets a reference to the exclusive monitor | 234 | /// Gets a reference to the exclusive monitor |
| 230 | ExclusiveMonitor& Monitor(); | 235 | [[nodiscard]] ExclusiveMonitor& Monitor(); |
| 231 | 236 | ||
| 232 | /// Gets a constant reference to the exclusive monitor | 237 | /// Gets a constant reference to the exclusive monitor |
| 233 | const ExclusiveMonitor& Monitor() const; | 238 | [[nodiscard]] const ExclusiveMonitor& Monitor() const; |
| 234 | 239 | ||
| 235 | /// Gets a mutable reference to the system memory instance. | 240 | /// Gets a mutable reference to the system memory instance. |
| 236 | Core::Memory::Memory& Memory(); | 241 | [[nodiscard]] Core::Memory::Memory& Memory(); |
| 237 | 242 | ||
| 238 | /// Gets a constant reference to the system memory instance. | 243 | /// Gets a constant reference to the system memory instance. |
| 239 | const Core::Memory::Memory& Memory() const; | 244 | [[nodiscard]] const Core::Memory::Memory& Memory() const; |
| 240 | 245 | ||
| 241 | /// Gets a mutable reference to the GPU interface | 246 | /// Gets a mutable reference to the GPU interface |
| 242 | Tegra::GPU& GPU(); | 247 | [[nodiscard]] Tegra::GPU& GPU(); |
| 243 | 248 | ||
| 244 | /// Gets an immutable reference to the GPU interface. | 249 | /// Gets an immutable reference to the GPU interface. |
| 245 | const Tegra::GPU& GPU() const; | 250 | [[nodiscard]] const Tegra::GPU& GPU() const; |
| 246 | 251 | ||
| 247 | /// Gets a mutable reference to the renderer. | 252 | /// Gets a mutable reference to the renderer. |
| 248 | VideoCore::RendererBase& Renderer(); | 253 | [[nodiscard]] VideoCore::RendererBase& Renderer(); |
| 249 | 254 | ||
| 250 | /// Gets an immutable reference to the renderer. | 255 | /// Gets an immutable reference to the renderer. |
| 251 | const VideoCore::RendererBase& Renderer() const; | 256 | [[nodiscard]] const VideoCore::RendererBase& Renderer() const; |
| 252 | |||
| 253 | /// Gets the scheduler for the CPU core with the specified index | ||
| 254 | Kernel::Scheduler& Scheduler(std::size_t core_index); | ||
| 255 | |||
| 256 | /// Gets the scheduler for the CPU core with the specified index | ||
| 257 | const Kernel::Scheduler& Scheduler(std::size_t core_index) const; | ||
| 258 | 257 | ||
| 259 | /// Gets the global scheduler | 258 | /// Gets the global scheduler |
| 260 | Kernel::GlobalScheduler& GlobalScheduler(); | 259 | [[nodiscard]] Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); |
| 261 | 260 | ||
| 262 | /// Gets the global scheduler | 261 | /// Gets the global scheduler |
| 263 | const Kernel::GlobalScheduler& GlobalScheduler() const; | 262 | [[nodiscard]] const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const; |
| 264 | 263 | ||
| 265 | /// Gets the manager for the guest device memory | 264 | /// Gets the manager for the guest device memory |
| 266 | Core::DeviceMemory& DeviceMemory(); | 265 | [[nodiscard]] Core::DeviceMemory& DeviceMemory(); |
| 267 | 266 | ||
| 268 | /// Gets the manager for the guest device memory | 267 | /// Gets the manager for the guest device memory |
| 269 | const Core::DeviceMemory& DeviceMemory() const; | 268 | [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; |
| 270 | 269 | ||
| 271 | /// Provides a pointer to the current process | 270 | /// Provides a pointer to the current process |
| 272 | Kernel::Process* CurrentProcess(); | 271 | [[nodiscard]] Kernel::Process* CurrentProcess(); |
| 273 | 272 | ||
| 274 | /// Provides a constant pointer to the current process. | 273 | /// Provides a constant pointer to the current process. |
| 275 | const Kernel::Process* CurrentProcess() const; | 274 | [[nodiscard]] const Kernel::Process* CurrentProcess() const; |
| 276 | 275 | ||
| 277 | /// Provides a reference to the core timing instance. | 276 | /// Provides a reference to the core timing instance. |
| 278 | Timing::CoreTiming& CoreTiming(); | 277 | [[nodiscard]] Timing::CoreTiming& CoreTiming(); |
| 279 | 278 | ||
| 280 | /// Provides a constant reference to the core timing instance. | 279 | /// Provides a constant reference to the core timing instance. |
| 281 | const Timing::CoreTiming& CoreTiming() const; | 280 | [[nodiscard]] const Timing::CoreTiming& CoreTiming() const; |
| 282 | 281 | ||
| 283 | /// Provides a reference to the interrupt manager instance. | 282 | /// Provides a reference to the interrupt manager instance. |
| 284 | Core::Hardware::InterruptManager& InterruptManager(); | 283 | [[nodiscard]] Core::Hardware::InterruptManager& InterruptManager(); |
| 285 | 284 | ||
| 286 | /// Provides a constant reference to the interrupt manager instance. | 285 | /// Provides a constant reference to the interrupt manager instance. |
| 287 | const Core::Hardware::InterruptManager& InterruptManager() const; | 286 | [[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const; |
| 288 | 287 | ||
| 289 | /// Provides a reference to the kernel instance. | 288 | /// Provides a reference to the kernel instance. |
| 290 | Kernel::KernelCore& Kernel(); | 289 | [[nodiscard]] Kernel::KernelCore& Kernel(); |
| 291 | 290 | ||
| 292 | /// Provides a constant reference to the kernel instance. | 291 | /// Provides a constant reference to the kernel instance. |
| 293 | const Kernel::KernelCore& Kernel() const; | 292 | [[nodiscard]] const Kernel::KernelCore& Kernel() const; |
| 294 | 293 | ||
| 295 | /// Provides a reference to the internal PerfStats instance. | 294 | /// Provides a reference to the internal PerfStats instance. |
| 296 | Core::PerfStats& GetPerfStats(); | 295 | [[nodiscard]] Core::PerfStats& GetPerfStats(); |
| 297 | 296 | ||
| 298 | /// Provides a constant reference to the internal PerfStats instance. | 297 | /// Provides a constant reference to the internal PerfStats instance. |
| 299 | const Core::PerfStats& GetPerfStats() const; | 298 | [[nodiscard]] const Core::PerfStats& GetPerfStats() const; |
| 300 | 299 | ||
| 301 | /// Provides a reference to the frame limiter; | 300 | /// Provides a reference to the frame limiter; |
| 302 | Core::FrameLimiter& FrameLimiter(); | 301 | [[nodiscard]] Core::FrameLimiter& FrameLimiter(); |
| 303 | 302 | ||
| 304 | /// Provides a constant referent to the frame limiter | 303 | /// Provides a constant referent to the frame limiter |
| 305 | const Core::FrameLimiter& FrameLimiter() const; | 304 | [[nodiscard]] const Core::FrameLimiter& FrameLimiter() const; |
| 306 | 305 | ||
| 307 | /// Gets the name of the current game | 306 | /// Gets the name of the current game |
| 308 | Loader::ResultStatus GetGameName(std::string& out) const; | 307 | [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; |
| 309 | 308 | ||
| 310 | void SetStatus(ResultStatus new_status, const char* details); | 309 | void SetStatus(ResultStatus new_status, const char* details); |
| 311 | 310 | ||
| 312 | const std::string& GetStatusDetails() const; | 311 | [[nodiscard]] const std::string& GetStatusDetails() const; |
| 313 | 312 | ||
| 314 | Loader::AppLoader& GetAppLoader() const; | 313 | [[nodiscard]] Loader::AppLoader& GetAppLoader(); |
| 314 | [[nodiscard]] const Loader::AppLoader& GetAppLoader() const; | ||
| 315 | 315 | ||
| 316 | Service::SM::ServiceManager& ServiceManager(); | 316 | [[nodiscard]] Service::SM::ServiceManager& ServiceManager(); |
| 317 | const Service::SM::ServiceManager& ServiceManager() const; | 317 | [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const; |
| 318 | 318 | ||
| 319 | void SetFilesystem(FileSys::VirtualFilesystem vfs); | 319 | void SetFilesystem(FileSys::VirtualFilesystem vfs); |
| 320 | 320 | ||
| 321 | FileSys::VirtualFilesystem GetFilesystem() const; | 321 | [[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const; |
| 322 | 322 | ||
| 323 | void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, | 323 | void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, |
| 324 | const std::array<u8, 0x20>& build_id, VAddr main_region_begin, | 324 | const std::array<u8, 0x20>& build_id, VAddr main_region_begin, |
| 325 | u64 main_region_size); | 325 | u64 main_region_size); |
| 326 | 326 | ||
| 327 | void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); | 327 | void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); |
| 328 | |||
| 329 | void SetDefaultAppletFrontendSet(); | 328 | void SetDefaultAppletFrontendSet(); |
| 330 | 329 | ||
| 331 | Service::AM::Applets::AppletManager& GetAppletManager(); | 330 | [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); |
| 332 | 331 | [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const; | |
| 333 | const Service::AM::Applets::AppletManager& GetAppletManager() const; | ||
| 334 | 332 | ||
| 335 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); | 333 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); |
| 336 | 334 | ||
| 337 | FileSys::ContentProvider& GetContentProvider(); | 335 | [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); |
| 338 | 336 | [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; | |
| 339 | const FileSys::ContentProvider& GetContentProvider() const; | ||
| 340 | 337 | ||
| 341 | Service::FileSystem::FileSystemController& GetFileSystemController(); | 338 | [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); |
| 342 | 339 | [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const; | |
| 343 | const Service::FileSystem::FileSystemController& GetFileSystemController() const; | ||
| 344 | 340 | ||
| 345 | void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, | 341 | void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, |
| 346 | FileSys::ContentProvider* provider); | 342 | FileSys::ContentProvider* provider); |
| 347 | 343 | ||
| 348 | void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); | 344 | void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); |
| 349 | 345 | ||
| 350 | const Reporter& GetReporter() const; | 346 | [[nodiscard]] const Reporter& GetReporter() const; |
| 351 | |||
| 352 | Service::Glue::ARPManager& GetARPManager(); | ||
| 353 | |||
| 354 | const Service::Glue::ARPManager& GetARPManager() const; | ||
| 355 | 347 | ||
| 356 | Service::APM::Controller& GetAPMController(); | 348 | [[nodiscard]] Service::Glue::ARPManager& GetARPManager(); |
| 349 | [[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const; | ||
| 357 | 350 | ||
| 358 | const Service::APM::Controller& GetAPMController() const; | 351 | [[nodiscard]] Service::APM::Controller& GetAPMController(); |
| 352 | [[nodiscard]] const Service::APM::Controller& GetAPMController() const; | ||
| 359 | 353 | ||
| 360 | Service::LM::Manager& GetLogManager(); | 354 | [[nodiscard]] Service::LM::Manager& GetLogManager(); |
| 355 | [[nodiscard]] const Service::LM::Manager& GetLogManager() const; | ||
| 361 | 356 | ||
| 362 | const Service::LM::Manager& GetLogManager() const; | 357 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); |
| 358 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; | ||
| 363 | 359 | ||
| 364 | void SetExitLock(bool locked); | 360 | void SetExitLock(bool locked); |
| 365 | 361 | [[nodiscard]] bool GetExitLock() const; | |
| 366 | bool GetExitLock() const; | ||
| 367 | 362 | ||
| 368 | void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); | 363 | void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); |
| 369 | 364 | [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | |
| 370 | const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | ||
| 371 | 365 | ||
| 372 | /// Register a host thread as an emulated CPU Core. | 366 | /// Register a host thread as an emulated CPU Core. |
| 373 | void RegisterCoreThread(std::size_t id); | 367 | void RegisterCoreThread(std::size_t id); |
| @@ -382,18 +376,27 @@ public: | |||
| 382 | void ExitDynarmicProfile(); | 376 | void ExitDynarmicProfile(); |
| 383 | 377 | ||
| 384 | /// Tells if system is running on multicore. | 378 | /// Tells if system is running on multicore. |
| 385 | bool IsMulticore() const; | 379 | [[nodiscard]] bool IsMulticore() const; |
| 386 | 380 | ||
| 387 | private: | 381 | /// Type used for the frontend to designate a callback for System to re-launch the application |
| 388 | System(); | 382 | /// using a specified program index. |
| 383 | using ExecuteProgramCallback = std::function<void(std::size_t)>; | ||
| 389 | 384 | ||
| 390 | /** | 385 | /** |
| 391 | * Initialize the emulated system. | 386 | * Registers a callback from the frontend for System to re-launch the application using a |
| 392 | * @param emu_window Reference to the host-system window used for video output and keyboard | 387 | * specified program index. |
| 393 | * input. | 388 | * @param callback Callback from the frontend to relaunch the application. |
| 394 | * @return ResultStatus code, indicating if the operation succeeded. | ||
| 395 | */ | 389 | */ |
| 396 | ResultStatus Init(Frontend::EmuWindow& emu_window); | 390 | void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback); |
| 391 | |||
| 392 | /** | ||
| 393 | * Instructs the frontend to re-launch the application using the specified program_index. | ||
| 394 | * @param program_index Specifies the index within the application of the program to launch. | ||
| 395 | */ | ||
| 396 | void ExecuteProgram(std::size_t program_index); | ||
| 397 | |||
| 398 | private: | ||
| 399 | System(); | ||
| 397 | 400 | ||
| 398 | struct Impl; | 401 | struct Impl; |
| 399 | std::unique_ptr<Impl> impl; | 402 | std::unique_ptr<Impl> impl; |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index b0b6036e4..77ff4c6fe 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -27,8 +27,8 @@ using TimedCallback = | |||
| 27 | 27 | ||
| 28 | /// Contains the characteristics of a particular event. | 28 | /// Contains the characteristics of a particular event. |
| 29 | struct EventType { | 29 | struct EventType { |
| 30 | EventType(TimedCallback&& callback, std::string&& name) | 30 | explicit EventType(TimedCallback&& callback_, std::string&& name_) |
| 31 | : callback{std::move(callback)}, name{std::move(name)} {} | 31 | : callback{std::move(callback_)}, name{std::move(name_)} {} |
| 32 | 32 | ||
| 33 | /// The event's callback function. | 33 | /// The event's callback function. |
| 34 | TimedCallback callback; | 34 | TimedCallback callback; |
| @@ -67,8 +67,8 @@ public: | |||
| 67 | void Shutdown(); | 67 | void Shutdown(); |
| 68 | 68 | ||
| 69 | /// Sets if emulation is multicore or single core, must be set before Initialize | 69 | /// Sets if emulation is multicore or single core, must be set before Initialize |
| 70 | void SetMulticore(bool is_multicore) { | 70 | void SetMulticore(bool is_multicore_) { |
| 71 | this->is_multicore = is_multicore; | 71 | is_multicore = is_multicore_; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | /// Check if it's using host timing. | 74 | /// Check if it's using host timing. |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 688b99eba..373395047 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -4,15 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/fiber.h" | 5 | #include "common/fiber.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "common/scope_exit.h" | ||
| 7 | #include "common/thread.h" | 8 | #include "common/thread.h" |
| 8 | #include "core/arm/exclusive_monitor.h" | 9 | #include "core/arm/exclusive_monitor.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 11 | #include "core/cpu_manager.h" | 12 | #include "core/cpu_manager.h" |
| 12 | #include "core/gdbstub/gdbstub.h" | 13 | #include "core/hle/kernel/k_scheduler.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/physical_core.h" | 15 | #include "core/hle/kernel/physical_core.h" |
| 15 | #include "core/hle/kernel/scheduler.h" | ||
| 16 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 17 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 18 | 18 | ||
| @@ -109,28 +109,26 @@ void* CpuManager::GetStartFuncParamater() { | |||
| 109 | 109 | ||
| 110 | void CpuManager::MultiCoreRunGuestThread() { | 110 | void CpuManager::MultiCoreRunGuestThread() { |
| 111 | auto& kernel = system.Kernel(); | 111 | auto& kernel = system.Kernel(); |
| 112 | { | 112 | kernel.CurrentScheduler()->OnThreadStart(); |
| 113 | auto& sched = kernel.CurrentScheduler(); | 113 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 114 | sched.OnThreadStart(); | 114 | auto& host_context = thread->GetHostContext(); |
| 115 | } | 115 | host_context->SetRewindPoint(GuestRewindFunction, this); |
| 116 | MultiCoreRunGuestLoop(); | 116 | MultiCoreRunGuestLoop(); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void CpuManager::MultiCoreRunGuestLoop() { | 119 | void CpuManager::MultiCoreRunGuestLoop() { |
| 120 | auto& kernel = system.Kernel(); | 120 | auto& kernel = system.Kernel(); |
| 121 | auto* thread = kernel.CurrentScheduler().GetCurrentThread(); | 121 | |
| 122 | while (true) { | 122 | while (true) { |
| 123 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 123 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 124 | auto& arm_interface = thread->ArmInterface(); | ||
| 125 | system.EnterDynarmicProfile(); | 124 | system.EnterDynarmicProfile(); |
| 126 | while (!physical_core->IsInterrupted()) { | 125 | while (!physical_core->IsInterrupted()) { |
| 127 | arm_interface.Run(); | 126 | physical_core->Run(); |
| 128 | physical_core = &kernel.CurrentPhysicalCore(); | 127 | physical_core = &kernel.CurrentPhysicalCore(); |
| 129 | } | 128 | } |
| 130 | system.ExitDynarmicProfile(); | 129 | system.ExitDynarmicProfile(); |
| 131 | arm_interface.ClearExclusiveState(); | 130 | physical_core->ArmInterface().ClearExclusiveState(); |
| 132 | auto& scheduler = kernel.CurrentScheduler(); | 131 | kernel.CurrentScheduler()->RescheduleCurrentCore(); |
| 133 | scheduler.TryDoContextSwitch(); | ||
| 134 | } | 132 | } |
| 135 | } | 133 | } |
| 136 | 134 | ||
| @@ -139,25 +137,21 @@ void CpuManager::MultiCoreRunIdleThread() { | |||
| 139 | while (true) { | 137 | while (true) { |
| 140 | auto& physical_core = kernel.CurrentPhysicalCore(); | 138 | auto& physical_core = kernel.CurrentPhysicalCore(); |
| 141 | physical_core.Idle(); | 139 | physical_core.Idle(); |
| 142 | auto& scheduler = kernel.CurrentScheduler(); | 140 | kernel.CurrentScheduler()->RescheduleCurrentCore(); |
| 143 | scheduler.TryDoContextSwitch(); | ||
| 144 | } | 141 | } |
| 145 | } | 142 | } |
| 146 | 143 | ||
| 147 | void CpuManager::MultiCoreRunSuspendThread() { | 144 | void CpuManager::MultiCoreRunSuspendThread() { |
| 148 | auto& kernel = system.Kernel(); | 145 | auto& kernel = system.Kernel(); |
| 149 | { | 146 | kernel.CurrentScheduler()->OnThreadStart(); |
| 150 | auto& sched = kernel.CurrentScheduler(); | ||
| 151 | sched.OnThreadStart(); | ||
| 152 | } | ||
| 153 | while (true) { | 147 | while (true) { |
| 154 | auto core = kernel.GetCurrentHostThreadID(); | 148 | auto core = kernel.GetCurrentHostThreadID(); |
| 155 | auto& scheduler = kernel.CurrentScheduler(); | 149 | auto& scheduler = *kernel.CurrentScheduler(); |
| 156 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 150 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 157 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); | 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); |
| 158 | ASSERT(scheduler.ContextSwitchPending()); | 152 | ASSERT(scheduler.ContextSwitchPending()); |
| 159 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 160 | scheduler.TryDoContextSwitch(); | 154 | scheduler.RescheduleCurrentCore(); |
| 161 | } | 155 | } |
| 162 | } | 156 | } |
| 163 | 157 | ||
| @@ -205,32 +199,31 @@ void CpuManager::MultiCorePause(bool paused) { | |||
| 205 | 199 | ||
| 206 | void CpuManager::SingleCoreRunGuestThread() { | 200 | void CpuManager::SingleCoreRunGuestThread() { |
| 207 | auto& kernel = system.Kernel(); | 201 | auto& kernel = system.Kernel(); |
| 208 | { | 202 | kernel.CurrentScheduler()->OnThreadStart(); |
| 209 | auto& sched = kernel.CurrentScheduler(); | 203 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 210 | sched.OnThreadStart(); | 204 | auto& host_context = thread->GetHostContext(); |
| 211 | } | 205 | host_context->SetRewindPoint(GuestRewindFunction, this); |
| 212 | SingleCoreRunGuestLoop(); | 206 | SingleCoreRunGuestLoop(); |
| 213 | } | 207 | } |
| 214 | 208 | ||
| 215 | void CpuManager::SingleCoreRunGuestLoop() { | 209 | void CpuManager::SingleCoreRunGuestLoop() { |
| 216 | auto& kernel = system.Kernel(); | 210 | auto& kernel = system.Kernel(); |
| 217 | auto* thread = kernel.CurrentScheduler().GetCurrentThread(); | 211 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 218 | while (true) { | 212 | while (true) { |
| 219 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 213 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 220 | auto& arm_interface = thread->ArmInterface(); | ||
| 221 | system.EnterDynarmicProfile(); | 214 | system.EnterDynarmicProfile(); |
| 222 | if (!physical_core->IsInterrupted()) { | 215 | if (!physical_core->IsInterrupted()) { |
| 223 | arm_interface.Run(); | 216 | physical_core->Run(); |
| 224 | physical_core = &kernel.CurrentPhysicalCore(); | 217 | physical_core = &kernel.CurrentPhysicalCore(); |
| 225 | } | 218 | } |
| 226 | system.ExitDynarmicProfile(); | 219 | system.ExitDynarmicProfile(); |
| 227 | thread->SetPhantomMode(true); | 220 | thread->SetPhantomMode(true); |
| 228 | system.CoreTiming().Advance(); | 221 | system.CoreTiming().Advance(); |
| 229 | thread->SetPhantomMode(false); | 222 | thread->SetPhantomMode(false); |
| 230 | arm_interface.ClearExclusiveState(); | 223 | physical_core->ArmInterface().ClearExclusiveState(); |
| 231 | PreemptSingleCore(); | 224 | PreemptSingleCore(); |
| 232 | auto& scheduler = kernel.Scheduler(current_core); | 225 | auto& scheduler = kernel.Scheduler(current_core); |
| 233 | scheduler.TryDoContextSwitch(); | 226 | scheduler.RescheduleCurrentCore(); |
| 234 | } | 227 | } |
| 235 | } | 228 | } |
| 236 | 229 | ||
| @@ -242,51 +235,53 @@ void CpuManager::SingleCoreRunIdleThread() { | |||
| 242 | system.CoreTiming().AddTicks(1000U); | 235 | system.CoreTiming().AddTicks(1000U); |
| 243 | idle_count++; | 236 | idle_count++; |
| 244 | auto& scheduler = physical_core.Scheduler(); | 237 | auto& scheduler = physical_core.Scheduler(); |
| 245 | scheduler.TryDoContextSwitch(); | 238 | scheduler.RescheduleCurrentCore(); |
| 246 | } | 239 | } |
| 247 | } | 240 | } |
| 248 | 241 | ||
| 249 | void CpuManager::SingleCoreRunSuspendThread() { | 242 | void CpuManager::SingleCoreRunSuspendThread() { |
| 250 | auto& kernel = system.Kernel(); | 243 | auto& kernel = system.Kernel(); |
| 251 | { | 244 | kernel.CurrentScheduler()->OnThreadStart(); |
| 252 | auto& sched = kernel.CurrentScheduler(); | ||
| 253 | sched.OnThreadStart(); | ||
| 254 | } | ||
| 255 | while (true) { | 245 | while (true) { |
| 256 | auto core = kernel.GetCurrentHostThreadID(); | 246 | auto core = kernel.GetCurrentHostThreadID(); |
| 257 | auto& scheduler = kernel.CurrentScheduler(); | 247 | auto& scheduler = *kernel.CurrentScheduler(); |
| 258 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 248 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 259 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); | 249 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); |
| 260 | ASSERT(scheduler.ContextSwitchPending()); | 250 | ASSERT(scheduler.ContextSwitchPending()); |
| 261 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 251 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 262 | scheduler.TryDoContextSwitch(); | 252 | scheduler.RescheduleCurrentCore(); |
| 263 | } | 253 | } |
| 264 | } | 254 | } |
| 265 | 255 | ||
| 266 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | 256 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { |
| 267 | std::size_t old_core = current_core; | 257 | { |
| 268 | auto& scheduler = system.Kernel().Scheduler(old_core); | 258 | auto& scheduler = system.Kernel().Scheduler(current_core); |
| 269 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 259 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 270 | if (idle_count >= 4 || from_running_enviroment) { | 260 | if (idle_count >= 4 || from_running_enviroment) { |
| 271 | if (!from_running_enviroment) { | 261 | if (!from_running_enviroment) { |
| 272 | system.CoreTiming().Idle(); | 262 | system.CoreTiming().Idle(); |
| 273 | idle_count = 0; | 263 | idle_count = 0; |
| 264 | } | ||
| 265 | current_thread->SetPhantomMode(true); | ||
| 266 | system.CoreTiming().Advance(); | ||
| 267 | current_thread->SetPhantomMode(false); | ||
| 274 | } | 268 | } |
| 275 | current_thread->SetPhantomMode(true); | 269 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); |
| 276 | system.CoreTiming().Advance(); | 270 | system.CoreTiming().ResetTicks(); |
| 277 | current_thread->SetPhantomMode(false); | 271 | scheduler.Unload(scheduler.GetCurrentThread()); |
| 272 | |||
| 273 | auto& next_scheduler = system.Kernel().Scheduler(current_core); | ||
| 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | ||
| 278 | } | 275 | } |
| 279 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); | 276 | |
| 280 | system.CoreTiming().ResetTicks(); | 277 | // May have changed scheduler |
| 281 | scheduler.Unload(); | 278 | { |
| 282 | auto& next_scheduler = system.Kernel().Scheduler(current_core); | 279 | auto& scheduler = system.Kernel().Scheduler(current_core); |
| 283 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | 280 | scheduler.Reload(scheduler.GetCurrentThread()); |
| 284 | /// May have changed scheduler | 281 | auto* currrent_thread2 = scheduler.GetCurrentThread(); |
| 285 | auto& current_scheduler = system.Kernel().Scheduler(current_core); | 282 | if (!currrent_thread2->IsIdleThread()) { |
| 286 | current_scheduler.Reload(); | 283 | idle_count = 0; |
| 287 | auto* currrent_thread2 = current_scheduler.GetCurrentThread(); | 284 | } |
| 288 | if (!currrent_thread2->IsIdleThread()) { | ||
| 289 | idle_count = 0; | ||
| 290 | } | 285 | } |
| 291 | } | 286 | } |
| 292 | 287 | ||
| @@ -343,6 +338,16 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 343 | data.initialized = true; | 338 | data.initialized = true; |
| 344 | const bool sc_sync = !is_async_gpu && !is_multicore; | 339 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 345 | bool sc_sync_first_use = sc_sync; | 340 | bool sc_sync_first_use = sc_sync; |
| 341 | |||
| 342 | // Cleanup | ||
| 343 | SCOPE_EXIT({ | ||
| 344 | data.host_context->Exit(); | ||
| 345 | data.enter_barrier.reset(); | ||
| 346 | data.exit_barrier.reset(); | ||
| 347 | data.initialized = false; | ||
| 348 | MicroProfileOnThreadExit(); | ||
| 349 | }); | ||
| 350 | |||
| 346 | /// Running | 351 | /// Running |
| 347 | while (running_mode) { | 352 | while (running_mode) { |
| 348 | data.is_running = false; | 353 | data.is_running = false; |
| @@ -351,8 +356,13 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 351 | system.GPU().ObtainContext(); | 356 | system.GPU().ObtainContext(); |
| 352 | sc_sync_first_use = false; | 357 | sc_sync_first_use = false; |
| 353 | } | 358 | } |
| 354 | auto& scheduler = system.Kernel().CurrentScheduler(); | 359 | |
| 355 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 360 | // Abort if emulation was killed before the session really starts |
| 361 | if (!system.IsPoweredOn()) { | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 365 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | ||
| 356 | data.is_running = true; | 366 | data.is_running = true; |
| 357 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); | 367 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); |
| 358 | data.is_running = false; | 368 | data.is_running = false; |
| @@ -360,11 +370,6 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 360 | data.exit_barrier->Wait(); | 370 | data.exit_barrier->Wait(); |
| 361 | data.is_paused = false; | 371 | data.is_paused = false; |
| 362 | } | 372 | } |
| 363 | /// Time to cleanup | ||
| 364 | data.host_context->Exit(); | ||
| 365 | data.enter_barrier.reset(); | ||
| 366 | data.exit_barrier.reset(); | ||
| 367 | data.initialized = false; | ||
| 368 | } | 373 | } |
| 369 | 374 | ||
| 370 | } // namespace Core | 375 | } // namespace Core |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 65d246050..cebe2ce37 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -143,6 +143,7 @@ u64 GetSignatureTypeDataSize(SignatureType type) { | |||
| 143 | return 0x3C; | 143 | return 0x3C; |
| 144 | } | 144 | } |
| 145 | UNREACHABLE(); | 145 | UNREACHABLE(); |
| 146 | return 0; | ||
| 146 | } | 147 | } |
| 147 | 148 | ||
| 148 | u64 GetSignatureTypePaddingSize(SignatureType type) { | 149 | u64 GetSignatureTypePaddingSize(SignatureType type) { |
| @@ -157,6 +158,7 @@ u64 GetSignatureTypePaddingSize(SignatureType type) { | |||
| 157 | return 0x40; | 158 | return 0x40; |
| 158 | } | 159 | } |
| 159 | UNREACHABLE(); | 160 | UNREACHABLE(); |
| 161 | return 0; | ||
| 160 | } | 162 | } |
| 161 | 163 | ||
| 162 | SignatureType Ticket::GetSignatureType() const { | 164 | SignatureType Ticket::GetSignatureType() const { |
| @@ -169,8 +171,7 @@ SignatureType Ticket::GetSignatureType() const { | |||
| 169 | if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { | 171 | if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { |
| 170 | return ticket->sig_type; | 172 | return ticket->sig_type; |
| 171 | } | 173 | } |
| 172 | 174 | throw std::bad_variant_access{}; | |
| 173 | UNREACHABLE(); | ||
| 174 | } | 175 | } |
| 175 | 176 | ||
| 176 | TicketData& Ticket::GetData() { | 177 | TicketData& Ticket::GetData() { |
| @@ -183,8 +184,7 @@ TicketData& Ticket::GetData() { | |||
| 183 | if (auto* ticket = std::get_if<ECDSATicket>(&data)) { | 184 | if (auto* ticket = std::get_if<ECDSATicket>(&data)) { |
| 184 | return ticket->data; | 185 | return ticket->data; |
| 185 | } | 186 | } |
| 186 | 187 | throw std::bad_variant_access{}; | |
| 187 | UNREACHABLE(); | ||
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | const TicketData& Ticket::GetData() const { | 190 | const TicketData& Ticket::GetData() const { |
| @@ -197,8 +197,7 @@ const TicketData& Ticket::GetData() const { | |||
| 197 | if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { | 197 | if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { |
| 198 | return ticket->data; | 198 | return ticket->data; |
| 199 | } | 199 | } |
| 200 | 200 | throw std::bad_variant_access{}; | |
| 201 | UNREACHABLE(); | ||
| 202 | } | 201 | } |
| 203 | 202 | ||
| 204 | u64 Ticket::GetSize() const { | 203 | u64 Ticket::GetSize() const { |
| @@ -411,7 +410,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke | |||
| 411 | // Combine sources and seed | 410 | // Combine sources and seed |
| 412 | for (auto& source : sd_key_sources) { | 411 | for (auto& source : sd_key_sources) { |
| 413 | for (std::size_t i = 0; i < source.size(); ++i) { | 412 | for (std::size_t i = 0; i < source.size(); ++i) { |
| 414 | source[i] ^= sd_seed[i & 0xF]; | 413 | source[i] = static_cast<u8>(source[i] ^ sd_seed[i & 0xF]); |
| 415 | } | 414 | } |
| 416 | } | 415 | } |
| 417 | 416 | ||
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 956da68f7..8dee5590b 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -29,7 +29,7 @@ constexpr std::array partition_names{ | |||
| 29 | "logo", | 29 | "logo", |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | XCI::XCI(VirtualFile file_) | 32 | XCI::XCI(VirtualFile file_, std::size_t program_index) |
| 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, | 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, |
| 34 | partitions(partition_names.size()), | 34 | partitions(partition_names.size()), |
| 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { | 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { |
| @@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_) | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | secure_partition = std::make_shared<NSP>( | 64 | secure_partition = std::make_shared<NSP>( |
| 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); | 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), |
| 66 | program_index); | ||
| 66 | 67 | ||
| 67 | ncas = secure_partition->GetNCAsCollapsed(); | 68 | ncas = secure_partition->GetNCAsCollapsed(); |
| 68 | program = | 69 | program = |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 2d0a0f285..4960e90fe 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo }; | |||
| 78 | 78 | ||
| 79 | class XCI : public ReadOnlyVfsDirectory { | 79 | class XCI : public ReadOnlyVfsDirectory { |
| 80 | public: | 80 | public: |
| 81 | explicit XCI(VirtualFile file); | 81 | explicit XCI(VirtualFile file, std::size_t program_index = 0); |
| 82 | ~XCI() override; | 82 | ~XCI() override; |
| 83 | 83 | ||
| 84 | Loader::ResultStatus GetStatus() const; | 84 | Loader::ResultStatus GetStatus() const; |
diff --git a/src/core/file_sys/common_funcs.h b/src/core/file_sys/common_funcs.h new file mode 100644 index 000000000..7ed97aa50 --- /dev/null +++ b/src/core/file_sys/common_funcs.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace FileSys { | ||
| 10 | |||
| 11 | constexpr u64 AOC_TITLE_ID_MASK = 0x7FF; | ||
| 12 | constexpr u64 AOC_TITLE_ID_OFFSET = 0x1000; | ||
| 13 | constexpr u64 BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Gets the base title ID from a given title ID. | ||
| 17 | * | ||
| 18 | * @param title_id The title ID. | ||
| 19 | * @returns The base title ID. | ||
| 20 | */ | ||
| 21 | [[nodiscard]] constexpr u64 GetBaseTitleID(u64 title_id) { | ||
| 22 | return title_id & BASE_TITLE_ID_MASK; | ||
| 23 | } | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Gets the base title ID with a program index offset from a given title ID. | ||
| 27 | * | ||
| 28 | * @param title_id The title ID. | ||
| 29 | * @param program_index The program index. | ||
| 30 | * @returns The base title ID with a program index offset. | ||
| 31 | */ | ||
| 32 | [[nodiscard]] constexpr u64 GetBaseTitleIDWithProgramIndex(u64 title_id, u64 program_index) { | ||
| 33 | return GetBaseTitleID(title_id) + program_index; | ||
| 34 | } | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Gets the AOC (Add-On Content) base title ID from a given title ID. | ||
| 38 | * | ||
| 39 | * @param title_id The title ID. | ||
| 40 | * @returns The AOC base title ID. | ||
| 41 | */ | ||
| 42 | [[nodiscard]] constexpr u64 GetAOCBaseTitleID(u64 title_id) { | ||
| 43 | return GetBaseTitleID(title_id) + AOC_TITLE_ID_OFFSET; | ||
| 44 | } | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Gets the AOC (Add-On Content) ID from a given AOC title ID. | ||
| 48 | * | ||
| 49 | * @param aoc_title_id The AOC title ID. | ||
| 50 | * @returns The AOC ID. | ||
| 51 | */ | ||
| 52 | [[nodiscard]] constexpr u64 GetAOCID(u64 aoc_title_id) { | ||
| 53 | return aoc_title_id & AOC_TITLE_ID_MASK; | ||
| 54 | } | ||
| 55 | |||
| 56 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 76af47ff9..a6c0337fa 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -410,8 +410,9 @@ u8 NCA::GetCryptoRevision() const { | |||
| 410 | std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { | 410 | std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { |
| 411 | const auto master_key_id = GetCryptoRevision(); | 411 | const auto master_key_id = GetCryptoRevision(); |
| 412 | 412 | ||
| 413 | if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) | 413 | if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) { |
| 414 | return {}; | 414 | return std::nullopt; |
| 415 | } | ||
| 415 | 416 | ||
| 416 | std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); | 417 | std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); |
| 417 | Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( | 418 | Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( |
| @@ -420,15 +421,17 @@ std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type | |||
| 420 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); | 421 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); |
| 421 | 422 | ||
| 422 | Core::Crypto::Key128 out; | 423 | Core::Crypto::Key128 out; |
| 423 | if (type == NCASectionCryptoType::XTS) | 424 | if (type == NCASectionCryptoType::XTS) { |
| 424 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); | 425 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); |
| 425 | else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) | 426 | } else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) { |
| 426 | std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin()); | 427 | std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin()); |
| 427 | else | 428 | } else { |
| 428 | LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", | 429 | LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", |
| 429 | static_cast<u8>(type)); | 430 | type); |
| 431 | } | ||
| 432 | |||
| 430 | u128 out_128{}; | 433 | u128 out_128{}; |
| 431 | memcpy(out_128.data(), out.data(), 16); | 434 | std::memcpy(out_128.data(), out.data(), sizeof(u128)); |
| 432 | LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", | 435 | LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", |
| 433 | master_key_id, header.key_index, out_128[1], out_128[0]); | 436 | master_key_id, header.key_index, out_128[1], out_128[0]); |
| 434 | 437 | ||
| @@ -507,7 +510,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s | |||
| 507 | // TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs | 510 | // TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs |
| 508 | default: | 511 | default: |
| 509 | LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", | 512 | LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", |
| 510 | static_cast<u8>(s_header.raw.header.crypto_type)); | 513 | s_header.raw.header.crypto_type); |
| 511 | return nullptr; | 514 | return nullptr; |
| 512 | } | 515 | } |
| 513 | } | 516 | } |
| @@ -516,15 +519,17 @@ Loader::ResultStatus NCA::GetStatus() const { | |||
| 516 | return status; | 519 | return status; |
| 517 | } | 520 | } |
| 518 | 521 | ||
| 519 | std::vector<std::shared_ptr<VfsFile>> NCA::GetFiles() const { | 522 | std::vector<VirtualFile> NCA::GetFiles() const { |
| 520 | if (status != Loader::ResultStatus::Success) | 523 | if (status != Loader::ResultStatus::Success) { |
| 521 | return {}; | 524 | return {}; |
| 525 | } | ||
| 522 | return files; | 526 | return files; |
| 523 | } | 527 | } |
| 524 | 528 | ||
| 525 | std::vector<std::shared_ptr<VfsDirectory>> NCA::GetSubdirectories() const { | 529 | std::vector<VirtualDir> NCA::GetSubdirectories() const { |
| 526 | if (status != Loader::ResultStatus::Success) | 530 | if (status != Loader::ResultStatus::Success) { |
| 527 | return {}; | 531 | return {}; |
| 532 | } | ||
| 528 | return dirs; | 533 | return dirs; |
| 529 | } | 534 | } |
| 530 | 535 | ||
| @@ -532,7 +537,7 @@ std::string NCA::GetName() const { | |||
| 532 | return file->GetName(); | 537 | return file->GetName(); |
| 533 | } | 538 | } |
| 534 | 539 | ||
| 535 | std::shared_ptr<VfsDirectory> NCA::GetParentDirectory() const { | 540 | VirtualDir NCA::GetParentDirectory() const { |
| 536 | return file->GetContainingDirectory(); | 541 | return file->GetContainingDirectory(); |
| 537 | } | 542 | } |
| 538 | 543 | ||
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 69292232a..e9eccdea3 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -82,7 +82,7 @@ struct NCAHeader { | |||
| 82 | }; | 82 | }; |
| 83 | static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size."); | 83 | static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size."); |
| 84 | 84 | ||
| 85 | inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) { | 85 | inline bool IsDirectoryExeFS(const VirtualDir& pfs) { |
| 86 | // According to switchbrew, an exefs must only contain these two files: | 86 | // According to switchbrew, an exefs must only contain these two files: |
| 87 | return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; | 87 | return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; |
| 88 | } | 88 | } |
| @@ -104,10 +104,10 @@ public: | |||
| 104 | 104 | ||
| 105 | Loader::ResultStatus GetStatus() const; | 105 | Loader::ResultStatus GetStatus() const; |
| 106 | 106 | ||
| 107 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 107 | std::vector<VirtualFile> GetFiles() const override; |
| 108 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 108 | std::vector<VirtualDir> GetSubdirectories() const override; |
| 109 | std::string GetName() const override; | 109 | std::string GetName() const override; |
| 110 | std::shared_ptr<VfsDirectory> GetParentDirectory() const override; | 110 | VirtualDir GetParentDirectory() const override; |
| 111 | 111 | ||
| 112 | NCAContentType GetType() const; | 112 | NCAContentType GetType() const; |
| 113 | u64 GetTitleId() const; | 113 | u64 GetTitleId() const; |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index 2aff2708a..c52fafb6f 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 266 | cur_file->offset = file_partition_size; | 266 | cur_file->offset = file_partition_size; |
| 267 | file_partition_size += cur_file->size; | 267 | file_partition_size += cur_file->size; |
| 268 | cur_file->entry_offset = entry_offset; | 268 | cur_file->entry_offset = entry_offset; |
| 269 | entry_offset += sizeof(RomFSFileEntry) + | 269 | entry_offset += |
| 270 | Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4); | 270 | static_cast<u32>(sizeof(RomFSFileEntry) + |
| 271 | Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4)); | ||
| 271 | prev_file = cur_file; | 272 | prev_file = cur_file; |
| 272 | } | 273 | } |
| 273 | // Assign deferred parent/sibling ownership. | 274 | // Assign deferred parent/sibling ownership. |
| @@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 284 | for (const auto& it : directories) { | 285 | for (const auto& it : directories) { |
| 285 | cur_dir = it.second; | 286 | cur_dir = it.second; |
| 286 | cur_dir->entry_offset = entry_offset; | 287 | cur_dir->entry_offset = entry_offset; |
| 287 | entry_offset += sizeof(RomFSDirectoryEntry) + | 288 | entry_offset += |
| 288 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4); | 289 | static_cast<u32>(sizeof(RomFSDirectoryEntry) + |
| 290 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); | ||
| 289 | } | 291 | } |
| 290 | // Assign deferred parent/sibling ownership. | 292 | // Assign deferred parent/sibling ownership. |
| 291 | for (auto it = directories.rbegin(); it->second != root; ++it) { | 293 | for (auto it = directories.rbegin(); it->second != root; ++it) { |
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index dd779310f..a6101f1c0 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp | |||
| @@ -299,7 +299,7 @@ void IPSwitchCompiler::Parse() { | |||
| 299 | patch_text->GetName(), offset, Common::HexToString(replace)); | 299 | patch_text->GetName(), offset, Common::HexToString(replace)); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | patch.records.insert_or_assign(offset, std::move(replace)); | 302 | patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace)); |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | patches.push_back(std::move(patch)); | 305 | patches.push_back(std::move(patch)); |
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp index 2d1476e3a..3596541b2 100644 --- a/src/core/file_sys/nca_metadata.cpp +++ b/src/core/file_sys/nca_metadata.cpp | |||
| @@ -108,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const { | |||
| 108 | memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader)); | 108 | memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader)); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | auto offset = header.table_offset; | 111 | u64_le offset = header.table_offset; |
| 112 | 112 | ||
| 113 | for (const auto& rec : content_records) { | 113 | for (const auto& rec : content_records) { |
| 114 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); | 114 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); |
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp index 5990a2fd5..a65ec6798 100644 --- a/src/core/file_sys/nca_patch.cpp +++ b/src/core/file_sys/nca_patch.cpp | |||
| @@ -51,8 +51,8 @@ std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockTyp | |||
| 51 | low = mid + 1; | 51 | low = mid + 1; |
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| 54 | |||
| 55 | UNREACHABLE_MSG("Offset could not be found in BKTR block."); | 54 | UNREACHABLE_MSG("Offset could not be found in BKTR block."); |
| 55 | return {0, 0}; | ||
| 56 | } | 56 | } |
| 57 | } // Anonymous namespace | 57 | } // Anonymous namespace |
| 58 | 58 | ||
| @@ -191,7 +191,7 @@ bool BKTR::Resize(std::size_t new_size) { | |||
| 191 | return false; | 191 | return false; |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | std::shared_ptr<VfsDirectory> BKTR::GetContainingDirectory() const { | 194 | VirtualDir BKTR::GetContainingDirectory() const { |
| 195 | return base_romfs->GetContainingDirectory(); | 195 | return base_romfs->GetContainingDirectory(); |
| 196 | } | 196 | } |
| 197 | 197 | ||
diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h index 60c544f8e..503cf473e 100644 --- a/src/core/file_sys/nca_patch.h +++ b/src/core/file_sys/nca_patch.h | |||
| @@ -106,7 +106,7 @@ public: | |||
| 106 | 106 | ||
| 107 | bool Resize(std::size_t new_size) override; | 107 | bool Resize(std::size_t new_size) override; |
| 108 | 108 | ||
| 109 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 109 | VirtualDir GetContainingDirectory() const override; |
| 110 | 110 | ||
| 111 | bool IsWritable() const override; | 111 | bool IsWritable() const override; |
| 112 | 112 | ||
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index b9c09b456..7c3284df8 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/file_sys/common_funcs.h" | ||
| 15 | #include "core/file_sys/content_archive.h" | 16 | #include "core/file_sys/content_archive.h" |
| 16 | #include "core/file_sys/control_metadata.h" | 17 | #include "core/file_sys/control_metadata.h" |
| 17 | #include "core/file_sys/ips_layer.h" | 18 | #include "core/file_sys/ips_layer.h" |
| @@ -29,8 +30,7 @@ | |||
| 29 | namespace FileSys { | 30 | namespace FileSys { |
| 30 | namespace { | 31 | namespace { |
| 31 | 32 | ||
| 32 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; | 33 | constexpr u32 SINGLE_BYTE_MODULUS = 0x100; |
| 33 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | ||
| 34 | 34 | ||
| 35 | constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ | 35 | constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ |
| 36 | "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", | 36 | "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", |
| @@ -112,7 +112,10 @@ bool IsDirValidAndNonEmpty(const VirtualDir& dir) { | |||
| 112 | } | 112 | } |
| 113 | } // Anonymous namespace | 113 | } // Anonymous namespace |
| 114 | 114 | ||
| 115 | PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} | 115 | PatchManager::PatchManager(u64 title_id_, |
| 116 | const Service::FileSystem::FileSystemController& fs_controller_, | ||
| 117 | const ContentProvider& content_provider_) | ||
| 118 | : title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {} | ||
| 116 | 119 | ||
| 117 | PatchManager::~PatchManager() = default; | 120 | PatchManager::~PatchManager() = default; |
| 118 | 121 | ||
| @@ -128,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 128 | 131 | ||
| 129 | if (Settings::values.dump_exefs) { | 132 | if (Settings::values.dump_exefs) { |
| 130 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); | 133 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); |
| 131 | const auto dump_dir = | 134 | const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); |
| 132 | Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); | ||
| 133 | if (dump_dir != nullptr) { | 135 | if (dump_dir != nullptr) { |
| 134 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); | 136 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); |
| 135 | VfsRawCopyD(exefs, exefs_dir); | 137 | VfsRawCopyD(exefs, exefs_dir); |
| 136 | } | 138 | } |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 140 | |||
| 141 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 141 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 142 | const auto update_disabled = | 142 | const auto update_disabled = |
| 143 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); | 143 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); |
| 144 | 144 | ||
| 145 | // Game Updates | 145 | // Game Updates |
| 146 | const auto update_tid = GetUpdateTitleID(title_id); | 146 | const auto update_tid = GetUpdateTitleID(title_id); |
| 147 | const auto update = installed.GetEntry(update_tid, ContentRecordType::Program); | 147 | const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program); |
| 148 | 148 | ||
| 149 | if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr && | 149 | if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr && |
| 150 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | 150 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { |
| 151 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", | 151 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", |
| 152 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); | 152 | FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0))); |
| 153 | exefs = update->GetExeFS(); | 153 | exefs = update->GetExeFS(); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | // LayeredExeFS | 156 | // LayeredExeFS |
| 157 | const auto load_dir = | 157 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 158 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 159 | if (load_dir != nullptr && load_dir->GetSize() > 0) { | 158 | if (load_dir != nullptr && load_dir->GetSize() > 0) { |
| 160 | auto patch_dirs = load_dir->GetSubdirectories(); | 159 | auto patch_dirs = load_dir->GetSubdirectories(); |
| 161 | std::sort( | 160 | std::sort( |
| @@ -241,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st | |||
| 241 | if (Settings::values.dump_nso) { | 240 | if (Settings::values.dump_nso) { |
| 242 | LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, | 241 | LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, |
| 243 | title_id); | 242 | title_id); |
| 244 | const auto dump_dir = | 243 | const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); |
| 245 | Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); | ||
| 246 | if (dump_dir != nullptr) { | 244 | if (dump_dir != nullptr) { |
| 247 | const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); | 245 | const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); |
| 248 | const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); | 246 | const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); |
| @@ -254,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st | |||
| 254 | 252 | ||
| 255 | LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); | 253 | LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); |
| 256 | 254 | ||
| 257 | const auto load_dir = | 255 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 258 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 259 | if (load_dir == nullptr) { | 256 | if (load_dir == nullptr) { |
| 260 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 257 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 261 | return nso; | 258 | return nso; |
| @@ -298,8 +295,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const { | |||
| 298 | 295 | ||
| 299 | LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); | 296 | LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); |
| 300 | 297 | ||
| 301 | const auto load_dir = | 298 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 302 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 303 | if (load_dir == nullptr) { | 299 | if (load_dir == nullptr) { |
| 304 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 300 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 305 | return false; | 301 | return false; |
| @@ -313,8 +309,8 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const { | |||
| 313 | } | 309 | } |
| 314 | 310 | ||
| 315 | std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( | 311 | std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( |
| 316 | const Core::System& system, const BuildID& build_id_) const { | 312 | const BuildID& build_id_) const { |
| 317 | const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); | 313 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 318 | if (load_dir == nullptr) { | 314 | if (load_dir == nullptr) { |
| 319 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 315 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 320 | return {}; | 316 | return {}; |
| @@ -347,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( | |||
| 347 | return out; | 343 | return out; |
| 348 | } | 344 | } |
| 349 | 345 | ||
| 350 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { | 346 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, |
| 351 | const auto load_dir = | 347 | const Service::FileSystem::FileSystemController& fs_controller) { |
| 352 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | 348 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 353 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || | 349 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || |
| 354 | load_dir == nullptr || load_dir->GetSize() <= 0) { | 350 | load_dir == nullptr || load_dir->GetSize() <= 0) { |
| 355 | return; | 351 | return; |
| @@ -411,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 411 | const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}", | 407 | const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}", |
| 412 | title_id, static_cast<u8>(type)); | 408 | title_id, static_cast<u8>(type)); |
| 413 | 409 | ||
| 414 | if (type == ContentRecordType::Program || type == ContentRecordType::Data) | 410 | if (type == ContentRecordType::Program || type == ContentRecordType::Data) { |
| 415 | LOG_INFO(Loader, "{}", log_string); | 411 | LOG_INFO(Loader, "{}", log_string); |
| 416 | else | 412 | } else { |
| 417 | LOG_DEBUG(Loader, "{}", log_string); | 413 | LOG_DEBUG(Loader, "{}", log_string); |
| 414 | } | ||
| 418 | 415 | ||
| 419 | if (romfs == nullptr) | 416 | if (romfs == nullptr) { |
| 420 | return romfs; | 417 | return romfs; |
| 421 | 418 | } | |
| 422 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 423 | 419 | ||
| 424 | // Game Updates | 420 | // Game Updates |
| 425 | const auto update_tid = GetUpdateTitleID(title_id); | 421 | const auto update_tid = GetUpdateTitleID(title_id); |
| 426 | const auto update = installed.GetEntryRaw(update_tid, type); | 422 | const auto update = content_provider.GetEntryRaw(update_tid, type); |
| 427 | 423 | ||
| 428 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 424 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 429 | const auto update_disabled = | 425 | const auto update_disabled = |
| @@ -434,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 434 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && | 430 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && |
| 435 | new_nca->GetRomFS() != nullptr) { | 431 | new_nca->GetRomFS() != nullptr) { |
| 436 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", | 432 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", |
| 437 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); | 433 | FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0))); |
| 438 | romfs = new_nca->GetRomFS(); | 434 | romfs = new_nca->GetRomFS(); |
| 439 | } | 435 | } |
| 440 | } else if (!update_disabled && update_raw != nullptr) { | 436 | } else if (!update_disabled && update_raw != nullptr) { |
| @@ -447,7 +443,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 447 | } | 443 | } |
| 448 | 444 | ||
| 449 | // LayeredFS | 445 | // LayeredFS |
| 450 | ApplyLayeredFS(romfs, title_id, type); | 446 | ApplyLayeredFS(romfs, title_id, type, fs_controller); |
| 451 | 447 | ||
| 452 | return romfs; | 448 | return romfs; |
| 453 | } | 449 | } |
| @@ -458,12 +454,11 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 458 | } | 454 | } |
| 459 | 455 | ||
| 460 | std::map<std::string, std::string, std::less<>> out; | 456 | std::map<std::string, std::string, std::less<>> out; |
| 461 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 462 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 457 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 463 | 458 | ||
| 464 | // Game Updates | 459 | // Game Updates |
| 465 | const auto update_tid = GetUpdateTitleID(title_id); | 460 | const auto update_tid = GetUpdateTitleID(title_id); |
| 466 | PatchManager update{update_tid}; | 461 | PatchManager update{update_tid, fs_controller, content_provider}; |
| 467 | const auto metadata = update.GetControlMetadata(); | 462 | const auto metadata = update.GetControlMetadata(); |
| 468 | const auto& nacp = metadata.first; | 463 | const auto& nacp = metadata.first; |
| 469 | 464 | ||
| @@ -474,8 +469,8 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 474 | if (nacp != nullptr) { | 469 | if (nacp != nullptr) { |
| 475 | out.insert_or_assign(update_label, nacp->GetVersionString()); | 470 | out.insert_or_assign(update_label, nacp->GetVersionString()); |
| 476 | } else { | 471 | } else { |
| 477 | if (installed.HasEntry(update_tid, ContentRecordType::Program)) { | 472 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
| 478 | const auto meta_ver = installed.GetEntryVersion(update_tid); | 473 | const auto meta_ver = content_provider.GetEntryVersion(update_tid); |
| 479 | if (meta_ver.value_or(0) == 0) { | 474 | if (meta_ver.value_or(0) == 0) { |
| 480 | out.insert_or_assign(update_label, ""); | 475 | out.insert_or_assign(update_label, ""); |
| 481 | } else { | 476 | } else { |
| @@ -487,8 +482,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 487 | } | 482 | } |
| 488 | 483 | ||
| 489 | // General Mods (LayeredFS and IPS) | 484 | // General Mods (LayeredFS and IPS) |
| 490 | const auto mod_dir = | 485 | const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 491 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 492 | if (mod_dir != nullptr && mod_dir->GetSize() > 0) { | 486 | if (mod_dir != nullptr && mod_dir->GetSize() > 0) { |
| 493 | for (const auto& mod : mod_dir->GetSubdirectories()) { | 487 | for (const auto& mod : mod_dir->GetSubdirectories()) { |
| 494 | std::string types; | 488 | std::string types; |
| @@ -532,13 +526,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 532 | } | 526 | } |
| 533 | 527 | ||
| 534 | // DLC | 528 | // DLC |
| 535 | const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); | 529 | const auto dlc_entries = |
| 530 | content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); | ||
| 536 | std::vector<ContentProviderEntry> dlc_match; | 531 | std::vector<ContentProviderEntry> dlc_match; |
| 537 | dlc_match.reserve(dlc_entries.size()); | 532 | dlc_match.reserve(dlc_entries.size()); |
| 538 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), | 533 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), |
| 539 | [this, &installed](const ContentProviderEntry& entry) { | 534 | [this](const ContentProviderEntry& entry) { |
| 540 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && | 535 | return GetBaseTitleID(entry.title_id) == title_id && |
| 541 | installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; | 536 | content_provider.GetEntry(entry)->GetStatus() == |
| 537 | Loader::ResultStatus::Success; | ||
| 542 | }); | 538 | }); |
| 543 | if (!dlc_match.empty()) { | 539 | if (!dlc_match.empty()) { |
| 544 | // Ensure sorted so DLC IDs show in order. | 540 | // Ensure sorted so DLC IDs show in order. |
| @@ -559,19 +555,16 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 559 | } | 555 | } |
| 560 | 556 | ||
| 561 | std::optional<u32> PatchManager::GetGameVersion() const { | 557 | std::optional<u32> PatchManager::GetGameVersion() const { |
| 562 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 563 | const auto update_tid = GetUpdateTitleID(title_id); | 558 | const auto update_tid = GetUpdateTitleID(title_id); |
| 564 | if (installed.HasEntry(update_tid, ContentRecordType::Program)) { | 559 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
| 565 | return installed.GetEntryVersion(update_tid); | 560 | return content_provider.GetEntryVersion(update_tid); |
| 566 | } | 561 | } |
| 567 | 562 | ||
| 568 | return installed.GetEntryVersion(title_id); | 563 | return content_provider.GetEntryVersion(title_id); |
| 569 | } | 564 | } |
| 570 | 565 | ||
| 571 | PatchManager::Metadata PatchManager::GetControlMetadata() const { | 566 | PatchManager::Metadata PatchManager::GetControlMetadata() const { |
| 572 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | 567 | const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control); |
| 573 | |||
| 574 | const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control); | ||
| 575 | if (base_control_nca == nullptr) { | 568 | if (base_control_nca == nullptr) { |
| 576 | return {}; | 569 | return {}; |
| 577 | } | 570 | } |
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 1f28c6241..fb1853035 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h | |||
| @@ -17,8 +17,13 @@ namespace Core { | |||
| 17 | class System; | 17 | class System; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | namespace Service::FileSystem { | ||
| 21 | class FileSystemController; | ||
| 22 | } | ||
| 23 | |||
| 20 | namespace FileSys { | 24 | namespace FileSys { |
| 21 | 25 | ||
| 26 | class ContentProvider; | ||
| 22 | class NCA; | 27 | class NCA; |
| 23 | class NACP; | 28 | class NACP; |
| 24 | 29 | ||
| @@ -29,7 +34,9 @@ public: | |||
| 29 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; | 34 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; |
| 30 | using PatchVersionNames = std::map<std::string, std::string, std::less<>>; | 35 | using PatchVersionNames = std::map<std::string, std::string, std::less<>>; |
| 31 | 36 | ||
| 32 | explicit PatchManager(u64 title_id); | 37 | explicit PatchManager(u64 title_id_, |
| 38 | const Service::FileSystem::FileSystemController& fs_controller_, | ||
| 39 | const ContentProvider& content_provider_); | ||
| 33 | ~PatchManager(); | 40 | ~PatchManager(); |
| 34 | 41 | ||
| 35 | [[nodiscard]] u64 GetTitleID() const; | 42 | [[nodiscard]] u64 GetTitleID() const; |
| @@ -50,7 +57,7 @@ public: | |||
| 50 | 57 | ||
| 51 | // Creates a CheatList object with all | 58 | // Creates a CheatList object with all |
| 52 | [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( | 59 | [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( |
| 53 | const Core::System& system, const BuildID& build_id) const; | 60 | const BuildID& build_id) const; |
| 54 | 61 | ||
| 55 | // Currently tracked RomFS patches: | 62 | // Currently tracked RomFS patches: |
| 56 | // - Game Updates | 63 | // - Game Updates |
| @@ -80,6 +87,8 @@ private: | |||
| 80 | const std::string& build_id) const; | 87 | const std::string& build_id) const; |
| 81 | 88 | ||
| 82 | u64 title_id; | 89 | u64 title_id; |
| 90 | const Service::FileSystem::FileSystemController& fs_controller; | ||
| 91 | const ContentProvider& content_provider; | ||
| 83 | }; | 92 | }; |
| 84 | 93 | ||
| 85 | } // namespace FileSys | 94 | } // namespace FileSys |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index da01002d5..431302f55 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -105,7 +105,8 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { | |||
| 105 | // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. | 105 | // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. |
| 106 | return ContentRecordType::HtmlDocument; | 106 | return ContentRecordType::HtmlDocument; |
| 107 | default: | 107 | default: |
| 108 | UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type)); | 108 | UNREACHABLE_MSG("Invalid NCAContentType={:02X}", type); |
| 109 | return ContentRecordType{}; | ||
| 109 | } | 110 | } |
| 110 | } | 111 | } |
| 111 | 112 | ||
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 5b414b0f0..b08a1687a 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -67,18 +67,18 @@ public: | |||
| 67 | virtual void Refresh() = 0; | 67 | virtual void Refresh() = 0; |
| 68 | 68 | ||
| 69 | virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0; | 69 | virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0; |
| 70 | virtual bool HasEntry(ContentProviderEntry entry) const; | 70 | bool HasEntry(ContentProviderEntry entry) const; |
| 71 | 71 | ||
| 72 | virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0; | 72 | virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0; |
| 73 | 73 | ||
| 74 | virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0; | 74 | virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0; |
| 75 | virtual VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const; | 75 | VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const; |
| 76 | 76 | ||
| 77 | virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0; | 77 | virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0; |
| 78 | virtual VirtualFile GetEntryRaw(ContentProviderEntry entry) const; | 78 | VirtualFile GetEntryRaw(ContentProviderEntry entry) const; |
| 79 | 79 | ||
| 80 | virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0; | 80 | virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0; |
| 81 | virtual std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const; | 81 | std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const; |
| 82 | 82 | ||
| 83 | virtual std::vector<ContentProviderEntry> ListEntries() const; | 83 | virtual std::vector<ContentProviderEntry> ListEntries() const; |
| 84 | 84 | ||
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index e967a254e..f4e16e4be 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/file_sys/card_image.h" | 9 | #include "core/file_sys/card_image.h" |
| 10 | #include "core/file_sys/common_funcs.h" | ||
| 10 | #include "core/file_sys/content_archive.h" | 11 | #include "core/file_sys/content_archive.h" |
| 11 | #include "core/file_sys/nca_metadata.h" | 12 | #include "core/file_sys/nca_metadata.h" |
| 12 | #include "core/file_sys/patch_manager.h" | 13 | #include "core/file_sys/patch_manager.h" |
| @@ -37,14 +38,37 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) { | |||
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { | 40 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { |
| 40 | if (!updatable) | 41 | if (!updatable) { |
| 41 | return MakeResult<VirtualFile>(file); | 42 | return MakeResult<VirtualFile>(file); |
| 43 | } | ||
| 42 | 44 | ||
| 43 | const PatchManager patch_manager(current_process_title_id); | 45 | const PatchManager patch_manager{current_process_title_id, filesystem_controller, |
| 46 | content_provider}; | ||
| 44 | return MakeResult<VirtualFile>( | 47 | return MakeResult<VirtualFile>( |
| 45 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); | 48 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); |
| 46 | } | 49 | } |
| 47 | 50 | ||
| 51 | ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const { | ||
| 52 | auto nca = content_provider.GetEntry(title_id, type); | ||
| 53 | |||
| 54 | if (nca == nullptr) { | ||
| 55 | // TODO: Find the right error code to use here | ||
| 56 | return RESULT_UNKNOWN; | ||
| 57 | } | ||
| 58 | |||
| 59 | const PatchManager patch_manager{title_id, filesystem_controller, content_provider}; | ||
| 60 | |||
| 61 | return MakeResult<VirtualFile>( | ||
| 62 | patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type)); | ||
| 63 | } | ||
| 64 | |||
| 65 | ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex( | ||
| 66 | u64 title_id, u8 program_index, ContentRecordType type) const { | ||
| 67 | const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index); | ||
| 68 | |||
| 69 | return OpenPatchedRomFS(res_title_id, type); | ||
| 70 | } | ||
| 71 | |||
| 48 | ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, | 72 | ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, |
| 49 | ContentRecordType type) const { | 73 | ContentRecordType type) const { |
| 50 | const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type); | 74 | const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type); |
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index ec704dfa8..96dd0d578 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h | |||
| @@ -42,6 +42,10 @@ public: | |||
| 42 | 42 | ||
| 43 | void SetPackedUpdate(VirtualFile update_raw); | 43 | void SetPackedUpdate(VirtualFile update_raw); |
| 44 | [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; | 44 | [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; |
| 45 | [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id, | ||
| 46 | ContentRecordType type) const; | ||
| 47 | [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex( | ||
| 48 | u64 title_id, u8 program_index, ContentRecordType type) const; | ||
| 45 | [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, | 49 | [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, |
| 46 | ContentRecordType type) const; | 50 | ContentRecordType type) const; |
| 47 | 51 | ||
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index ba4efee3a..b7bfe0928 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -70,7 +70,8 @@ std::string SaveDataAttribute::DebugInfo() const { | |||
| 70 | static_cast<u8>(rank), index); | 70 | static_cast<u8>(rank), index); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) { | 73 | SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_) |
| 74 | : dir{std::move(save_directory_)}, system{system_} { | ||
| 74 | // Delete all temporary storages | 75 | // Delete all temporary storages |
| 75 | // On hardware, it is expected that temporary storage be empty at first use. | 76 | // On hardware, it is expected that temporary storage be empty at first use. |
| 76 | dir->DeleteSubdirectoryRecursive("temp"); | 77 | dir->DeleteSubdirectoryRecursive("temp"); |
| @@ -83,7 +84,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space, | |||
| 83 | PrintSaveDataAttributeWarnings(meta); | 84 | PrintSaveDataAttributeWarnings(meta); |
| 84 | 85 | ||
| 85 | const auto save_directory = | 86 | const auto save_directory = |
| 86 | GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 87 | GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 87 | 88 | ||
| 88 | auto out = dir->CreateDirectoryRelative(save_directory); | 89 | auto out = dir->CreateDirectoryRelative(save_directory); |
| 89 | 90 | ||
| @@ -100,7 +101,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, | |||
| 100 | const SaveDataAttribute& meta) const { | 101 | const SaveDataAttribute& meta) const { |
| 101 | 102 | ||
| 102 | const auto save_directory = | 103 | const auto save_directory = |
| 103 | GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 104 | GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 104 | 105 | ||
| 105 | auto out = dir->GetDirectoryRelative(save_directory); | 106 | auto out = dir->GetDirectoryRelative(save_directory); |
| 106 | 107 | ||
| @@ -135,13 +136,14 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { | |||
| 135 | } | 136 | } |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | 139 | std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space, |
| 139 | u128 user_id, u64 save_id) { | 140 | SaveDataType type, u64 title_id, u128 user_id, |
| 141 | u64 save_id) { | ||
| 140 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 142 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 141 | // be interpreted as the title id of the current process. | 143 | // be interpreted as the title id of the current process. |
| 142 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { | 144 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { |
| 143 | if (title_id == 0) { | 145 | if (title_id == 0) { |
| 144 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 146 | title_id = system.CurrentProcess()->GetTitleID(); |
| 145 | } | 147 | } |
| 146 | } | 148 | } |
| 147 | 149 | ||
| @@ -167,7 +169,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 167 | 169 | ||
| 168 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | 170 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, |
| 169 | u128 user_id) const { | 171 | u128 user_id) const { |
| 170 | const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 172 | const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 171 | const auto dir = GetOrCreateDirectoryRelative(this->dir, path); | 173 | const auto dir = GetOrCreateDirectoryRelative(this->dir, path); |
| 172 | 174 | ||
| 173 | const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME); | 175 | const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME); |
| @@ -182,7 +184,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | |||
| 182 | 184 | ||
| 183 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 185 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, |
| 184 | SaveDataSize new_value) const { | 186 | SaveDataSize new_value) const { |
| 185 | const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 187 | const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 186 | const auto dir = GetOrCreateDirectoryRelative(this->dir, path); | 188 | const auto dir = GetOrCreateDirectoryRelative(this->dir, path); |
| 187 | 189 | ||
| 188 | const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME); | 190 | const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME); |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index 6625bbbd8..17f774baa 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -12,6 +12,10 @@ | |||
| 12 | #include "core/file_sys/vfs.h" | 12 | #include "core/file_sys/vfs.h" |
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | 14 | ||
| 15 | namespace Core { | ||
| 16 | class System; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace FileSys { | 19 | namespace FileSys { |
| 16 | 20 | ||
| 17 | enum class SaveDataSpaceId : u8 { | 21 | enum class SaveDataSpaceId : u8 { |
| @@ -84,7 +88,7 @@ struct SaveDataSize { | |||
| 84 | /// File system interface to the SaveData archive | 88 | /// File system interface to the SaveData archive |
| 85 | class SaveDataFactory { | 89 | class SaveDataFactory { |
| 86 | public: | 90 | public: |
| 87 | explicit SaveDataFactory(VirtualDir dir); | 91 | explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_); |
| 88 | ~SaveDataFactory(); | 92 | ~SaveDataFactory(); |
| 89 | 93 | ||
| 90 | ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; | 94 | ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; |
| @@ -93,8 +97,8 @@ public: | |||
| 93 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; | 97 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; |
| 94 | 98 | ||
| 95 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | 99 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); |
| 96 | static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, | 100 | static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type, |
| 97 | u128 user_id, u64 save_id); | 101 | u64 title_id, u128 user_id, u64 save_id); |
| 98 | 102 | ||
| 99 | SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; | 103 | SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; |
| 100 | void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 104 | void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, |
| @@ -102,6 +106,7 @@ public: | |||
| 102 | 106 | ||
| 103 | private: | 107 | private: |
| 104 | VirtualDir dir; | 108 | VirtualDir dir; |
| 109 | Core::System& system; | ||
| 105 | }; | 110 | }; |
| 106 | 111 | ||
| 107 | } // namespace FileSys | 112 | } // namespace FileSys |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index aab957bf2..c05735ddd 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -19,41 +19,9 @@ | |||
| 19 | #include "core/loader/loader.h" | 19 | #include "core/loader/loader.h" |
| 20 | 20 | ||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | namespace { | ||
| 23 | void SetTicketKeys(const std::vector<VirtualFile>& files) { | ||
| 24 | auto& keys = Core::Crypto::KeyManager::Instance(); | ||
| 25 | 22 | ||
| 26 | for (const auto& ticket_file : files) { | 23 | NSP::NSP(VirtualFile file_, std::size_t program_index) |
| 27 | if (ticket_file == nullptr) { | 24 | : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success}, |
| 28 | continue; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (ticket_file->GetExtension() != "tik") { | ||
| 32 | continue; | ||
| 33 | } | ||
| 34 | |||
| 35 | if (ticket_file->GetSize() < | ||
| 36 | Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) { | ||
| 37 | continue; | ||
| 38 | } | ||
| 39 | |||
| 40 | Core::Crypto::Key128 key{}; | ||
| 41 | ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); | ||
| 42 | |||
| 43 | // We get the name without the extension in order to create the rights ID. | ||
| 44 | std::string name_only(ticket_file->GetName()); | ||
| 45 | name_only.erase(name_only.size() - 4); | ||
| 46 | |||
| 47 | const auto rights_id_raw = Common::HexStringToArray<16>(name_only); | ||
| 48 | u128 rights_id; | ||
| 49 | std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128)); | ||
| 50 | keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } // Anonymous namespace | ||
| 54 | |||
| 55 | NSP::NSP(VirtualFile file_) | ||
| 56 | : file(std::move(file_)), status{Loader::ResultStatus::Success}, | ||
| 57 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { | 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { |
| 58 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { | 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { |
| 59 | status = pfs->GetStatus(); | 27 | status = pfs->GetStatus(); |
| @@ -178,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType | |||
| 178 | if (extracted) | 146 | if (extracted) |
| 179 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); | 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); |
| 180 | 148 | ||
| 181 | const auto title_id_iter = ncas.find(title_id); | 149 | const auto title_id_iter = ncas.find(title_id + program_index); |
| 182 | if (title_id_iter == ncas.end()) | 150 | if (title_id_iter == ncas.end()) |
| 183 | return nullptr; | 151 | return nullptr; |
| 184 | 152 | ||
| @@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const { | |||
| 232 | return file->GetContainingDirectory(); | 200 | return file->GetContainingDirectory(); |
| 233 | } | 201 | } |
| 234 | 202 | ||
| 203 | void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) { | ||
| 204 | for (const auto& ticket_file : files) { | ||
| 205 | if (ticket_file == nullptr) { | ||
| 206 | continue; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (ticket_file->GetExtension() != "tik") { | ||
| 210 | continue; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (ticket_file->GetSize() < | ||
| 214 | Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) { | ||
| 215 | continue; | ||
| 216 | } | ||
| 217 | |||
| 218 | Core::Crypto::Key128 key{}; | ||
| 219 | ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); | ||
| 220 | |||
| 221 | // We get the name without the extension in order to create the rights ID. | ||
| 222 | std::string name_only(ticket_file->GetName()); | ||
| 223 | name_only.erase(name_only.size() - 4); | ||
| 224 | |||
| 225 | const auto rights_id_raw = Common::HexStringToArray<16>(name_only); | ||
| 226 | u128 rights_id; | ||
| 227 | std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128)); | ||
| 228 | keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 235 | void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) { | 232 | void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) { |
| 236 | exefs = pfs; | 233 | exefs = pfs; |
| 237 | 234 | ||
| @@ -286,12 +283,31 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 286 | } | 283 | } |
| 287 | 284 | ||
| 288 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); | 285 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); |
| 286 | |||
| 289 | if (next_nca->GetType() == NCAContentType::Program) { | 287 | if (next_nca->GetType() == NCAContentType::Program) { |
| 290 | program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); | 288 | program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); |
| 291 | } | 289 | } |
| 292 | if (next_nca->GetStatus() == Loader::ResultStatus::Success || | 290 | |
| 293 | (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && | 291 | if (next_nca->GetStatus() != Loader::ResultStatus::Success && |
| 294 | (next_nca->GetTitleId() & 0x800) != 0)) { | 292 | next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { |
| 293 | continue; | ||
| 294 | } | ||
| 295 | |||
| 296 | // If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the | ||
| 297 | // BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA. | ||
| 298 | if ((cnmt.GetTitleID() & 0x800) != 0 || | ||
| 299 | next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | ||
| 300 | // If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and | ||
| 301 | // 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular | ||
| 302 | // update NCA. | ||
| 303 | if ((next_nca->GetTitleId() & 0x7FF) != 0 && | ||
| 304 | (next_nca->GetTitleId() & 0x800) == 0) { | ||
| 305 | ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = | ||
| 306 | std::move(next_nca); | ||
| 307 | } else { | ||
| 308 | ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca); | ||
| 309 | } | ||
| 310 | } else { | ||
| 295 | ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca); | 311 | ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca); |
| 296 | } | 312 | } |
| 297 | } | 313 | } |
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index 2db5e46b8..54581a6f3 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -27,7 +27,7 @@ enum class ContentRecordType : u8; | |||
| 27 | 27 | ||
| 28 | class NSP : public ReadOnlyVfsDirectory { | 28 | class NSP : public ReadOnlyVfsDirectory { |
| 29 | public: | 29 | public: |
| 30 | explicit NSP(VirtualFile file); | 30 | explicit NSP(VirtualFile file, std::size_t program_index = 0); |
| 31 | ~NSP() override; | 31 | ~NSP() override; |
| 32 | 32 | ||
| 33 | Loader::ResultStatus GetStatus() const; | 33 | Loader::ResultStatus GetStatus() const; |
| @@ -63,11 +63,14 @@ public: | |||
| 63 | VirtualDir GetParentDirectory() const override; | 63 | VirtualDir GetParentDirectory() const override; |
| 64 | 64 | ||
| 65 | private: | 65 | private: |
| 66 | void SetTicketKeys(const std::vector<VirtualFile>& files); | ||
| 66 | void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files); | 67 | void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files); |
| 67 | void ReadNCAs(const std::vector<VirtualFile>& files); | 68 | void ReadNCAs(const std::vector<VirtualFile>& files); |
| 68 | 69 | ||
| 69 | VirtualFile file; | 70 | VirtualFile file; |
| 70 | 71 | ||
| 72 | const std::size_t program_index; | ||
| 73 | |||
| 71 | bool extracted = false; | 74 | bool extracted = false; |
| 72 | Loader::ResultStatus status; | 75 | Loader::ResultStatus status; |
| 73 | std::map<u64, Loader::ResultStatus> program_status; | 76 | std::map<u64, Loader::ResultStatus> program_status; |
diff --git a/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp b/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp index 69d62ce8f..29ef110a6 100644 --- a/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp +++ b/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp | |||
| @@ -6,191 +6,384 @@ | |||
| 6 | 6 | ||
| 7 | namespace FileSys::SystemArchive::SharedFontData { | 7 | namespace FileSys::SystemArchive::SharedFontData { |
| 8 | 8 | ||
| 9 | const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED{{ | 9 | const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED{{ |
| 10 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x03, 0x00, 0x70, 0x44, 0x53, 0x49, 0x47, | 10 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, 0x4F, 0x53, 0x2F, 0x32, |
| 11 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x4f, 0x53, 0x2f, 0x32, | 11 | 0x34, 0x00, 0x1E, 0x26, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70, |
| 12 | 0x33, 0x86, 0x1d, 0x9b, 0x00, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, | 12 | 0xC1, 0xE7, 0xC8, 0xF3, 0x00, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x01, 0x72, 0x63, 0x76, 0x74, 0x20, |
| 13 | 0xc2, 0x06, 0x20, 0xde, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x76, 0x74, 0x20, | 13 | 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6D, |
| 14 | 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2c, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6d, | 14 | 0x06, 0x59, 0x9C, 0x37, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70, |
| 15 | 0x06, 0x59, 0x9c, 0x37, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70, | 15 | 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6C, 0x79, 0x66, |
| 16 | 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0b, 0x64, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, | 16 | 0x50, 0x0B, 0xEA, 0xFA, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x0F, 0x04, 0x68, 0x65, 0x61, 0x64, |
| 17 | 0x10, 0x31, 0x88, 0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x04, 0x64, 0x68, 0x65, 0x61, 0x64, | 17 | 0x18, 0x65, 0x81, 0x09, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61, |
| 18 | 0x15, 0x9d, 0xef, 0x91, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61, | 18 | 0x09, 0x88, 0x03, 0x86, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6D, 0x74, 0x78, |
| 19 | 0x09, 0x60, 0x03, 0x71, 0x00, 0x00, 0x01, 0x34, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, | 19 | 0x0A, 0xF0, 0x01, 0x94, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x42, 0x6C, 0x6F, 0x63, 0x61, |
| 20 | 0x0d, 0x2e, 0x03, 0xa7, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x26, 0x6c, 0x6f, 0x63, 0x61, | 20 | 0x34, 0x80, 0x30, 0x6E, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00, 0x3A, 0x6D, 0x61, 0x78, 0x70, |
| 21 | 0x05, 0xc0, 0x04, 0x6c, 0x00, 0x00, 0x08, 0x98, 0x00, 0x00, 0x00, 0x1e, 0x6d, 0x61, 0x78, 0x70, | 21 | 0x02, 0x2C, 0x00, 0x72, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x61, 0x6D, 0x65, |
| 22 | 0x02, 0x1c, 0x00, 0x5f, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, | 22 | 0xDB, 0xC5, 0x42, 0x4D, 0x00, 0x00, 0x14, 0x54, 0x00, 0x00, 0x01, 0xFE, 0x70, 0x6F, 0x73, 0x74, |
| 23 | 0x7c, 0xe0, 0x84, 0x5c, 0x00, 0x00, 0x08, 0xb8, 0x00, 0x00, 0x02, 0x09, 0x70, 0x6f, 0x73, 0x74, | 23 | 0xF4, 0xB4, 0xAC, 0xAB, 0x00, 0x00, 0x16, 0x54, 0x00, 0x00, 0x01, 0x2A, 0x70, 0x72, 0x65, 0x70, |
| 24 | 0x47, 0x4e, 0x74, 0x19, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x00, 0x9e, 0x70, 0x72, 0x65, 0x70, | 24 | 0x1C, 0xFC, 0x7D, 0x9C, 0x00, 0x00, 0x04, 0xF4, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00, |
| 25 | 0x1c, 0xfc, 0x7d, 0x9c, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00, | 25 | 0x00, 0x01, 0x00, 0x00, 0xC9, 0x16, 0x5B, 0x71, 0x5F, 0x0F, 0x3C, 0xF5, 0x00, 0x0B, 0x04, 0x00, |
| 26 | 0x00, 0x01, 0x00, 0x00, 0x7c, 0xc7, 0xb1, 0x63, 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x1b, 0x03, 0xe8, | 26 | 0x00, 0x00, 0x00, 0x00, 0xD9, 0x44, 0x2F, 0x5D, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x02, 0x0D, 0xA7, |
| 27 | 0x00, 0x00, 0x00, 0x00, 0xd9, 0x44, 0x2f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x45, 0x7b, 0x69, | 27 | 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, |
| 28 | 0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, | 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x9A, 0xFF, 0x80, 0x02, 0x00, 0x04, 0x00, |
| 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x84, 0xff, 0x83, 0x01, 0xf4, 0x03, 0xe8, | 29 | 0x00, 0x00, 0x00, 0x00, 0x03, 0xEC, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 30 | 0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x71, |
| 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x5e, | 31 | 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, |
| 32 | 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, | 32 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xC4, 0x01, 0x90, 0x00, 0x05, |
| 33 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x74, 0x01, 0x90, 0x00, 0x05, | 33 | 0x00, 0x04, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00, 0x01, 0x26, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00, |
| 34 | 0x00, 0x04, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x1f, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00, | 34 | 0x03, 0xDA, 0x00, 0x68, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 35 | 0x03, 0xc3, 0x00, 0x66, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 37 | 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xc0, 0x00, 0x00, 0xe0, 0xe9, 0x03, 0x84, 0xff, 0x83, | 36 | 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xC0, 0x00, 0x0D, 0xE0, 0xF0, 0x03, 0x9A, 0xFF, 0x80, |
| 38 | 0x01, 0xf4, 0x02, 0xee, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, | 37 | 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, |
| 39 | 0x02, 0xbc, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 38 | 0x02, 0xCD, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0x04, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00, |
| 40 | 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x03, 0xe8, 0x00, 0xeb, 0x01, 0x21, 0x00, 0xff, | 39 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, |
| 41 | 0x00, 0xff, 0x01, 0x3d, 0x01, 0x17, 0x00, 0x42, 0x00, 0x1c, 0x00, 0x3e, 0x00, 0x17, 0x00, 0x00, | 40 | 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, |
| 42 | 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x68, 0x00, 0x01, 0x00, 0x00, | 41 | 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, |
| 43 | 0x00, 0x00, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x06, 0x00, 0x4c, | 42 | 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, |
| 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 43 | 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, |
| 44 | 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10, | ||
| 45 | 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA9, 0xE0, 0xB4, | ||
| 46 | 0xE0, 0xE9, 0xE0, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA0, | ||
| 47 | 0xE0, 0xB3, 0xE0, 0xE0, 0xE0, 0xEF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xF5, 0xFF, 0xE3, 0x1F, 0x64, | ||
| 48 | 0x1F, 0x5B, 0x1F, 0x30, 0x1F, 0x2B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, | ||
| 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, | ||
| 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, | ||
| 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 46 | 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0a, | ||
| 49 | 0x00, 0x08, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe9, 0xff, 0xff, | ||
| 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe0, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf5, | ||
| 51 | 0xff, 0xe3, 0x1f, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 52 | 0xb8, 0x00, 0x00, 0x2c, 0x4b, 0xb8, 0x00, 0x09, 0x50, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0xb8, | ||
| 53 | 0x01, 0xff, 0x85, 0xb8, 0x00, 0x44, 0x1d, 0xb9, 0x00, 0x09, 0x00, 0x03, 0x5f, 0x5e, 0x2d, 0xb8, | ||
| 54 | 0x00, 0x01, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, 0x60, 0x2d, 0xb8, 0x00, 0x02, 0x2c, | ||
| 55 | 0xb8, 0x00, 0x01, 0x2a, 0x21, 0x2d, 0xb8, 0x00, 0x03, 0x2c, 0x20, 0x46, 0xb0, 0x03, 0x25, 0x46, | ||
| 56 | 0x52, 0x58, 0x23, 0x59, 0x20, 0x8a, 0x20, 0x8a, 0x49, 0x64, 0x8a, 0x20, 0x46, 0x20, 0x68, 0x61, | ||
| 57 | 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8a, 0x59, 0x2f, | ||
| 58 | 0x20, 0xb0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x1b, | ||
| 59 | 0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x65, 0x59, 0x59, 0x3a, 0x2d, 0xb8, 0x00, | ||
| 60 | 0x04, 0x2c, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8a, 0x59, 0x20, 0x46, 0x20, | ||
| 61 | 0x6a, 0x61, 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x6a, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8a, 0x59, | ||
| 62 | 0x2f, 0xfd, 0x2d, 0xb8, 0x00, 0x05, 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58, | ||
| 63 | 0xb0, 0x80, 0x44, 0x1b, 0xb0, 0x40, 0x44, 0x59, 0x1b, 0x21, 0x21, 0x20, 0x45, 0xb0, 0xc0, 0x50, | ||
| 64 | 0x58, 0xb0, 0xc0, 0x44, 0x1b, 0x21, 0x59, 0x59, 0x2d, 0xb8, 0x00, 0x06, 0x2c, 0x20, 0x20, 0x45, | ||
| 65 | 0x69, 0x44, 0xb0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xb0, 0x01, 0x60, 0x2d, | ||
| 66 | 0xb8, 0x00, 0x07, 0x2c, 0xb8, 0x00, 0x06, 0x2a, 0x2d, 0xb8, 0x00, 0x08, 0x2c, 0x4b, 0x20, 0xb0, | ||
| 67 | 0x03, 0x26, 0x53, 0x58, 0xb0, 0x40, 0x1b, 0xb0, 0x00, 0x59, 0x8a, 0x8a, 0x20, 0xb0, 0x03, 0x26, | ||
| 68 | 0x53, 0x58, 0x23, 0x21, 0xb0, 0x80, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26, | ||
| 69 | 0x53, 0x58, 0x23, 0x21, 0xb8, 0x00, 0xc0, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, | ||
| 70 | 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x00, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, | ||
| 71 | 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x40, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, | ||
| 72 | 0xb8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x03, 0x25, 0x45, 0xb8, 0x01, 0x80, 0x50, 0x58, 0x23, | ||
| 73 | 0x21, 0xb8, 0x01, 0x80, 0x23, 0x21, 0x1b, 0xb0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59, | ||
| 74 | 0x1b, 0x21, 0x59, 0x44, 0x2d, 0xb8, 0x00, 0x09, 0x2c, 0x4b, 0x53, 0x58, 0x45, 0x44, 0x1b, 0x21, | ||
| 75 | 0x21, 0x59, 0x2d, 0x00, 0xb8, 0x00, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, | ||
| 76 | 0x2b, 0xb8, 0x00, 0x00, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, | ||
| 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x06, | ||
| 78 | 0x00, 0x00, 0x35, 0x01, 0x33, 0x15, 0x01, 0x23, 0x35, 0x03, 0x52, 0x94, 0xfc, 0xa6, 0x8c, 0x90, | ||
| 79 | 0x03, 0x58, 0x86, 0xfc, 0xa0, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x00, 0xeb, 0x00, 0xcc, 0x02, 0xfb, | ||
| 80 | 0x03, 0x1e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x33, 0x13, 0x23, 0x27, 0x23, 0x07, 0x23, | ||
| 81 | 0x13, 0x17, 0x07, 0x06, 0x15, 0x33, 0x27, 0x07, 0x01, 0xbc, 0x6d, 0xd2, 0x7c, 0x26, 0xcc, 0x26, | ||
| 82 | 0x7c, 0xd1, 0x35, 0x40, 0x02, 0x89, 0x45, 0x02, 0x03, 0x1e, 0xfd, 0xae, 0x77, 0x77, 0x02, 0x52, | ||
| 83 | 0x9b, 0xcc, 0x08, 0x04, 0xda, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x21, 0x00, 0xcc, 0x02, 0xc5, | ||
| 84 | 0x03, 0x1e, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x00, 0x25, 0x11, 0x33, 0x32, 0x1e, 0x02, | ||
| 85 | 0x15, 0x14, 0x0e, 0x02, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x2b, 0x01, 0x13, 0x33, 0x32, | ||
| 86 | 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x1d, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b, | ||
| 87 | 0x01, 0x15, 0x01, 0x21, 0xea, 0x25, 0x3f, 0x2e, 0x1a, 0x0e, 0x15, 0x1b, 0x0e, 0x2d, 0x2d, 0x1a, | ||
| 88 | 0x2e, 0x3f, 0x25, 0xf8, 0x76, 0x62, 0x20, 0x2a, 0x28, 0x22, 0x62, 0x76, 0x10, 0x18, 0x11, 0x09, | ||
| 89 | 0x22, 0x22, 0x74, 0xcc, 0x02, 0x52, 0x18, 0x2b, 0x3c, 0x24, 0x1d, 0x1f, 0x17, 0x17, 0x14, 0x0f, | ||
| 90 | 0x48, 0x2f, 0x24, 0x3f, 0x2e, 0x1a, 0x01, 0x5b, 0x29, 0x20, 0x20, 0x2b, 0x94, 0xf8, 0x0e, 0x16, | ||
| 91 | 0x1c, 0x0e, 0x1f, 0x31, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7, | ||
| 92 | 0x03, 0x1e, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x33, 0x17, 0x37, 0x33, 0x03, 0x13, 0x23, 0x27, 0x07, | ||
| 93 | 0x23, 0x13, 0x03, 0x01, 0x04, 0x86, 0x69, 0x69, 0x86, 0xa3, 0xa8, 0x88, 0x6c, 0x6c, 0x88, 0xa8, | ||
| 94 | 0xa3, 0x03, 0x1e, 0xcb, 0xcb, 0xfe, 0xda, 0xfe, 0xd4, 0xcf, 0xcf, 0x01, 0x2c, 0x01, 0x26, 0x00, | ||
| 95 | 0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7, 0x03, 0x1e, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x03, | ||
| 96 | 0x33, 0x17, 0x32, 0x15, 0x1e, 0x01, 0x15, 0x1b, 0x01, 0x33, 0x03, 0x15, 0x23, 0x35, 0x01, 0xb8, | ||
| 97 | 0xb9, 0x7e, 0x01, 0x01, 0x01, 0x03, 0x70, 0x75, 0x7f, 0xb9, 0x76, 0x01, 0xa3, 0x01, 0x7b, 0x01, | ||
| 98 | 0x01, 0x01, 0x05, 0x02, 0xff, 0x00, 0x01, 0x0a, 0xfe, 0x85, 0xd7, 0xd7, 0x00, 0x01, 0x01, 0x3d, | ||
| 99 | 0x00, 0xcc, 0x02, 0xa9, 0x03, 0x1e, 0x00, 0x06, 0x00, 0x00, 0x25, 0x11, 0x33, 0x11, 0x33, 0x15, | ||
| 100 | 0x21, 0x01, 0x3d, 0x75, 0xf7, 0xfe, 0x94, 0xcc, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00, | ||
| 101 | 0x00, 0x02, 0x01, 0x17, 0x00, 0xbc, 0x02, 0xcf, 0x03, 0x0e, 0x00, 0x15, 0x00, 0x21, 0x00, 0x00, | ||
| 102 | 0x25, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x1d, 0x01, 0x0e, 0x03, 0x1d, 0x01, 0x17, 0x15, 0x23, 0x27, | ||
| 103 | 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x01, 0x17, | ||
| 104 | 0xf4, 0x27, 0x40, 0x2e, 0x19, 0x01, 0x1f, 0x24, 0x1e, 0x78, 0x7d, 0x6a, 0x5c, 0x75, 0x76, 0x72, | ||
| 105 | 0x12, 0x19, 0x11, 0x08, 0x26, 0x26, 0x6a, 0xbc, 0x02, 0x52, 0x1d, 0x31, 0x42, 0x25, 0x16, 0x18, | ||
| 106 | 0x32, 0x2a, 0x1b, 0x02, 0x01, 0xef, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x10, 0x1a, 0x1e, 0x0f, 0x23, | ||
| 107 | 0x36, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0x00, 0xbc, 0x03, 0xa4, 0x03, 0x0e, 0x00, 0x0a, | ||
| 108 | 0x00, 0x11, 0x00, 0x00, 0x13, 0x35, 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01, | ||
| 109 | 0x11, 0x33, 0x11, 0x33, 0x15, 0x21, 0x42, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b, 0xfe, 0x53, 0x01, | ||
| 110 | 0x15, 0xfe, 0xeb, 0x01, 0xf7, 0x75, 0xf6, 0xfe, 0x95, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62, | ||
| 111 | 0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c, | ||
| 112 | 0x00, 0xbc, 0x03, 0xca, 0x03, 0x0e, 0x00, 0x0a, 0x00, 0x21, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35, | ||
| 113 | 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15, | ||
| 114 | 0x14, 0x06, 0x07, 0x0e, 0x03, 0x15, 0x17, 0x15, 0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, | ||
| 115 | 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01, 0x15, 0x1c, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b, | ||
| 116 | 0xfe, 0x53, 0x01, 0x15, 0xfe, 0xeb, 0x01, 0xf7, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x01, | ||
| 117 | 0x0d, 0x0e, 0x0a, 0x78, 0x7d, 0x69, 0x5c, 0x75, 0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14, | ||
| 118 | 0x1d, 0x13, 0x69, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62, 0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02, | ||
| 119 | 0x52, 0x1d, 0x31, 0x42, 0x25, 0x2b, 0x44, 0x1d, 0x01, 0x08, 0x09, 0x07, 0x01, 0xf1, 0x06, 0xd7, | ||
| 120 | 0xd7, 0x01, 0x3f, 0x11, 0x19, 0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x02, 0x00, 0x3e, | ||
| 121 | 0x00, 0xb3, 0x03, 0xa8, 0x03, 0x17, 0x00, 0x3a, 0x00, 0x41, 0x00, 0x00, 0x13, 0x34, 0x3e, 0x02, | ||
| 122 | 0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15, | ||
| 123 | 0x14, 0x16, 0x15, 0x1e, 0x05, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x33, 0x1e, | ||
| 124 | 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x04, 0x35, 0x01, 0x11, 0x33, 0x11, 0x33, 0x15, | ||
| 125 | 0x21, 0x50, 0x24, 0x3b, 0x4a, 0x27, 0x28, 0x4b, 0x39, 0x22, 0x73, 0x01, 0x01, 0x08, 0x2b, 0x29, | ||
| 126 | 0x10, 0x20, 0x19, 0x0f, 0x01, 0x0b, 0x35, 0x41, 0x46, 0x3b, 0x25, 0x23, 0x3a, 0x4b, 0x27, 0x2b, | ||
| 127 | 0x50, 0x3f, 0x26, 0x74, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x11, 0x2c, 0x42, 0x4d, 0x42, 0x2c, | ||
| 128 | 0x01, 0xef, 0x73, 0xf6, 0xfe, 0x97, 0x02, 0x70, 0x2a, 0x3f, 0x2a, 0x14, 0x18, 0x2e, 0x44, 0x2c, | ||
| 129 | 0x02, 0x03, 0x01, 0x27, 0x27, 0x07, 0x10, 0x1a, 0x12, 0x02, 0x0b, 0x02, 0x1f, 0x22, 0x19, 0x17, | ||
| 130 | 0x27, 0x3f, 0x34, 0x2c, 0x3e, 0x28, 0x13, 0x1a, 0x32, 0x48, 0x2e, 0x30, 0x30, 0x06, 0x0f, 0x1a, | ||
| 131 | 0x13, 0x21, 0x27, 0x1e, 0x1b, 0x29, 0x3e, 0x31, 0xfe, 0x4c, 0x02, 0x53, 0xfe, 0x10, 0x63, 0x00, | ||
| 132 | 0x00, 0x03, 0x00, 0x17, 0x00, 0xb3, 0x03, 0xce, 0x03, 0x17, 0x00, 0x38, 0x00, 0x4f, 0x00, 0x5d, | ||
| 133 | 0x00, 0x00, 0x13, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x23, 0x2e, | ||
| 134 | 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x14, 0x1e, 0x04, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, | ||
| 135 | 0x02, 0x35, 0x33, 0x1e, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x03, 0x35, | ||
| 136 | 0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x30, 0x0e, 0x02, 0x31, 0x17, 0x15, | ||
| 137 | 0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01, | ||
| 138 | 0x15, 0x2a, 0x24, 0x3a, 0x4a, 0x26, 0x29, 0x4b, 0x39, 0x23, 0x73, 0x01, 0x01, 0x08, 0x2a, 0x2a, | ||
| 139 | 0x10, 0x1f, 0x1a, 0x10, 0x2c, 0x42, 0x4d, 0x42, 0x2c, 0x23, 0x39, 0x4b, 0x27, 0x2b, 0x51, 0x3f, | ||
| 140 | 0x27, 0x75, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x10, 0x1f, 0x1c, 0x25, 0x53, 0x47, 0x2e, 0x01, | ||
| 141 | 0xed, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x0c, 0x0e, 0x0c, 0x78, 0x7d, 0x68, 0x5d, 0x75, | ||
| 142 | 0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14, 0x1d, 0x13, 0x69, 0x02, 0x71, 0x2a, 0x3e, 0x2a, | ||
| 143 | 0x14, 0x18, 0x2e, 0x44, 0x2c, 0x02, 0x02, 0x27, 0x29, 0x07, 0x11, 0x1a, 0x12, 0x1d, 0x24, 0x1c, | ||
| 144 | 0x1d, 0x2b, 0x40, 0x32, 0x2c, 0x3f, 0x29, 0x13, 0x1a, 0x31, 0x49, 0x2e, 0x30, 0x30, 0x06, 0x0f, | ||
| 145 | 0x19, 0x13, 0x1e, 0x22, 0x0b, 0x0e, 0x20, 0x2f, 0x43, 0x30, 0xfe, 0x4b, 0x02, 0x52, 0x1d, 0x32, | ||
| 146 | 0x42, 0x25, 0x2c, 0x42, 0x1d, 0x08, 0x0a, 0x08, 0xf1, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x11, 0x19, | ||
| 147 | 0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, | ||
| 148 | 0x00, 0x12, 0x00, 0x32, 0x00, 0x72, 0x00, 0x8e, 0x00, 0xac, 0x00, 0xbe, 0x00, 0xf0, 0x01, 0x14, | ||
| 149 | 0x01, 0x5c, 0x01, 0xb6, 0x02, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0xa2, 0x00, 0x01, | ||
| 150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
| 151 | 0x00, 0x02, 0x00, 0x07, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2f, | ||
| 152 | 0x00, 0x17, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x46, 0x00, 0x01, | ||
| 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x58, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
| 154 | 0x00, 0x06, 0x00, 0x12, 0x00, 0x65, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x20, | ||
| 155 | 0x00, 0x77, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x97, 0x00, 0x03, | ||
| 156 | 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x5e, 0x00, 0xa5, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, | ||
| 157 | 0x00, 0x04, 0x00, 0x24, 0x01, 0x03, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1a, | ||
| 158 | 0x01, 0x27, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x24, 0x01, 0x41, 0x00, 0x03, | ||
| 159 | 0x00, 0x01, 0x04, 0x09, 0x00, 0x11, 0x00, 0x02, 0x01, 0x65, 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, | ||
| 160 | 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, | ||
| 161 | 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x3b, 0x3b, | ||
| 162 | 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, | ||
| 163 | 0x2d, 0x52, 0x3b, 0x32, 0x30, 0x31, 0x39, 0x3b, 0x46, 0x4c, 0x56, 0x49, 0x2d, 0x36, 0x31, 0x34, | ||
| 164 | 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, | ||
| 165 | 0x20, 0x52, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x59, | ||
| 166 | 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2d, | ||
| 167 | 0x52, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, | ||
| 168 | 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, | ||
| 169 | 0x6e, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00, | ||
| 170 | 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, | ||
| 171 | 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x59, 0x00, | ||
| 172 | 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, | ||
| 173 | 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00, | ||
| 174 | 0x52, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x46, 0x00, | ||
| 175 | 0x4c, 0x00, 0x56, 0x00, 0x49, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x31, 0x00, 0x34, 0x00, 0x59, 0x00, | ||
| 176 | 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, | ||
| 177 | 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, | ||
| 178 | 0x52, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, | ||
| 179 | 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x59, 0x00, 0x75, 0x00, | ||
| 180 | 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, | ||
| 181 | 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x52, 0x00, | ||
| 182 | 0x52, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9c, 0x00, 0x32, | ||
| 183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04, | 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 185 | 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, | 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 186 | 0x01, 0x0d, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, | 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 187 | 0x30, 0x44, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, | 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 188 | 0x45, 0x31, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, | 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 189 | 0x45, 0x33, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, | 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 190 | 0x45, 0x35, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, | 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 191 | 0x45, 0x37, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, | 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 192 | 0x45, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xff, 0xff, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, | 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 193 | 0x00, 0x00, 0x00, 0x00, | 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 66 | 0xB8, 0x00, 0x00, 0x2C, 0x4B, 0xB8, 0x00, 0x09, 0x50, 0x58, 0xB1, 0x01, 0x01, 0x8E, 0x59, 0xB8, | ||
| 67 | 0x01, 0xFF, 0x85, 0xB8, 0x00, 0x44, 0x1D, 0xB9, 0x00, 0x09, 0x00, 0x03, 0x5F, 0x5E, 0x2D, 0xB8, | ||
| 68 | 0x00, 0x01, 0x2C, 0x20, 0x20, 0x45, 0x69, 0x44, 0xB0, 0x01, 0x60, 0x2D, 0xB8, 0x00, 0x02, 0x2C, | ||
| 69 | 0xB8, 0x00, 0x01, 0x2A, 0x21, 0x2D, 0xB8, 0x00, 0x03, 0x2C, 0x20, 0x46, 0xB0, 0x03, 0x25, 0x46, | ||
| 70 | 0x52, 0x58, 0x23, 0x59, 0x20, 0x8A, 0x20, 0x8A, 0x49, 0x64, 0x8A, 0x20, 0x46, 0x20, 0x68, 0x61, | ||
| 71 | 0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8A, 0x59, 0x2F, | ||
| 72 | 0x20, 0xB0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x59, 0x1B, | ||
| 73 | 0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x65, 0x59, 0x59, 0x3A, 0x2D, 0xB8, 0x00, | ||
| 74 | 0x04, 0x2C, 0x20, 0x46, 0xB0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8A, 0x59, 0x20, 0x46, 0x20, | ||
| 75 | 0x6A, 0x61, 0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x6A, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8A, 0x59, | ||
| 76 | 0x2F, 0xFD, 0x2D, 0xB8, 0x00, 0x05, 0x2C, 0x4B, 0x20, 0xB0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58, | ||
| 77 | 0xB0, 0x80, 0x44, 0x1B, 0xB0, 0x40, 0x44, 0x59, 0x1B, 0x21, 0x21, 0x20, 0x45, 0xB0, 0xC0, 0x50, | ||
| 78 | 0x58, 0xB0, 0xC0, 0x44, 0x1B, 0x21, 0x59, 0x59, 0x2D, 0xB8, 0x00, 0x06, 0x2C, 0x20, 0x20, 0x45, | ||
| 79 | 0x69, 0x44, 0xB0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0xB0, 0x01, 0x60, 0x2D, | ||
| 80 | 0xB8, 0x00, 0x07, 0x2C, 0xB8, 0x00, 0x06, 0x2A, 0x2D, 0xB8, 0x00, 0x08, 0x2C, 0x4B, 0x20, 0xB0, | ||
| 81 | 0x03, 0x26, 0x53, 0x58, 0xB0, 0x40, 0x1B, 0xB0, 0x00, 0x59, 0x8A, 0x8A, 0x20, 0xB0, 0x03, 0x26, | ||
| 82 | 0x53, 0x58, 0x23, 0x21, 0xB0, 0x80, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03, 0x26, | ||
| 83 | 0x53, 0x58, 0x23, 0x21, 0xB8, 0x00, 0xC0, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03, | ||
| 84 | 0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x00, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, | ||
| 85 | 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x40, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, | ||
| 86 | 0xB8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xB0, 0x03, 0x25, 0x45, 0xB8, 0x01, 0x80, 0x50, 0x58, 0x23, | ||
| 87 | 0x21, 0xB8, 0x01, 0x80, 0x23, 0x21, 0x1B, 0xB0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59, | ||
| 88 | 0x1B, 0x21, 0x59, 0x44, 0x2D, 0xB8, 0x00, 0x09, 0x2C, 0x4B, 0x53, 0x58, 0x45, 0x44, 0x1B, 0x21, | ||
| 89 | 0x21, 0x59, 0x2D, 0x00, 0xB8, 0x00, 0x00, 0x2B, 0x00, 0xBA, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, | ||
| 90 | 0x2B, 0xB8, 0x00, 0x00, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, | ||
| 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x70, | ||
| 92 | 0x00, 0xDC, 0x01, 0x34, 0x01, 0x7C, 0x01, 0xA2, 0x01, 0xF4, 0x02, 0x3C, 0x02, 0xA8, 0x03, 0x4C, | ||
| 93 | 0x03, 0xE2, 0x04, 0x20, 0x04, 0x58, 0x04, 0x9A, 0x04, 0xEE, 0x05, 0x32, 0x05, 0x64, 0x05, 0x80, | ||
| 94 | 0x05, 0xC6, 0x05, 0xF6, 0x06, 0x54, 0x06, 0xB2, 0x07, 0x38, 0x07, 0x60, 0x07, 0x82, 0x00, 0x00, | ||
| 95 | 0x00, 0x02, 0x00, 0xA4, 0xFF, 0xFF, 0x03, 0x5C, 0x03, 0x09, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, | ||
| 96 | 0x13, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0xCD, 0x02, 0x66, 0xFD, 0x71, 0x02, 0xB8, 0xFD, | ||
| 97 | 0x48, 0x02, 0xE0, 0xFD, 0x48, 0x02, 0xB8, 0x29, 0xFC, 0xF6, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, | ||
| 98 | 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x2F, 0x00, 0x39, 0x00, 0x00, | ||
| 99 | 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x32, 0x1E, | ||
| 100 | 0x02, 0x14, 0x0E, 0x02, 0x22, 0x2E, 0x02, 0x34, 0x3E, 0x01, 0x13, 0x12, 0x37, 0x33, 0x13, 0x12, | ||
| 101 | 0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30, 0x27, 0x26, 0x2F, 0x01, | ||
| 102 | 0x06, 0x07, 0x06, 0x32, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, | ||
| 103 | 0x46, 0x46, 0x77, 0xFE, 0x9E, 0xC8, 0xB7, 0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0x4E, | ||
| 104 | 0x4E, 0x83, 0x23, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E, 0xD1, 0x2B, 0x37, 0x33, | ||
| 105 | 0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03, 0x3F, 0x46, 0x77, 0xA4, | ||
| 106 | 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, | ||
| 107 | 0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0xFD, 0x64, 0x01, 0x1A, 0xEB, 0xFE, 0xFE, 0xFE, | ||
| 108 | 0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C, 0x02, 0xBE, 0x02, 0x00, | ||
| 109 | 0x00, 0x05, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2F, | ||
| 110 | 0x00, 0x3A, 0x00, 0x44, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x02, | ||
| 111 | 0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x01, | ||
| 112 | 0x16, 0x17, 0x14, 0x06, 0x07, 0x06, 0x2B, 0x01, 0x19, 0x01, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16, | ||
| 113 | 0x07, 0x06, 0x0F, 0x01, 0x36, 0x37, 0x34, 0x2E, 0x01, 0x27, 0x23, 0x15, 0x33, 0x32, 0x27, 0x32, | ||
| 114 | 0x37, 0x36, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x45, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, | ||
| 115 | 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, | ||
| 116 | 0xF4, 0xE2, 0x01, 0xF7, 0x61, 0x01, 0x4E, 0x3E, 0x29, 0xAF, 0x4E, 0x81, 0x8B, 0x1D, 0x3C, 0x1F, | ||
| 117 | 0x19, 0x04, 0x06, 0x39, 0x57, 0x44, 0x01, 0x1B, 0x2D, 0x51, 0x46, 0x46, 0x47, 0x66, 0x70, 0x16, | ||
| 118 | 0x1F, 0x01, 0x2C, 0x08, 0x4B, 0x4C, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, | ||
| 119 | 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, | ||
| 120 | 0x84, 0x84, 0x01, 0x6D, 0x21, 0x5B, 0x40, 0x50, 0x05, 0x03, 0x01, 0x03, 0x01, 0x05, 0x01, 0x05, | ||
| 121 | 0x09, 0x30, 0x25, 0x29, 0x40, 0x21, 0xC2, 0x06, 0x3E, 0x1A, 0x21, 0x0B, 0x01, 0x8C, 0xE1, 0x0A, | ||
| 122 | 0x0E, 0x54, 0x0B, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, | ||
| 123 | 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x38, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E, | ||
| 124 | 0x02, 0x34, 0x2E, 0x02, 0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E, | ||
| 125 | 0x01, 0x20, 0x26, 0x36, 0x34, 0x3F, 0x01, 0x27, 0x26, 0x27, 0x33, 0x17, 0x16, 0x33, 0x36, 0x3F, | ||
| 126 | 0x02, 0x32, 0x14, 0x06, 0x16, 0x12, 0x14, 0x2B, 0x01, 0x27, 0x26, 0x06, 0x0F, 0x01, 0x23, 0x45, | ||
| 127 | 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, | ||
| 128 | 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x7B, 0x58, 0x58, 0x4D, 0x4F, 0x05, 0x7A, | ||
| 129 | 0x34, 0x34, 0x02, 0x01, 0x33, 0x32, 0x3C, 0x3C, 0xA1, 0x01, 0xB0, 0x3E, 0x3F, 0x39, 0x3B, 0x02, | ||
| 130 | 0x3A, 0x38, 0x3F, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, | ||
| 131 | 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x60, | ||
| 132 | 0x02, 0x87, 0x88, 0x79, 0x7A, 0x06, 0x54, 0x54, 0x01, 0x53, 0x53, 0x01, 0x01, 0xFB, 0x04, 0xFE, | ||
| 133 | 0xF8, 0x02, 0x5B, 0x5A, 0x03, 0x59, 0x59, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, | ||
| 134 | 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, | ||
| 135 | 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, | ||
| 136 | 0x01, 0x10, 0x36, 0x01, 0x35, 0x27, 0x26, 0x34, 0x3B, 0x01, 0x17, 0x16, 0x36, 0x3F, 0x01, 0x33, | ||
| 137 | 0x03, 0x15, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, | ||
| 138 | 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, | ||
| 139 | 0x36, 0x5E, 0x5F, 0x3C, 0x3D, 0x3D, 0x3D, 0x03, 0x3B, 0x3B, 0x77, 0xBE, 0x68, 0x03, 0x3F, 0x46, | ||
| 140 | 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0xFE, | ||
| 141 | 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6E, 0x96, 0x95, 0x01, 0x67, 0x67, | ||
| 142 | 0x03, 0x66, 0x65, 0xFE, 0xD3, 0xDA, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC, | ||
| 143 | 0x03, 0x4B, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x00, 0x01, 0x21, 0x22, 0x15, 0x30, 0x11, | ||
| 144 | 0x21, 0x17, 0x21, 0x11, 0x10, 0x25, 0x21, 0x01, 0x11, 0x33, 0x11, 0x21, 0x15, 0x03, 0xBB, 0xFD, | ||
| 145 | 0x77, 0xED, 0x03, 0x76, 0x31, 0xFC, 0x28, 0x01, 0x1E, 0x02, 0xBA, 0xFD, 0x5C, 0x68, 0x01, 0x08, | ||
| 146 | 0x03, 0x1A, 0xEE, 0xFD, 0xC2, 0x31, 0x02, 0x6F, 0x01, 0x1E, 0x01, 0xFD, 0x36, 0x02, 0x07, 0xFE, | ||
| 147 | 0x50, 0x57, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC, 0x03, 0x4B, 0x00, 0x06, | ||
| 148 | 0x00, 0x0C, 0x00, 0x27, 0x00, 0x32, 0x00, 0x00, 0x05, 0x11, 0x34, 0x27, 0x30, 0x21, 0x11, 0x07, | ||
| 149 | 0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x07, | ||
| 150 | 0x06, 0x07, 0x06, 0x07, 0x1E, 0x02, 0x15, 0x07, 0x23, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x13, | ||
| 151 | 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x23, 0x15, 0x33, 0x36, 0x03, 0xBB, 0xED, 0xFD, 0x77, 0x31, | ||
| 152 | 0x02, 0xBA, 0x01, 0x1E, 0xFD, 0x2A, 0x77, 0x76, 0x15, 0x49, 0x20, 0x35, 0x08, 0x04, 0x06, 0x13, | ||
| 153 | 0x66, 0x0C, 0x01, 0x1F, 0x2E, 0x65, 0x3D, 0x3D, 0x2A, 0x56, 0x28, 0x2E, 0x19, 0x99, 0x3C, 0x20, | ||
| 154 | 0x10, 0x56, 0x4F, 0x46, 0x47, 0x12, 0x02, 0x3E, 0xED, 0x01, 0xFC, 0xD4, 0x31, 0x03, 0x8E, 0xFE, | ||
| 155 | 0xE1, 0xFD, 0x91, 0xC4, 0x02, 0x07, 0x01, 0x04, 0x13, 0x21, 0x44, 0x1D, 0x19, 0x58, 0x15, 0x02, | ||
| 156 | 0x01, 0x13, 0x2D, 0xA2, 0x01, 0x01, 0x3D, 0x81, 0x1A, 0x01, 0x01, 0xDA, 0x01, 0x2D, 0x08, 0x3A, | ||
| 157 | 0x29, 0x0F, 0x08, 0x01, 0x85, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC, | ||
| 158 | 0x03, 0x13, 0x00, 0x09, 0x00, 0x11, 0x00, 0x26, 0x00, 0x32, 0x00, 0x00, 0x37, 0x21, 0x34, 0x10, | ||
| 159 | 0x35, 0x34, 0x27, 0x21, 0x04, 0x11, 0x23, 0x10, 0x25, 0x21, 0x16, 0x15, 0x11, 0x21, 0x37, 0x35, | ||
| 160 | 0x37, 0x36, 0x22, 0x2B, 0x01, 0x3D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x0F, 0x01, 0x3B, 0x01, 0x1D, | ||
| 161 | 0x01, 0x2B, 0x01, 0x25, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x45, | ||
| 162 | 0x03, 0x76, 0x45, 0xFE, 0x2D, 0xFE, 0xA2, 0x31, 0x01, 0x8F, 0x01, 0xD3, 0x76, 0xFC, 0x28, 0xA7, | ||
| 163 | 0x68, 0x68, 0x01, 0x5B, 0x5D, 0x90, 0x91, 0x6C, 0x6D, 0x71, 0x70, 0xA0, 0xA0, 0x01, 0x75, 0x27, | ||
| 164 | 0x28, 0x63, 0x63, 0x8B, 0x8A, 0x27, 0x69, 0x01, 0xA4, 0x69, 0x44, 0x01, 0x02, 0xFE, 0xA4, 0x01, | ||
| 165 | 0x8C, 0x03, 0x01, 0x75, 0xFD, 0x58, 0xBB, 0x24, 0x80, 0x80, 0x21, 0x21, 0x1F, 0x1E, 0x85, 0x86, | ||
| 166 | 0x20, 0x22, 0xC3, 0xC3, 0xA1, 0xA3, 0x20, 0x22, 0x00, 0x05, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC, | ||
| 167 | 0x03, 0x13, 0x00, 0x08, 0x00, 0x10, 0x00, 0x2B, 0x00, 0x37, 0x00, 0x44, 0x00, 0x00, 0x37, 0x21, | ||
| 168 | 0x11, 0x10, 0x25, 0x30, 0x21, 0x06, 0x15, 0x03, 0x11, 0x34, 0x37, 0x21, 0x04, 0x19, 0x01, 0x01, | ||
| 169 | 0x35, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17, | ||
| 170 | 0x16, 0x23, 0x2F, 0x01, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x23, 0x37, 0x32, 0x36, 0x37, 0x36, 0x35, | ||
| 171 | 0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x05, 0x35, 0x37, 0x36, 0x26, 0x2B, 0x01, 0x35, 0x21, 0x15, | ||
| 172 | 0x03, 0x17, 0x15, 0x45, 0x03, 0x76, 0xFE, 0xA2, 0xFE, 0x2D, 0x45, 0x31, 0x76, 0x01, 0xD3, 0x01, | ||
| 173 | 0x8F, 0xFE, 0x1E, 0x65, 0x6F, 0x15, 0x46, 0x10, 0x05, 0x04, 0x0D, 0x4F, 0x09, 0x09, 0x1F, 0x1D, | ||
| 174 | 0x3A, 0x06, 0x01, 0x30, 0x2F, 0x22, 0x37, 0x1E, 0x29, 0x14, 0x4E, 0x82, 0x34, 0x19, 0x0E, 0x13, | ||
| 175 | 0x0A, 0x22, 0x07, 0x38, 0x37, 0xFE, 0x3E, 0x68, 0x68, 0x01, 0x5C, 0x5C, 0x01, 0x20, 0xD8, 0xE1, | ||
| 176 | 0x27, 0x01, 0x5D, 0x01, 0x5B, 0x03, 0x01, 0x44, 0xFD, 0x58, 0x02, 0xA8, 0x75, 0x01, 0x03, 0xFE, | ||
| 177 | 0x74, 0xFE, 0x71, 0x01, 0x5C, 0xC5, 0x01, 0x04, 0x0C, 0x43, 0x15, 0x1D, 0x44, 0x10, 0x04, 0x06, | ||
| 178 | 0x14, 0x2B, 0x56, 0x10, 0x01, 0x01, 0x34, 0x52, 0x1C, 0x01, 0x01, 0xA5, 0xE3, 0x04, 0x06, 0x0A, | ||
| 179 | 0x20, 0x2C, 0x04, 0x01, 0x65, 0xE3, 0x47, 0x80, 0x80, 0x01, 0x42, 0x3D, 0xFE, 0xF5, 0x01, 0x41, | ||
| 180 | 0x00, 0x04, 0x00, 0x14, 0x00, 0x52, 0x03, 0xEC, 0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x64, | ||
| 181 | 0x00, 0x70, 0x00, 0x00, 0x25, 0x11, 0x21, 0x22, 0x15, 0x30, 0x15, 0x14, 0x33, 0x11, 0x21, 0x32, | ||
| 182 | 0x15, 0x11, 0x14, 0x27, 0x21, 0x22, 0x26, 0x3D, 0x01, 0x34, 0x36, 0x13, 0x26, 0x27, 0x26, 0x27, | ||
| 183 | 0x26, 0x37, 0x33, 0x36, 0x37, 0x36, 0x33, 0x16, 0x17, 0x16, 0x17, 0x16, 0x37, 0x36, 0x37, 0x36, | ||
| 184 | 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x34, 0x37, 0x36, 0x37, | ||
| 185 | 0x36, 0x37, 0x36, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x0F, 0x01, 0x22, 0x06, 0x23, | ||
| 186 | 0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, | ||
| 187 | 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x27, 0x37, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B, | ||
| 188 | 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x03, 0xBB, 0xFD, 0x2A, 0xA0, 0xA0, 0x02, 0xEE, 0x19, 0x19, 0xFD, | ||
| 189 | 0x12, 0x57, 0x7A, 0x7A, 0xCA, 0x38, 0x1D, 0x16, 0x08, 0x03, 0x01, 0x02, 0x0F, 0x0C, 0x1E, 0x01, | ||
| 190 | 0x02, 0x04, 0x0C, 0x2B, 0x0F, 0x0E, 0x18, 0x0C, 0x09, 0x04, 0x15, 0x32, 0x23, 0x12, 0x1C, 0x0E, | ||
| 191 | 0x09, 0x03, 0x01, 0x01, 0x09, 0x21, 0x0F, 0x14, 0x2E, 0x2A, 0x13, 0x0F, 0x0C, 0x08, 0x0B, 0x05, | ||
| 192 | 0x02, 0x01, 0x02, 0x03, 0x36, 0x03, 0x02, 0x03, 0x08, 0x0D, 0x23, 0x16, 0x0E, 0x10, 0x01, 0x01, | ||
| 193 | 0x07, 0x0B, 0x32, 0x25, 0x13, 0x26, 0x0F, 0x09, 0x01, 0x01, 0x0F, 0x11, 0x24, 0x21, 0x2A, 0xE3, | ||
| 194 | 0x20, 0x20, 0x52, 0x50, 0x71, 0x71, 0x84, 0x02, 0x00, 0xAF, 0xA2, 0xAF, 0x02, 0x32, 0x19, 0xFD, | ||
| 195 | 0xCE, 0x19, 0x01, 0x84, 0x5C, 0xA2, 0x5C, 0x85, 0xFE, 0x29, 0x04, 0x1E, 0x18, 0x26, 0x0F, 0x01, | ||
| 196 | 0x02, 0x01, 0x03, 0x05, 0x0B, 0x29, 0x06, 0x02, 0x03, 0x04, 0x11, 0x0B, 0x0D, 0x0A, 0x06, 0x12, | ||
| 197 | 0x0D, 0x0A, 0x07, 0x0C, 0x18, 0x0D, 0x10, 0x06, 0x18, 0x05, 0x27, 0x14, 0x09, 0x03, 0x0A, 0x0D, | ||
| 198 | 0x06, 0x09, 0x09, 0x0D, 0x0F, 0x14, 0x0C, 0x06, 0x03, 0x02, 0x04, 0x10, 0x0A, 0x11, 0x08, 0x09, | ||
| 199 | 0x0E, 0x0C, 0x07, 0x0C, 0x0C, 0x0A, 0x07, 0x0F, 0x20, 0x11, 0x18, 0x1E, 0x1A, 0x1E, 0x0C, 0x0B, | ||
| 200 | 0x03, 0xAA, 0xA5, 0x89, 0x8A, 0x1C, 0x1B, 0x00, 0x00, 0x05, 0x00, 0x14, 0x00, 0x53, 0x03, 0xEC, | ||
| 201 | 0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x2E, 0x00, 0x38, 0x00, 0x65, 0x00, 0x00, 0x01, 0x30, | ||
| 202 | 0x21, 0x11, 0x21, 0x32, 0x3D, 0x01, 0x34, 0x27, 0x32, 0x16, 0x1D, 0x01, 0x14, 0x06, 0x23, 0x21, | ||
| 203 | 0x26, 0x35, 0x11, 0x34, 0x33, 0x01, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, | ||
| 204 | 0x17, 0x1E, 0x01, 0x1F, 0x01, 0x23, 0x2A, 0x01, 0x2E, 0x01, 0x23, 0x27, 0x15, 0x37, 0x32, 0x37, | ||
| 205 | 0x36, 0x27, 0x2E, 0x01, 0x2B, 0x01, 0x15, 0x05, 0x26, 0x27, 0x37, 0x32, 0x3F, 0x01, 0x16, 0x17, | ||
| 206 | 0x1E, 0x01, 0x37, 0x36, 0x27, 0x2E, 0x04, 0x37, 0x3E, 0x01, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14, | ||
| 207 | 0x06, 0x27, 0x26, 0x27, 0x26, 0x0E, 0x01, 0x1E, 0x02, 0x17, 0x16, 0x06, 0x07, 0x06, 0x07, 0x06, | ||
| 208 | 0x03, 0x1B, 0xFD, 0x2A, 0x02, 0xD6, 0xA0, 0xA0, 0x57, 0x7A, 0x7A, 0x57, 0xFD, 0x12, 0x19, 0x19, | ||
| 209 | 0x01, 0xD3, 0x47, 0x44, 0x11, 0x3E, 0x18, 0x21, 0x0B, 0x0C, 0x43, 0x04, 0x17, 0x1C, 0x1E, 0x16, | ||
| 210 | 0x26, 0x26, 0x03, 0x4D, 0x18, 0x1E, 0x11, 0x25, 0x3A, 0x0C, 0x22, 0x08, 0x03, 0x1B, 0x3E, 0x29, | ||
| 211 | 0xFE, 0xAC, 0x0D, 0x04, 0x02, 0x02, 0x1E, 0x1D, 0x03, 0x02, 0x0C, 0x4C, 0x13, 0x20, 0x07, 0x04, | ||
| 212 | 0x1B, 0x56, 0x2D, 0x1C, 0x01, 0x02, 0x44, 0x35, 0x49, 0x1F, 0x10, 0x03, 0x41, 0x01, 0x06, 0x0A, | ||
| 213 | 0x16, 0x3C, 0x18, 0x0C, 0x16, 0x5D, 0x15, 0x33, 0x03, 0x2B, 0x1E, 0x34, 0x59, 0x02, 0x84, 0xFE, | ||
| 214 | 0x00, 0xAF, 0xA2, 0xAF, 0x32, 0x85, 0x5C, 0xA2, 0x5C, 0x84, 0x01, 0x17, 0x02, 0x32, 0x19, 0xFE, | ||
| 215 | 0x2F, 0x01, 0x45, 0x01, 0x02, 0x19, 0x22, 0x32, 0x39, 0x0B, 0x08, 0x0F, 0x27, 0x2F, 0x24, 0x75, | ||
| 216 | 0x12, 0x01, 0x88, 0xBB, 0x04, 0x09, 0x2A, 0x0F, 0x0D, 0x53, 0x8A, 0x17, 0x1E, 0x04, 0x03, 0x03, | ||
| 217 | 0x0C, 0x04, 0x26, 0x0E, 0x0C, 0x14, 0x1A, 0x0E, 0x0E, 0x16, 0x16, 0x2C, 0x1A, 0x2D, 0x2D, 0x2A, | ||
| 218 | 0x16, 0x1D, 0x06, 0x04, 0x01, 0x1A, 0x09, 0x11, 0x09, 0x17, 0x18, 0x0D, 0x17, 0x0C, 0x1B, 0x71, | ||
| 219 | 0x1B, 0x12, 0x01, 0x03, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, | ||
| 220 | 0x00, 0x1B, 0x00, 0x27, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, | ||
| 221 | 0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, | ||
| 222 | 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x35, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77, | ||
| 223 | 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, | ||
| 224 | 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC5, 0x4E, 0xC5, 0xC4, 0x50, 0xC4, 0x03, 0x3F, | ||
| 225 | 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, | ||
| 226 | 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0xC4, 0xC5, 0x4E, 0xC5, 0xC5, | ||
| 227 | 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x1F, | ||
| 228 | 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, | ||
| 229 | 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x35, 0x21, 0x15, 0x02, | ||
| 230 | 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, | ||
| 231 | 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8, 0x03, 0x3F, | ||
| 232 | 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, | ||
| 233 | 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0x71, 0x4E, 0x4E, 0x00, 0x00, 0x00, | ||
| 234 | 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x1B, 0x00, 0x25, | ||
| 235 | 0x00, 0x00, 0x00, 0x20, 0x0E, 0x01, 0x10, 0x1E, 0x01, 0x20, 0x3E, 0x01, 0x10, 0x26, 0x01, 0x12, | ||
| 236 | 0x37, 0x33, 0x13, 0x12, 0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30, | ||
| 237 | 0x27, 0x26, 0x2F, 0x01, 0x06, 0x07, 0x06, 0x32, 0x02, 0x86, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, | ||
| 238 | 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xFD, 0xA0, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E, | ||
| 239 | 0xD1, 0x2B, 0x37, 0x33, 0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03, | ||
| 240 | 0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0x9A, 0x01, 0x1A, | ||
| 241 | 0xEB, 0xFE, 0xFE, 0xFE, 0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C, | ||
| 242 | 0x02, 0xBE, 0x02, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, | ||
| 243 | 0x00, 0x20, 0x00, 0x2B, 0x00, 0x35, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, | ||
| 244 | 0x0E, 0x01, 0x20, 0x26, 0x01, 0x30, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x23, 0x27, | ||
| 245 | 0x19, 0x01, 0x33, 0x32, 0x37, 0x3E, 0x01, 0x35, 0x26, 0x07, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x1E, | ||
| 246 | 0x02, 0x15, 0x06, 0x27, 0x23, 0x35, 0x33, 0x16, 0x17, 0x16, 0x14, 0x07, 0x06, 0x14, 0x84, 0xE2, | ||
| 247 | 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x01, 0xF7, 0x0A, 0x3A, 0x05, 0x04, 0x19, | ||
| 248 | 0x20, 0x3B, 0x1D, 0x8B, 0x81, 0x4E, 0xAF, 0x29, 0x3E, 0x4E, 0x01, 0xAE, 0x0D, 0x47, 0x46, 0x46, | ||
| 249 | 0x52, 0x2C, 0x1B, 0x01, 0xB7, 0x27, 0x4C, 0x4C, 0x07, 0x2C, 0x1E, 0x16, 0xFE, 0x01, 0x0C, 0xE2, | ||
| 250 | 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x6D, 0x06, 0x21, 0x40, 0x2A, 0x24, 0x30, | ||
| 251 | 0x09, 0x05, 0x01, 0xFE, 0xFB, 0xFE, 0xFD, 0x03, 0x05, 0x4F, 0x41, 0x5B, 0x9B, 0x01, 0x8C, 0x01, | ||
| 252 | 0x0B, 0x21, 0x1A, 0x3E, 0xDA, 0x79, 0x01, 0x01, 0x0B, 0x54, 0x0E, 0x0A, 0x00, 0x02, 0x00, 0x14, | ||
| 253 | 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x29, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01, | ||
| 254 | 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x36, 0x14, 0x3B, 0x01, 0x37, 0x36, 0x37, 0x36, | ||
| 255 | 0x1F, 0x01, 0x33, 0x32, 0x34, 0x02, 0x26, 0x36, 0x34, 0x23, 0x0F, 0x01, 0x06, 0x07, 0x22, 0x2F, | ||
| 256 | 0x01, 0x23, 0x16, 0x1F, 0x01, 0x07, 0x14, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, | ||
| 257 | 0xF4, 0xE2, 0x7B, 0x3D, 0x3F, 0x38, 0x3A, 0x01, 0x02, 0x3A, 0x39, 0x3F, 0x3E, 0xB0, 0x01, 0xA1, | ||
| 258 | 0x3C, 0x3C, 0x32, 0x33, 0x01, 0x02, 0x34, 0x34, 0x7A, 0x05, 0x4F, 0x4D, 0x58, 0xFE, 0x01, 0x0C, | ||
| 259 | 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x62, 0x02, 0x59, 0x59, 0x02, 0x01, 0x5A, | ||
| 260 | 0x5B, 0x02, 0x01, 0x08, 0x04, 0xFB, 0x01, 0x01, 0x53, 0x53, 0x01, 0x54, 0x54, 0x06, 0x7A, 0x79, | ||
| 261 | 0x88, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, | ||
| 262 | 0x00, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, | ||
| 263 | 0x01, 0x15, 0x33, 0x35, 0x13, 0x23, 0x07, 0x0E, 0x01, 0x2F, 0x01, 0x23, 0x22, 0x16, 0x1F, 0x01, | ||
| 264 | 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x36, 0x68, | ||
| 265 | 0xBE, 0x77, 0x3B, 0x3C, 0x02, 0x3D, 0x3D, 0x3D, 0x3D, 0x01, 0x5F, 0x5E, 0x03, 0x70, 0x84, 0xE2, | ||
| 266 | 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6D, 0xDA, 0x01, 0x2D, 0x65, | ||
| 267 | 0x66, 0x03, 0x67, 0x67, 0x01, 0x95, 0x96, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC, | ||
| 268 | 0x03, 0x4A, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x05, 0x21, 0x11, 0x10, 0x05, 0x21, 0x01, 0x21, | ||
| 269 | 0x35, 0x21, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x14, 0x02, 0xC4, 0xFD, 0x5C, 0x01, 0x70, | ||
| 270 | 0xFE, 0xF8, 0x68, 0x41, 0x02, 0x77, 0x01, 0x14, 0x01, 0xFD, 0x38, 0x57, 0x01, 0xB0, 0x00, 0x00, | ||
| 271 | 0x00, 0x03, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC, 0x03, 0x49, 0x00, 0x05, 0x00, 0x20, 0x00, 0x2B, | ||
| 272 | 0x00, 0x00, 0x17, 0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F, 0x01, | ||
| 273 | 0x33, 0x37, 0x2E, 0x02, 0x27, 0x34, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, | ||
| 274 | 0x2B, 0x01, 0x05, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x16, 0x17, 0x16, 0x15, 0x14, 0x14, 0x02, 0xC4, | ||
| 275 | 0x01, 0x14, 0xFD, 0x2A, 0x69, 0x19, 0x2E, 0x28, 0x56, 0x2A, 0x3D, 0x3D, 0x01, 0x65, 0x2C, 0x20, | ||
| 276 | 0x0D, 0x66, 0x13, 0x06, 0x04, 0x09, 0x34, 0x20, 0x49, 0x15, 0x76, 0x77, 0x01, 0x02, 0x0C, 0x47, | ||
| 277 | 0x46, 0x4F, 0x56, 0x10, 0x20, 0x41, 0x03, 0x8A, 0xFE, 0xED, 0xFD, 0x89, 0xC2, 0xDA, 0x01, 0x01, | ||
| 278 | 0x1A, 0x81, 0x3D, 0x01, 0x01, 0xA3, 0x2C, 0x13, 0x01, 0x02, 0x13, 0x5A, 0x1A, 0x1C, 0x44, 0x21, | ||
| 279 | 0x13, 0x04, 0x01, 0xDA, 0x02, 0x85, 0x01, 0x08, 0x0F, 0x29, 0x3A, 0x00, 0x00, 0x03, 0x00, 0x14, | ||
| 280 | 0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x08, 0x00, 0x15, 0x00, 0x1B, 0x00, 0x00, 0x05, 0x21, | ||
| 281 | 0x11, 0x10, 0x21, 0x30, 0x21, 0x32, 0x15, 0x01, 0x21, 0x35, 0x23, 0x13, 0x35, 0x21, 0x15, 0x33, | ||
| 282 | 0x32, 0x22, 0x0F, 0x01, 0x05, 0x21, 0x35, 0x23, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x8A, | ||
| 283 | 0x01, 0xEC, 0x62, 0xFC, 0xCF, 0x01, 0x40, 0xE1, 0xD9, 0xFE, 0xDF, 0x5D, 0x5C, 0x01, 0x67, 0x68, | ||
| 284 | 0x01, 0x75, 0x01, 0x15, 0xC6, 0x4F, 0x05, 0x01, 0x89, 0x01, 0x8A, 0x63, 0xFD, 0xE1, 0x42, 0x01, | ||
| 285 | 0x0B, 0x3D, 0x42, 0x80, 0x80, 0x48, 0x42, 0x01, 0x44, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, | ||
| 286 | 0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x07, 0x00, 0x22, 0x00, 0x2F, 0x00, 0x3C, 0x00, 0x00, | ||
| 287 | 0x17, 0x11, 0x34, 0x37, 0x21, 0x20, 0x19, 0x01, 0x01, 0x15, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F, | ||
| 288 | 0x02, 0x32, 0x35, 0x26, 0x27, 0x26, 0x27, 0x26, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, | ||
| 289 | 0x23, 0x27, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14, 0x07, 0x0E, 0x01, 0x05, | ||
| 290 | 0x21, 0x35, 0x27, 0x13, 0x35, 0x21, 0x15, 0x33, 0x32, 0x14, 0x0F, 0x01, 0x14, 0x62, 0x01, 0xEC, | ||
| 291 | 0x01, 0x8A, 0xFE, 0x1E, 0x4E, 0x14, 0x29, 0x1E, 0x37, 0x22, 0x2F, 0x2F, 0x06, 0x3A, 0x1D, 0x1F, | ||
| 292 | 0x09, 0x09, 0x4E, 0x0E, 0x04, 0x05, 0x0F, 0x47, 0x15, 0x6F, 0x65, 0x82, 0x34, 0x37, 0x38, 0x07, | ||
| 293 | 0x23, 0x09, 0x13, 0x0D, 0x1A, 0xFD, 0xD6, 0x01, 0x40, 0xE1, 0xD8, 0xFE, 0xE0, 0x5C, 0x5C, 0x67, | ||
| 294 | 0x68, 0x05, 0x02, 0xB0, 0x62, 0x01, 0xFE, 0x76, 0xFE, 0x77, 0x01, 0x56, 0xC5, 0xA5, 0x01, 0x01, | ||
| 295 | 0x1C, 0x52, 0x34, 0x01, 0x01, 0x0E, 0x58, 0x2C, 0x13, 0x06, 0x04, 0x0F, 0x45, 0x1E, 0x14, 0x42, | ||
| 296 | 0x0D, 0x04, 0x01, 0xA7, 0x65, 0x01, 0x04, 0x2C, 0x21, 0x09, 0x07, 0x03, 0xE3, 0x41, 0x01, 0x01, | ||
| 297 | 0x0B, 0x3D, 0x42, 0x01, 0x80, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC, | ||
| 298 | 0x02, 0xAB, 0x00, 0x08, 0x00, 0x37, 0x00, 0x3D, 0x00, 0x00, 0x13, 0x30, 0x21, 0x11, 0x21, 0x22, | ||
| 299 | 0x3D, 0x01, 0x34, 0x05, 0x37, 0x34, 0x27, 0x26, 0x27, 0x26, 0x07, 0x06, 0x07, 0x0E, 0x01, 0x17, | ||
| 300 | 0x1E, 0x01, 0x17, 0x16, 0x14, 0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x22, 0x17, | ||
| 301 | 0x1E, 0x01, 0x17, 0x16, 0x37, 0x36, 0x27, 0x26, 0x27, 0x2E, 0x02, 0x37, 0x36, 0x33, 0x32, 0x1F, | ||
| 302 | 0x02, 0x33, 0x35, 0x23, 0x11, 0x23, 0xD6, 0x03, 0x16, 0xFC, 0xEA, 0xC2, 0x01, 0xC6, 0x02, 0x01, | ||
| 303 | 0x0C, 0x3A, 0x2B, 0x2D, 0x13, 0x10, 0x2B, 0x01, 0x33, 0x17, 0x55, 0x15, 0x04, 0x09, 0x14, 0x58, | ||
| 304 | 0x0C, 0x04, 0x02, 0x02, 0x26, 0x14, 0x01, 0x03, 0x08, 0x33, 0x38, 0x5F, 0x20, 0x10, 0x01, 0x03, | ||
| 305 | 0x3C, 0x12, 0x59, 0x11, 0x01, 0x02, 0x39, 0x2C, 0x09, 0x02, 0x9D, 0xE2, 0xA2, 0x40, 0x02, 0xAB, | ||
| 306 | 0xFD, 0xB2, 0xD2, 0xAA, 0xD2, 0xDC, 0x03, 0x07, 0x0B, 0x38, 0x10, 0x0C, 0x09, 0x04, 0x08, 0x19, | ||
| 307 | 0x6C, 0x17, 0x0B, 0x17, 0x11, 0x07, 0x17, 0x0A, 0x1A, 0x0A, 0x29, 0x0C, 0x04, 0x04, 0x02, 0x10, | ||
| 308 | 0x25, 0x37, 0x04, 0x06, 0x37, 0x1D, 0x1C, 0x3F, 0x19, 0x08, 0x16, 0x13, 0x0B, 0x1F, 0x2B, 0x04, | ||
| 309 | 0xE9, 0x37, 0x01, 0x13, 0x00, 0x04, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC, 0x02, 0xAB, 0x00, 0x07, | ||
| 310 | 0x00, 0x1F, 0x00, 0x2A, 0x00, 0x58, 0x00, 0x00, 0x01, 0x32, 0x1D, 0x01, 0x14, 0x23, 0x21, 0x11, | ||
| 311 | 0x01, 0x33, 0x35, 0x17, 0x1E, 0x03, 0x3B, 0x01, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x36, 0x37, 0x36, | ||
| 312 | 0x27, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x16, 0x17, 0x16, 0x07, | ||
| 313 | 0x06, 0x05, 0x16, 0x37, 0x36, 0x37, 0x3E, 0x01, 0x27, 0x2E, 0x03, 0x3E, 0x01, 0x17, 0x16, 0x17, | ||
| 314 | 0x30, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x06, 0x1E, 0x03, 0x17, 0x16, | ||
| 315 | 0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x07, 0x06, 0x23, 0x07, 0x16, 0x03, 0x2A, 0xC2, 0xC2, 0xFC, | ||
| 316 | 0xEA, 0x01, 0xEC, 0x41, 0x11, 0x1F, 0x17, 0x4D, 0x02, 0x27, 0x26, 0x16, 0x1E, 0x1C, 0x17, 0x04, | ||
| 317 | 0x43, 0x0C, 0x0B, 0x21, 0x18, 0x3E, 0x0F, 0x46, 0x47, 0x66, 0x25, 0x29, 0x3E, 0x1B, 0x03, 0x08, | ||
| 318 | 0x22, 0x0C, 0xFE, 0x4D, 0x22, 0x59, 0x34, 0x1E, 0x2B, 0x03, 0x33, 0x16, 0x5C, 0x16, 0x0C, 0x18, | ||
| 319 | 0x3C, 0x16, 0x0B, 0x05, 0x22, 0x21, 0x01, 0x03, 0x10, 0x1F, 0x49, 0x36, 0x43, 0x02, 0x01, 0x1C, | ||
| 320 | 0x2D, 0x56, 0x1B, 0x04, 0x07, 0x20, 0x13, 0x4B, 0x0D, 0x01, 0x04, 0x1D, 0x1E, 0x02, 0x02, 0x04, | ||
| 321 | 0x02, 0xAB, 0xD2, 0xAA, 0xD2, 0x02, 0x4E, 0xFE, 0x39, 0x89, 0x01, 0x01, 0x11, 0x75, 0x01, 0x25, | ||
| 322 | 0x2F, 0x27, 0x0F, 0x08, 0x0C, 0x38, 0x33, 0x21, 0x19, 0x02, 0x01, 0x8A, 0x53, 0x0D, 0x0F, 0x2A, | ||
| 323 | 0x09, 0x04, 0x8A, 0x3A, 0x03, 0x01, 0x12, 0x1B, 0x71, 0x1B, 0x0C, 0x17, 0x0D, 0x18, 0x17, 0x09, | ||
| 324 | 0x11, 0x09, 0x1A, 0x01, 0x01, 0x07, 0x1E, 0x15, 0x29, 0x01, 0x2D, 0x2D, 0x1A, 0x2C, 0x16, 0x16, | ||
| 325 | 0x0D, 0x0F, 0x1A, 0x14, 0x0C, 0x0D, 0x27, 0x04, 0x0C, 0x03, 0x03, 0x04, 0x1E, 0x00, 0x00, 0x00, | ||
| 326 | 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x17, 0x00, 0x00, | ||
| 327 | 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x15, 0x33, 0x15, | ||
| 328 | 0x33, 0x35, 0x33, 0x35, 0x23, 0x35, 0x23, 0x15, 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, | ||
| 329 | 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC4, 0x50, 0xC4, 0xC5, 0x4E, 0x03, 0x70, 0x84, 0xE2, 0xFE, | ||
| 330 | 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0x4F, 0xC5, 0xC5, 0x4E, 0xC5, 0xC4, | ||
| 331 | 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0x00, | ||
| 332 | 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x21, 0x35, 0x21, | ||
| 333 | 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8, | ||
| 334 | 0xFE, 0x28, 0x03, 0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, | ||
| 335 | 0x71, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xAE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
| 336 | 0x00, 0x00, 0x00, 0x15, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, | ||
| 337 | 0x00, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x85, 0x00, 0x01, | ||
| 338 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0xAF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
| 339 | 0x00, 0x04, 0x00, 0x10, 0x00, 0xE2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0D, | ||
| 340 | 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x01, 0x3F, 0x00, 0x03, | ||
| 341 | 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, | ||
| 342 | 0x00, 0x01, 0x00, 0x20, 0x00, 0x42, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0E, | ||
| 343 | 0x00, 0x75, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x20, 0x00, 0x8D, 0x00, 0x03, | ||
| 344 | 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, | ||
| 345 | 0x00, 0x05, 0x00, 0x1A, 0x00, 0xF3, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x20, | ||
| 346 | 0x01, 0x1D, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6D, | ||
| 347 | 0x00, 0x75, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x20, 0x00, 0x50, | ||
| 348 | 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x00, 0x59, 0x75, | ||
| 349 | 0x7A, 0x75, 0x20, 0x45, 0x6D, 0x75, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x20, 0x50, 0x72, 0x6F, 0x6A, | ||
| 350 | 0x65, 0x63, 0x74, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, | ||
| 351 | 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, | ||
| 352 | 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, | ||
| 353 | 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, | ||
| 354 | 0x6C, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x00, 0x00, | ||
| 355 | 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, | ||
| 356 | 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, | ||
| 357 | 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F, | ||
| 358 | 0x6E, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, | ||
| 359 | 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, | ||
| 360 | 0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, | ||
| 361 | 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, | ||
| 362 | 0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, | ||
| 363 | 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x00, 0x00, | ||
| 364 | 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, | ||
| 365 | 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, | ||
| 366 | 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F, | ||
| 367 | 0x6E, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xB5, 0x00, 0x32, | ||
| 368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04, | ||
| 370 | 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, 0x01, 0x0C, | ||
| 371 | 0x01, 0x0D, 0x01, 0x0E, 0x01, 0x0F, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, | ||
| 372 | 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1A, 0x01, 0x1B, 0x07, 0x75, | ||
| 373 | 0x6E, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x30, 0x30, 0x30, 0x44, 0x07, 0x75, | ||
| 374 | 0x6E, 0x69, 0x45, 0x30, 0x41, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x31, 0x07, 0x75, | ||
| 375 | 0x6E, 0x69, 0x45, 0x30, 0x41, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x33, 0x07, 0x75, | ||
| 376 | 0x6E, 0x69, 0x45, 0x30, 0x41, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x35, 0x07, 0x75, | ||
| 377 | 0x6E, 0x69, 0x45, 0x30, 0x41, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x37, 0x07, 0x75, | ||
| 378 | 0x6E, 0x69, 0x45, 0x30, 0x41, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x39, 0x07, 0x75, | ||
| 379 | 0x6E, 0x69, 0x45, 0x30, 0x42, 0x33, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x42, 0x34, 0x07, 0x75, | ||
| 380 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x31, 0x07, 0x75, | ||
| 381 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x33, 0x07, 0x75, | ||
| 382 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x35, 0x07, 0x75, | ||
| 383 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x37, 0x07, 0x75, | ||
| 384 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x39, 0x07, 0x75, | ||
| 385 | 0x6E, 0x69, 0x45, 0x30, 0x45, 0x46, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x46, 0x30, 0x00, 0x00, | ||
| 386 | 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x0F, | ||
| 194 | }}; | 387 | }}; |
| 195 | 388 | ||
| 196 | } // namespace FileSys::SystemArchive::SharedFontData | 389 | } // namespace FileSys::SystemArchive::SharedFontData |
diff --git a/src/core/file_sys/system_archive/data/font_nintendo_extended.h b/src/core/file_sys/system_archive/data/font_nintendo_extended.h index 2089f3db9..edb9df914 100644 --- a/src/core/file_sys/system_archive/data/font_nintendo_extended.h +++ b/src/core/file_sys/system_archive/data/font_nintendo_extended.h | |||
| @@ -8,6 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys::SystemArchive::SharedFontData { | 9 | namespace FileSys::SystemArchive::SharedFontData { |
| 10 | 10 | ||
| 11 | extern const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED; | 11 | extern const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED; |
| 12 | 12 | ||
| 13 | } // namespace FileSys::SystemArchive::SharedFontData | 13 | } // namespace FileSys::SystemArchive::SharedFontData |
diff --git a/src/core/file_sys/system_archive/system_version.cpp b/src/core/file_sys/system_archive/system_version.cpp index aa313de66..7bfbc9a67 100644 --- a/src/core/file_sys/system_archive/system_version.cpp +++ b/src/core/file_sys/system_archive/system_version.cpp | |||
| @@ -12,17 +12,17 @@ namespace SystemVersionData { | |||
| 12 | // This section should reflect the best system version to describe yuzu's HLE api. | 12 | // This section should reflect the best system version to describe yuzu's HLE api. |
| 13 | // TODO(DarkLordZach): Update when HLE gets better. | 13 | // TODO(DarkLordZach): Update when HLE gets better. |
| 14 | 14 | ||
| 15 | constexpr u8 VERSION_MAJOR = 10; | 15 | constexpr u8 VERSION_MAJOR = 11; |
| 16 | constexpr u8 VERSION_MINOR = 0; | 16 | constexpr u8 VERSION_MINOR = 0; |
| 17 | constexpr u8 VERSION_MICRO = 2; | 17 | constexpr u8 VERSION_MICRO = 0; |
| 18 | 18 | ||
| 19 | constexpr u8 REVISION_MAJOR = 1; | 19 | constexpr u8 REVISION_MAJOR = 5; |
| 20 | constexpr u8 REVISION_MINOR = 0; | 20 | constexpr u8 REVISION_MINOR = 0; |
| 21 | 21 | ||
| 22 | constexpr char PLATFORM_STRING[] = "NX"; | 22 | constexpr char PLATFORM_STRING[] = "NX"; |
| 23 | constexpr char VERSION_HASH[] = "f90143fa8bbc061d4f68c35f95f04f8080c0ecdc"; | 23 | constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d"; |
| 24 | constexpr char DISPLAY_VERSION[] = "10.0.2"; | 24 | constexpr char DISPLAY_VERSION[] = "11.0.0"; |
| 25 | constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 10.0.2-1.0"; | 25 | constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0"; |
| 26 | 26 | ||
| 27 | } // namespace SystemVersionData | 27 | } // namespace SystemVersionData |
| 28 | 28 | ||
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index b2f026b6d..f497e9396 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const { | |||
| 203 | return GetContainingDirectory()->GetFullPath() + "/" + GetName(); | 203 | return GetContainingDirectory()->GetFullPath() + "/" + GetName(); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const { | 206 | VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const { |
| 207 | auto vec = Common::FS::SplitPathComponents(path); | 207 | auto vec = Common::FS::SplitPathComponents(path); |
| 208 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), | 208 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), |
| 209 | vec.end()); | 209 | vec.end()); |
| @@ -231,7 +231,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) co | |||
| 231 | return dir->GetFile(vec.back()); | 231 | return dir->GetFile(vec.back()); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) const { | 234 | VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const { |
| 235 | if (IsRoot()) { | 235 | if (IsRoot()) { |
| 236 | return GetFileRelative(path); | 236 | return GetFileRelative(path); |
| 237 | } | 237 | } |
| @@ -239,7 +239,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) co | |||
| 239 | return GetParentDirectory()->GetFileAbsolute(path); | 239 | return GetParentDirectory()->GetFileAbsolute(path); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const { | 242 | VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const { |
| 243 | auto vec = Common::FS::SplitPathComponents(path); | 243 | auto vec = Common::FS::SplitPathComponents(path); |
| 244 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), | 244 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), |
| 245 | vec.end()); | 245 | vec.end()); |
| @@ -261,7 +261,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_vie | |||
| 261 | return dir; | 261 | return dir; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_view path) const { | 264 | VirtualDir VfsDirectory::GetDirectoryAbsolute(std::string_view path) const { |
| 265 | if (IsRoot()) { | 265 | if (IsRoot()) { |
| 266 | return GetDirectoryRelative(path); | 266 | return GetDirectoryRelative(path); |
| 267 | } | 267 | } |
| @@ -269,14 +269,14 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_vie | |||
| 269 | return GetParentDirectory()->GetDirectoryAbsolute(path); | 269 | return GetParentDirectory()->GetDirectoryAbsolute(path); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | std::shared_ptr<VfsFile> VfsDirectory::GetFile(std::string_view name) const { | 272 | VirtualFile VfsDirectory::GetFile(std::string_view name) const { |
| 273 | const auto& files = GetFiles(); | 273 | const auto& files = GetFiles(); |
| 274 | const auto iter = std::find_if(files.begin(), files.end(), | 274 | const auto iter = std::find_if(files.begin(), files.end(), |
| 275 | [&name](const auto& file1) { return name == file1->GetName(); }); | 275 | [&name](const auto& file1) { return name == file1->GetName(); }); |
| 276 | return iter == files.end() ? nullptr : *iter; | 276 | return iter == files.end() ? nullptr : *iter; |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(std::string_view name) const { | 279 | VirtualDir VfsDirectory::GetSubdirectory(std::string_view name) const { |
| 280 | const auto& subs = GetSubdirectories(); | 280 | const auto& subs = GetSubdirectories(); |
| 281 | const auto iter = std::find_if(subs.begin(), subs.end(), | 281 | const auto iter = std::find_if(subs.begin(), subs.end(), |
| 282 | [&name](const auto& file1) { return name == file1->GetName(); }); | 282 | [&name](const auto& file1) { return name == file1->GetName(); }); |
| @@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const { | |||
| 301 | return file_total + subdir_total; | 301 | return file_total + subdir_total; |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) { | 304 | VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) { |
| 305 | auto vec = Common::FS::SplitPathComponents(path); | 305 | auto vec = Common::FS::SplitPathComponents(path); |
| 306 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), | 306 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), |
| 307 | vec.end()); | 307 | vec.end()); |
| @@ -324,7 +324,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) | |||
| 324 | return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path)); | 324 | return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path)); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) { | 327 | VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) { |
| 328 | if (IsRoot()) { | 328 | if (IsRoot()) { |
| 329 | return CreateFileRelative(path); | 329 | return CreateFileRelative(path); |
| 330 | } | 330 | } |
| @@ -332,7 +332,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) | |||
| 332 | return GetParentDirectory()->CreateFileAbsolute(path); | 332 | return GetParentDirectory()->CreateFileAbsolute(path); |
| 333 | } | 333 | } |
| 334 | 334 | ||
| 335 | std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) { | 335 | VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) { |
| 336 | auto vec = Common::FS::SplitPathComponents(path); | 336 | auto vec = Common::FS::SplitPathComponents(path); |
| 337 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), | 337 | vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), |
| 338 | vec.end()); | 338 | vec.end()); |
| @@ -355,7 +355,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_ | |||
| 355 | return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path)); | 355 | return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path)); |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) { | 358 | VirtualDir VfsDirectory::CreateDirectoryAbsolute(std::string_view path) { |
| 359 | if (IsRoot()) { | 359 | if (IsRoot()) { |
| 360 | return CreateDirectoryRelative(path); | 360 | return CreateDirectoryRelative(path); |
| 361 | } | 361 | } |
| @@ -446,27 +446,27 @@ bool ReadOnlyVfsDirectory::IsReadable() const { | |||
| 446 | return true; | 446 | return true; |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) { | 449 | VirtualDir ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) { |
| 450 | return nullptr; | 450 | return nullptr; |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) { | 453 | VirtualFile ReadOnlyVfsDirectory::CreateFile(std::string_view name) { |
| 454 | return nullptr; | 454 | return nullptr; |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) { | 457 | VirtualFile ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) { |
| 458 | return nullptr; | 458 | return nullptr; |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) { | 461 | VirtualFile ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) { |
| 462 | return nullptr; | 462 | return nullptr; |
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) { | 465 | VirtualDir ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) { |
| 466 | return nullptr; | 466 | return nullptr; |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) { | 469 | VirtualDir ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) { |
| 470 | return nullptr; | 470 | return nullptr; |
| 471 | } | 471 | } |
| 472 | 472 | ||
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 954094772..afd64e95c 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -91,7 +91,7 @@ public: | |||
| 91 | // Resizes the file to new_size. Returns whether or not the operation was successful. | 91 | // Resizes the file to new_size. Returns whether or not the operation was successful. |
| 92 | virtual bool Resize(std::size_t new_size) = 0; | 92 | virtual bool Resize(std::size_t new_size) = 0; |
| 93 | // Gets a pointer to the directory containing this file, returning nullptr if there is none. | 93 | // Gets a pointer to the directory containing this file, returning nullptr if there is none. |
| 94 | virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0; | 94 | virtual VirtualDir GetContainingDirectory() const = 0; |
| 95 | 95 | ||
| 96 | // Returns whether or not the file can be written to. | 96 | // Returns whether or not the file can be written to. |
| 97 | virtual bool IsWritable() const = 0; | 97 | virtual bool IsWritable() const = 0; |
| @@ -183,27 +183,27 @@ public: | |||
| 183 | 183 | ||
| 184 | // Retrives the file located at path as if the current directory was root. Returns nullptr if | 184 | // Retrives the file located at path as if the current directory was root. Returns nullptr if |
| 185 | // not found. | 185 | // not found. |
| 186 | virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const; | 186 | virtual VirtualFile GetFileRelative(std::string_view path) const; |
| 187 | // Calls GetFileRelative(path) on the root of the current directory. | 187 | // Calls GetFileRelative(path) on the root of the current directory. |
| 188 | virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const; | 188 | virtual VirtualFile GetFileAbsolute(std::string_view path) const; |
| 189 | 189 | ||
| 190 | // Retrives the directory located at path as if the current directory was root. Returns nullptr | 190 | // Retrives the directory located at path as if the current directory was root. Returns nullptr |
| 191 | // if not found. | 191 | // if not found. |
| 192 | virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const; | 192 | virtual VirtualDir GetDirectoryRelative(std::string_view path) const; |
| 193 | // Calls GetDirectoryRelative(path) on the root of the current directory. | 193 | // Calls GetDirectoryRelative(path) on the root of the current directory. |
| 194 | virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const; | 194 | virtual VirtualDir GetDirectoryAbsolute(std::string_view path) const; |
| 195 | 195 | ||
| 196 | // Returns a vector containing all of the files in this directory. | 196 | // Returns a vector containing all of the files in this directory. |
| 197 | virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0; | 197 | virtual std::vector<VirtualFile> GetFiles() const = 0; |
| 198 | // Returns the file with filename matching name. Returns nullptr if directory dosen't have a | 198 | // Returns the file with filename matching name. Returns nullptr if directory dosen't have a |
| 199 | // file with name. | 199 | // file with name. |
| 200 | virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const; | 200 | virtual VirtualFile GetFile(std::string_view name) const; |
| 201 | 201 | ||
| 202 | // Returns a vector containing all of the subdirectories in this directory. | 202 | // Returns a vector containing all of the subdirectories in this directory. |
| 203 | virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0; | 203 | virtual std::vector<VirtualDir> GetSubdirectories() const = 0; |
| 204 | // Returns the directory with name matching name. Returns nullptr if directory dosen't have a | 204 | // Returns the directory with name matching name. Returns nullptr if directory dosen't have a |
| 205 | // directory with name. | 205 | // directory with name. |
| 206 | virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const; | 206 | virtual VirtualDir GetSubdirectory(std::string_view name) const; |
| 207 | 207 | ||
| 208 | // Returns whether or not the directory can be written to. | 208 | // Returns whether or not the directory can be written to. |
| 209 | virtual bool IsWritable() const = 0; | 209 | virtual bool IsWritable() const = 0; |
| @@ -219,31 +219,31 @@ public: | |||
| 219 | virtual std::size_t GetSize() const; | 219 | virtual std::size_t GetSize() const; |
| 220 | // Returns the parent directory of this directory. Returns nullptr if this directory is root or | 220 | // Returns the parent directory of this directory. Returns nullptr if this directory is root or |
| 221 | // has no parent. | 221 | // has no parent. |
| 222 | virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0; | 222 | virtual VirtualDir GetParentDirectory() const = 0; |
| 223 | 223 | ||
| 224 | // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr | 224 | // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr |
| 225 | // if the operation failed. | 225 | // if the operation failed. |
| 226 | virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0; | 226 | virtual VirtualDir CreateSubdirectory(std::string_view name) = 0; |
| 227 | // Creates a new file with name name. Returns a pointer to the new file or nullptr if the | 227 | // Creates a new file with name name. Returns a pointer to the new file or nullptr if the |
| 228 | // operation failed. | 228 | // operation failed. |
| 229 | virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0; | 229 | virtual VirtualFile CreateFile(std::string_view name) = 0; |
| 230 | 230 | ||
| 231 | // Creates a new file at the path relative to this directory. Also creates directories if | 231 | // Creates a new file at the path relative to this directory. Also creates directories if |
| 232 | // they do not exist and is supported by this implementation. Returns nullptr on any failure. | 232 | // they do not exist and is supported by this implementation. Returns nullptr on any failure. |
| 233 | virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path); | 233 | virtual VirtualFile CreateFileRelative(std::string_view path); |
| 234 | 234 | ||
| 235 | // Creates a new file at the path relative to root of this directory. Also creates directories | 235 | // Creates a new file at the path relative to root of this directory. Also creates directories |
| 236 | // if they do not exist and is supported by this implementation. Returns nullptr on any failure. | 236 | // if they do not exist and is supported by this implementation. Returns nullptr on any failure. |
| 237 | virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path); | 237 | virtual VirtualFile CreateFileAbsolute(std::string_view path); |
| 238 | 238 | ||
| 239 | // Creates a new directory at the path relative to this directory. Also creates directories if | 239 | // Creates a new directory at the path relative to this directory. Also creates directories if |
| 240 | // they do not exist and is supported by this implementation. Returns nullptr on any failure. | 240 | // they do not exist and is supported by this implementation. Returns nullptr on any failure. |
| 241 | virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path); | 241 | virtual VirtualDir CreateDirectoryRelative(std::string_view path); |
| 242 | 242 | ||
| 243 | // Creates a new directory at the path relative to root of this directory. Also creates | 243 | // Creates a new directory at the path relative to root of this directory. Also creates |
| 244 | // directories if they do not exist and is supported by this implementation. Returns nullptr on | 244 | // directories if they do not exist and is supported by this implementation. Returns nullptr on |
| 245 | // any failure. | 245 | // any failure. |
| 246 | virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); | 246 | virtual VirtualDir CreateDirectoryAbsolute(std::string_view path); |
| 247 | 247 | ||
| 248 | // Deletes the subdirectory with the given 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; |
| @@ -280,12 +280,12 @@ class ReadOnlyVfsDirectory : public VfsDirectory { | |||
| 280 | public: | 280 | public: |
| 281 | bool IsWritable() const override; | 281 | bool IsWritable() const override; |
| 282 | bool IsReadable() const override; | 282 | bool IsReadable() const override; |
| 283 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; | 283 | VirtualDir CreateSubdirectory(std::string_view name) override; |
| 284 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; | 284 | VirtualFile CreateFile(std::string_view name) override; |
| 285 | std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override; | 285 | VirtualFile CreateFileAbsolute(std::string_view path) override; |
| 286 | std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; | 286 | VirtualFile CreateFileRelative(std::string_view path) override; |
| 287 | std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override; | 287 | VirtualDir CreateDirectoryAbsolute(std::string_view path) override; |
| 288 | std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; | 288 | VirtualDir CreateDirectoryRelative(std::string_view path) override; |
| 289 | bool DeleteSubdirectory(std::string_view name) override; | 289 | bool DeleteSubdirectory(std::string_view name) override; |
| 290 | bool DeleteSubdirectoryRecursive(std::string_view name) override; | 290 | bool DeleteSubdirectoryRecursive(std::string_view name) override; |
| 291 | bool CleanSubdirectoryRecursive(std::string_view name) override; | 291 | bool CleanSubdirectoryRecursive(std::string_view name) override; |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index e0ff70174..3c5a7d87a 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -46,7 +46,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f | |||
| 46 | if (files.size() == 1) | 46 | if (files.size() == 1) |
| 47 | return files[0]; | 47 | return files[0]; |
| 48 | 48 | ||
| 49 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | 49 | return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name))); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, | 52 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, |
| @@ -71,20 +71,23 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, | |||
| 71 | if (files.begin()->first != 0) | 71 | if (files.begin()->first != 0) |
| 72 | files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); | 72 | files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); |
| 73 | 73 | ||
| 74 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | 74 | return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name))); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | std::string ConcatenatedVfsFile::GetName() const { | 77 | std::string ConcatenatedVfsFile::GetName() const { |
| 78 | if (files.empty()) | 78 | if (files.empty()) { |
| 79 | return ""; | 79 | return ""; |
| 80 | if (!name.empty()) | 80 | } |
| 81 | if (!name.empty()) { | ||
| 81 | return name; | 82 | return name; |
| 83 | } | ||
| 82 | return files.begin()->second->GetName(); | 84 | return files.begin()->second->GetName(); |
| 83 | } | 85 | } |
| 84 | 86 | ||
| 85 | std::size_t ConcatenatedVfsFile::GetSize() const { | 87 | std::size_t ConcatenatedVfsFile::GetSize() const { |
| 86 | if (files.empty()) | 88 | if (files.empty()) { |
| 87 | return 0; | 89 | return 0; |
| 90 | } | ||
| 88 | return files.rbegin()->first + files.rbegin()->second->GetSize(); | 91 | return files.rbegin()->first + files.rbegin()->second->GetSize(); |
| 89 | } | 92 | } |
| 90 | 93 | ||
| @@ -92,9 +95,10 @@ bool ConcatenatedVfsFile::Resize(std::size_t new_size) { | |||
| 92 | return false; | 95 | return false; |
| 93 | } | 96 | } |
| 94 | 97 | ||
| 95 | std::shared_ptr<VfsDirectory> ConcatenatedVfsFile::GetContainingDirectory() const { | 98 | VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const { |
| 96 | if (files.empty()) | 99 | if (files.empty()) { |
| 97 | return nullptr; | 100 | return nullptr; |
| 101 | } | ||
| 98 | return files.begin()->second->GetContainingDirectory(); | 102 | return files.begin()->second->GetContainingDirectory(); |
| 99 | } | 103 | } |
| 100 | 104 | ||
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index 7a26343c0..287c72555 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -31,7 +31,7 @@ public: | |||
| 31 | std::string GetName() const override; | 31 | std::string GetName() const override; |
| 32 | std::size_t GetSize() const override; | 32 | std::size_t GetSize() const override; |
| 33 | bool Resize(std::size_t new_size) override; | 33 | bool Resize(std::size_t new_size) override; |
| 34 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 34 | VirtualDir GetContainingDirectory() const override; |
| 35 | bool IsWritable() const override; | 35 | bool IsWritable() const override; |
| 36 | bool IsReadable() const override; | 36 | bool IsReadable() const override; |
| 37 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; | 37 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 338e398da..434b03cec 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -20,10 +20,10 @@ VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dir | |||
| 20 | if (dirs.size() == 1) | 20 | if (dirs.size() == 1) |
| 21 | return dirs[0]; | 21 | return dirs[0]; |
| 22 | 22 | ||
| 23 | return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); | 23 | return VirtualDir(new LayeredVfsDirectory(std::move(dirs), std::move(name))); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { | 26 | VirtualFile LayeredVfsDirectory::GetFileRelative(std::string_view path) const { |
| 27 | for (const auto& layer : dirs) { | 27 | for (const auto& layer : dirs) { |
| 28 | const auto file = layer->GetFileRelative(path); | 28 | const auto file = layer->GetFileRelative(path); |
| 29 | if (file != nullptr) | 29 | if (file != nullptr) |
| @@ -33,23 +33,23 @@ std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view p | |||
| 33 | return nullptr; | 33 | return nullptr; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative( | 36 | VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) const { |
| 37 | std::string_view path) const { | ||
| 38 | std::vector<VirtualDir> out; | 37 | std::vector<VirtualDir> out; |
| 39 | for (const auto& layer : dirs) { | 38 | for (const auto& layer : dirs) { |
| 40 | auto dir = layer->GetDirectoryRelative(path); | 39 | auto dir = layer->GetDirectoryRelative(path); |
| 41 | if (dir != nullptr) | 40 | if (dir != nullptr) { |
| 42 | out.push_back(std::move(dir)); | 41 | out.push_back(std::move(dir)); |
| 42 | } | ||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | return MakeLayeredDirectory(std::move(out)); | 45 | return MakeLayeredDirectory(std::move(out)); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { | 48 | VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const { |
| 49 | return GetFileRelative(name); | 49 | return GetFileRelative(name); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetSubdirectory(std::string_view name) const { | 52 | VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const { |
| 53 | return GetDirectoryRelative(name); | 53 | return GetDirectoryRelative(name); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| @@ -57,7 +57,7 @@ std::string LayeredVfsDirectory::GetFullPath() const { | |||
| 57 | return dirs[0]->GetFullPath(); | 57 | return dirs[0]->GetFullPath(); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const { | 60 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { |
| 61 | std::vector<VirtualFile> out; | 61 | std::vector<VirtualFile> out; |
| 62 | for (const auto& layer : dirs) { | 62 | for (const auto& layer : dirs) { |
| 63 | for (const auto& file : layer->GetFiles()) { | 63 | for (const auto& file : layer->GetFiles()) { |
| @@ -72,7 +72,7 @@ std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const { | |||
| 72 | return out; | 72 | return out; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | std::vector<std::shared_ptr<VfsDirectory>> LayeredVfsDirectory::GetSubdirectories() const { | 75 | std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { |
| 76 | std::vector<std::string> names; | 76 | std::vector<std::string> names; |
| 77 | for (const auto& layer : dirs) { | 77 | for (const auto& layer : dirs) { |
| 78 | for (const auto& sd : layer->GetSubdirectories()) { | 78 | for (const auto& sd : layer->GetSubdirectories()) { |
| @@ -101,15 +101,15 @@ std::string LayeredVfsDirectory::GetName() const { | |||
| 101 | return name.empty() ? dirs[0]->GetName() : name; | 101 | return name.empty() ? dirs[0]->GetName() : name; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetParentDirectory() const { | 104 | VirtualDir LayeredVfsDirectory::GetParentDirectory() const { |
| 105 | return dirs[0]->GetParentDirectory(); | 105 | return dirs[0]->GetParentDirectory(); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | std::shared_ptr<VfsDirectory> LayeredVfsDirectory::CreateSubdirectory(std::string_view name) { | 108 | VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) { |
| 109 | return nullptr; | 109 | return nullptr; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | std::shared_ptr<VfsFile> LayeredVfsDirectory::CreateFile(std::string_view name) { | 112 | VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) { |
| 113 | return nullptr; | 113 | return nullptr; |
| 114 | } | 114 | } |
| 115 | 115 | ||
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h index 8a25c3428..6d7513ac6 100644 --- a/src/core/file_sys/vfs_layered.h +++ b/src/core/file_sys/vfs_layered.h | |||
| @@ -21,20 +21,20 @@ public: | |||
| 21 | /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. | 21 | /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. |
| 22 | static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = ""); | 22 | static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = ""); |
| 23 | 23 | ||
| 24 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | 24 | VirtualFile GetFileRelative(std::string_view path) const override; |
| 25 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | 25 | VirtualDir GetDirectoryRelative(std::string_view path) const override; |
| 26 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | 26 | VirtualFile GetFile(std::string_view name) const override; |
| 27 | std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override; | 27 | VirtualDir GetSubdirectory(std::string_view name) const override; |
| 28 | std::string GetFullPath() const override; | 28 | std::string GetFullPath() const override; |
| 29 | 29 | ||
| 30 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 30 | std::vector<VirtualFile> GetFiles() const override; |
| 31 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 31 | std::vector<VirtualDir> GetSubdirectories() const override; |
| 32 | bool IsWritable() const override; | 32 | bool IsWritable() const override; |
| 33 | bool IsReadable() const override; | 33 | bool IsReadable() const override; |
| 34 | std::string GetName() const override; | 34 | std::string GetName() const override; |
| 35 | std::shared_ptr<VfsDirectory> GetParentDirectory() const override; | 35 | VirtualDir GetParentDirectory() const override; |
| 36 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; | 36 | VirtualDir CreateSubdirectory(std::string_view name) override; |
| 37 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; | 37 | VirtualFile CreateFile(std::string_view name) override; |
| 38 | bool DeleteSubdirectory(std::string_view name) override; | 38 | bool DeleteSubdirectory(std::string_view name) override; |
| 39 | bool DeleteFile(std::string_view name) override; | 39 | bool DeleteFile(std::string_view name) override; |
| 40 | bool Rename(std::string_view name) override; | 40 | bool Rename(std::string_view name) override; |
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index 7714d3de5..056737b54 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace FileSys { | 10 | namespace FileSys { |
| 11 | 11 | ||
| 12 | OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_, std::size_t offset_, | 12 | OffsetVfsFile::OffsetVfsFile(VirtualFile file_, std::size_t size_, std::size_t offset_, |
| 13 | std::string name_, VirtualDir parent_) | 13 | std::string name_, VirtualDir parent_) |
| 14 | : file(file_), offset(offset_), size(size_), name(std::move(name_)), | 14 | : file(file_), offset(offset_), size(size_), name(std::move(name_)), |
| 15 | parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} | 15 | parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} |
| @@ -37,7 +37,7 @@ bool OffsetVfsFile::Resize(std::size_t new_size) { | |||
| 37 | return true; | 37 | return true; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const { | 40 | VirtualDir OffsetVfsFile::GetContainingDirectory() const { |
| 41 | return parent; | 41 | return parent; |
| 42 | } | 42 | } |
| 43 | 43 | ||
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index f7b7a3256..b2ccc5c7b 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h | |||
| @@ -17,14 +17,14 @@ namespace FileSys { | |||
| 17 | // the size of this wrapper. | 17 | // the size of this wrapper. |
| 18 | class OffsetVfsFile : public VfsFile { | 18 | class OffsetVfsFile : public VfsFile { |
| 19 | public: | 19 | public: |
| 20 | OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0, | 20 | OffsetVfsFile(VirtualFile file, std::size_t size, std::size_t offset = 0, |
| 21 | std::string new_name = "", VirtualDir new_parent = nullptr); | 21 | std::string new_name = "", VirtualDir new_parent = nullptr); |
| 22 | ~OffsetVfsFile() override; | 22 | ~OffsetVfsFile() override; |
| 23 | 23 | ||
| 24 | std::string GetName() const override; | 24 | std::string GetName() const override; |
| 25 | std::size_t GetSize() const override; | 25 | std::size_t GetSize() const override; |
| 26 | bool Resize(std::size_t new_size) override; | 26 | bool Resize(std::size_t new_size) override; |
| 27 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 27 | VirtualDir GetContainingDirectory() const override; |
| 28 | bool IsWritable() const override; | 28 | bool IsWritable() const override; |
| 29 | bool IsReadable() const override; | 29 | bool IsReadable() const override; |
| 30 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; | 30 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
| @@ -42,7 +42,7 @@ public: | |||
| 42 | private: | 42 | private: |
| 43 | std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; | 43 | std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; |
| 44 | 44 | ||
| 45 | std::shared_ptr<VfsFile> file; | 45 | VirtualFile file; |
| 46 | std::size_t offset; | 46 | std::size_t offset; |
| 47 | std::size_t size; | 47 | std::size_t size; |
| 48 | std::string name; | 48 | std::string name; |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 488687ba9..a287eebe3 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -263,7 +263,7 @@ bool RealVfsFile::Resize(std::size_t new_size) { | |||
| 263 | return backing->Resize(new_size); | 263 | return backing->Resize(new_size); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { | 266 | VirtualDir RealVfsFile::GetContainingDirectory() const { |
| 267 | return base.OpenDirectory(parent_path, perms); | 267 | return base.OpenDirectory(parent_path, perms); |
| 268 | } | 268 | } |
| 269 | 269 | ||
| @@ -352,7 +352,7 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& | |||
| 352 | 352 | ||
| 353 | RealVfsDirectory::~RealVfsDirectory() = default; | 353 | RealVfsDirectory::~RealVfsDirectory() = default; |
| 354 | 354 | ||
| 355 | std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const { | 355 | VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const { |
| 356 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); | 356 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 357 | if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) { | 357 | if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) { |
| 358 | return nullptr; | 358 | return nullptr; |
| @@ -360,7 +360,7 @@ std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path | |||
| 360 | return base.OpenFile(full_path, perms); | 360 | return base.OpenFile(full_path, perms); |
| 361 | } | 361 | } |
| 362 | 362 | ||
| 363 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { | 363 | VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { |
| 364 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); | 364 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 365 | if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) { | 365 | if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) { |
| 366 | return nullptr; | 366 | return nullptr; |
| @@ -368,20 +368,20 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string | |||
| 368 | return base.OpenDirectory(full_path, perms); | 368 | return base.OpenDirectory(full_path, perms); |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const { | 371 | VirtualFile RealVfsDirectory::GetFile(std::string_view name) const { |
| 372 | return GetFileRelative(name); | 372 | return GetFileRelative(name); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const { | 375 | VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const { |
| 376 | return GetDirectoryRelative(name); | 376 | return GetDirectoryRelative(name); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) { | 379 | VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) { |
| 380 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); | 380 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 381 | return base.CreateFile(full_path, perms); | 381 | return base.CreateFile(full_path, perms); |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { | 384 | VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { |
| 385 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); | 385 | const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 386 | return base.CreateDirectory(full_path, perms); | 386 | return base.CreateDirectory(full_path, perms); |
| 387 | } | 387 | } |
| @@ -391,11 +391,11 @@ bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { | |||
| 391 | return base.DeleteDirectory(full_path); | 391 | return base.DeleteDirectory(full_path); |
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { | 394 | std::vector<VirtualFile> RealVfsDirectory::GetFiles() const { |
| 395 | return IterateEntries<RealVfsFile, VfsFile>(); | 395 | return IterateEntries<RealVfsFile, VfsFile>(); |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { | 398 | std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const { |
| 399 | return IterateEntries<RealVfsDirectory, VfsDirectory>(); | 399 | return IterateEntries<RealVfsDirectory, VfsDirectory>(); |
| 400 | } | 400 | } |
| 401 | 401 | ||
| @@ -411,7 +411,7 @@ std::string RealVfsDirectory::GetName() const { | |||
| 411 | return path_components.back(); | 411 | return path_components.back(); |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const { | 414 | VirtualDir RealVfsDirectory::GetParentDirectory() const { |
| 415 | if (path_components.size() <= 1) { | 415 | if (path_components.size() <= 1) { |
| 416 | return nullptr; | 416 | return nullptr; |
| 417 | } | 417 | } |
| @@ -419,12 +419,12 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const { | |||
| 419 | return base.OpenDirectory(parent_path, perms); | 419 | return base.OpenDirectory(parent_path, perms); |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { | 422 | VirtualDir RealVfsDirectory::CreateSubdirectory(std::string_view name) { |
| 423 | const std::string subdir_path = (path + DIR_SEP).append(name); | 423 | const std::string subdir_path = (path + DIR_SEP).append(name); |
| 424 | return base.CreateDirectory(subdir_path, perms); | 424 | return base.CreateDirectory(subdir_path, perms); |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { | 427 | VirtualFile RealVfsDirectory::CreateFile(std::string_view name) { |
| 428 | const std::string file_path = (path + DIR_SEP).append(name); | 428 | const std::string file_path = (path + DIR_SEP).append(name); |
| 429 | return base.CreateFile(file_path, perms); | 429 | return base.CreateFile(file_path, perms); |
| 430 | } | 430 | } |
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 0b537b22c..23e99865e 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h | |||
| @@ -50,7 +50,7 @@ public: | |||
| 50 | std::string GetName() const override; | 50 | std::string GetName() const override; |
| 51 | std::size_t GetSize() const override; | 51 | std::size_t GetSize() const override; |
| 52 | bool Resize(std::size_t new_size) override; | 52 | bool Resize(std::size_t new_size) override; |
| 53 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 53 | VirtualDir GetContainingDirectory() const override; |
| 54 | bool IsWritable() const override; | 54 | bool IsWritable() const override; |
| 55 | bool IsReadable() const override; | 55 | bool IsReadable() const override; |
| 56 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; | 56 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
| @@ -79,21 +79,21 @@ class RealVfsDirectory : public VfsDirectory { | |||
| 79 | public: | 79 | public: |
| 80 | ~RealVfsDirectory() override; | 80 | ~RealVfsDirectory() override; |
| 81 | 81 | ||
| 82 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | 82 | VirtualFile GetFileRelative(std::string_view path) const override; |
| 83 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | 83 | VirtualDir GetDirectoryRelative(std::string_view path) const override; |
| 84 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | 84 | VirtualFile GetFile(std::string_view name) const override; |
| 85 | std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override; | 85 | VirtualDir GetSubdirectory(std::string_view name) const override; |
| 86 | std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; | 86 | VirtualFile CreateFileRelative(std::string_view path) override; |
| 87 | std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; | 87 | VirtualDir CreateDirectoryRelative(std::string_view path) override; |
| 88 | bool DeleteSubdirectoryRecursive(std::string_view name) override; | 88 | bool DeleteSubdirectoryRecursive(std::string_view name) override; |
| 89 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 89 | std::vector<VirtualFile> GetFiles() const override; |
| 90 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 90 | std::vector<VirtualDir> GetSubdirectories() const override; |
| 91 | bool IsWritable() const override; | 91 | bool IsWritable() const override; |
| 92 | bool IsReadable() const override; | 92 | bool IsReadable() const override; |
| 93 | std::string GetName() const override; | 93 | std::string GetName() const override; |
| 94 | std::shared_ptr<VfsDirectory> GetParentDirectory() const override; | 94 | VirtualDir GetParentDirectory() const override; |
| 95 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; | 95 | VirtualDir CreateSubdirectory(std::string_view name) override; |
| 96 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; | 96 | VirtualFile CreateFile(std::string_view name) override; |
| 97 | bool DeleteSubdirectory(std::string_view name) override; | 97 | bool DeleteSubdirectory(std::string_view name) override; |
| 98 | bool DeleteFile(std::string_view name) override; | 98 | bool DeleteFile(std::string_view name) override; |
| 99 | bool Rename(std::string_view name) override; | 99 | bool Rename(std::string_view name) override; |
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 8b27c30fa..c840b24b9 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h | |||
| @@ -31,7 +31,7 @@ public: | |||
| 31 | return true; | 31 | return true; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override { | 34 | VirtualDir GetContainingDirectory() const override { |
| 35 | return parent; | 35 | return parent; |
| 36 | } | 36 | } |
| 37 | 37 | ||
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 75fc04302..c1ec1e645 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp | |||
| @@ -25,7 +25,7 @@ bool VectorVfsFile::Resize(size_t new_size) { | |||
| 25 | return true; | 25 | return true; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | std::shared_ptr<VfsDirectory> VectorVfsFile::GetContainingDirectory() const { | 28 | VirtualDir VectorVfsFile::GetContainingDirectory() const { |
| 29 | return parent; | 29 | return parent; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| @@ -68,11 +68,11 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, | |||
| 68 | 68 | ||
| 69 | VectorVfsDirectory::~VectorVfsDirectory() = default; | 69 | VectorVfsDirectory::~VectorVfsDirectory() = default; |
| 70 | 70 | ||
| 71 | std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { | 71 | std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const { |
| 72 | return files; | 72 | return files; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const { | 75 | std::vector<VirtualDir> VectorVfsDirectory::GetSubdirectories() const { |
| 76 | return dirs; | 76 | return dirs; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| @@ -88,7 +88,7 @@ std::string VectorVfsDirectory::GetName() const { | |||
| 88 | return name; | 88 | return name; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const { | 91 | VirtualDir VectorVfsDirectory::GetParentDirectory() const { |
| 92 | return parent; | 92 | return parent; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| @@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) { | |||
| 116 | return true; | 116 | return true; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) { | 119 | VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) { |
| 120 | return nullptr; | 120 | return nullptr; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) { | 123 | VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) { |
| 124 | return nullptr; | 124 | return nullptr; |
| 125 | } | 125 | } |
| 126 | 126 | ||
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 95d3da2f2..2aff9ca34 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h | |||
| @@ -17,9 +17,9 @@ namespace FileSys { | |||
| 17 | template <std::size_t size> | 17 | template <std::size_t size> |
| 18 | class ArrayVfsFile : public VfsFile { | 18 | class ArrayVfsFile : public VfsFile { |
| 19 | public: | 19 | public: |
| 20 | explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "", | 20 | explicit ArrayVfsFile(const std::array<u8, size>& data_, std::string name_ = "", |
| 21 | VirtualDir parent = nullptr) | 21 | VirtualDir parent_ = nullptr) |
| 22 | : data(data), name(std::move(name)), parent(std::move(parent)) {} | 22 | : data(data_), name(std::move(name_)), parent(std::move(parent_)) {} |
| 23 | 23 | ||
| 24 | std::string GetName() const override { | 24 | std::string GetName() const override { |
| 25 | return name; | 25 | return name; |
| @@ -33,7 +33,7 @@ public: | |||
| 33 | return false; | 33 | return false; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override { | 36 | VirtualDir GetContainingDirectory() const override { |
| 37 | return parent; | 37 | return parent; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| @@ -51,12 +51,12 @@ public: | |||
| 51 | return read; | 51 | return read; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override { | 54 | std::size_t Write(const u8* data_, std::size_t length, std::size_t offset) override { |
| 55 | return 0; | 55 | return 0; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | bool Rename(std::string_view name) override { | 58 | bool Rename(std::string_view new_name) override { |
| 59 | this->name = name; | 59 | name = new_name; |
| 60 | return true; | 60 | return true; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| @@ -82,7 +82,7 @@ public: | |||
| 82 | std::string GetName() const override; | 82 | std::string GetName() const override; |
| 83 | std::size_t GetSize() const override; | 83 | std::size_t GetSize() const override; |
| 84 | bool Resize(std::size_t new_size) override; | 84 | bool Resize(std::size_t new_size) override; |
| 85 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 85 | VirtualDir GetContainingDirectory() const override; |
| 86 | bool IsWritable() const override; | 86 | bool IsWritable() const override; |
| 87 | bool IsReadable() const override; | 87 | bool IsReadable() const override; |
| 88 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; | 88 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
| @@ -106,17 +106,17 @@ public: | |||
| 106 | VirtualDir parent = nullptr); | 106 | VirtualDir parent = nullptr); |
| 107 | ~VectorVfsDirectory() override; | 107 | ~VectorVfsDirectory() override; |
| 108 | 108 | ||
| 109 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 109 | std::vector<VirtualFile> GetFiles() const override; |
| 110 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 110 | std::vector<VirtualDir> GetSubdirectories() const override; |
| 111 | bool IsWritable() const override; | 111 | bool IsWritable() const override; |
| 112 | bool IsReadable() const override; | 112 | bool IsReadable() const override; |
| 113 | std::string GetName() const override; | 113 | std::string GetName() const override; |
| 114 | std::shared_ptr<VfsDirectory> GetParentDirectory() const override; | 114 | VirtualDir GetParentDirectory() const override; |
| 115 | bool DeleteSubdirectory(std::string_view name) override; | 115 | bool DeleteSubdirectory(std::string_view name) override; |
| 116 | bool DeleteFile(std::string_view name) override; | 116 | bool DeleteFile(std::string_view name) override; |
| 117 | bool Rename(std::string_view name) override; | 117 | bool Rename(std::string_view name) override; |
| 118 | std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; | 118 | VirtualDir CreateSubdirectory(std::string_view name) override; |
| 119 | std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; | 119 | VirtualFile CreateFile(std::string_view name) override; |
| 120 | 120 | ||
| 121 | virtual void AddFile(VirtualFile file); | 121 | virtual void AddFile(VirtualFile file); |
| 122 | virtual void AddDirectory(VirtualDir dir); | 122 | virtual void AddDirectory(VirtualDir dir); |
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 24c58e7ae..814fd5680 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp | |||
| @@ -152,11 +152,11 @@ NAXContentType NAX::GetContentType() const { | |||
| 152 | return type; | 152 | return type; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | std::vector<std::shared_ptr<VfsFile>> NAX::GetFiles() const { | 155 | std::vector<VirtualFile> NAX::GetFiles() const { |
| 156 | return {dec_file}; | 156 | return {dec_file}; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | std::vector<std::shared_ptr<VfsDirectory>> NAX::GetSubdirectories() const { | 159 | std::vector<VirtualDir> NAX::GetSubdirectories() const { |
| 160 | return {}; | 160 | return {}; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| @@ -164,7 +164,7 @@ std::string NAX::GetName() const { | |||
| 164 | return file->GetName(); | 164 | return file->GetName(); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | std::shared_ptr<VfsDirectory> NAX::GetParentDirectory() const { | 167 | VirtualDir NAX::GetParentDirectory() const { |
| 168 | return file->GetContainingDirectory(); | 168 | return file->GetContainingDirectory(); |
| 169 | } | 169 | } |
| 170 | 170 | ||
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index c472e226e..63a032b68 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h | |||
| @@ -47,13 +47,13 @@ public: | |||
| 47 | 47 | ||
| 48 | NAXContentType GetContentType() const; | 48 | NAXContentType GetContentType() const; |
| 49 | 49 | ||
| 50 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 50 | std::vector<VirtualFile> GetFiles() const override; |
| 51 | 51 | ||
| 52 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 52 | std::vector<VirtualDir> GetSubdirectories() const override; |
| 53 | 53 | ||
| 54 | std::string GetName() const override; | 54 | std::string GetName() const override; |
| 55 | 55 | ||
| 56 | std::shared_ptr<VfsDirectory> GetParentDirectory() const override; | 56 | VirtualDir GetParentDirectory() const override; |
| 57 | 57 | ||
| 58 | private: | 58 | private: |
| 59 | Loader::ResultStatus Parse(std::string_view path); | 59 | Loader::ResultStatus Parse(std::string_view path); |
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 4505da758..03bbedf8b 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 8 | #include "core/frontend/applets/controller.h" | 7 | #include "core/frontend/applets/controller.h" |
| 9 | #include "core/hle/service/hid/controllers/npad.h" | 8 | #include "core/hle/service/hid/controllers/npad.h" |
| 10 | #include "core/hle/service/hid/hid.h" | 9 | #include "core/hle/service/hid/hid.h" |
| @@ -14,32 +13,33 @@ namespace Core::Frontend { | |||
| 14 | 13 | ||
| 15 | ControllerApplet::~ControllerApplet() = default; | 14 | ControllerApplet::~ControllerApplet() = default; |
| 16 | 15 | ||
| 16 | DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) | ||
| 17 | : service_manager{service_manager_} {} | ||
| 18 | |||
| 17 | DefaultControllerApplet::~DefaultControllerApplet() = default; | 19 | DefaultControllerApplet::~DefaultControllerApplet() = default; |
| 18 | 20 | ||
| 19 | void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, | 21 | void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, |
| 20 | ControllerParameters parameters) const { | 22 | const ControllerParameters& parameters) const { |
| 21 | LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); | 23 | LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); |
| 22 | 24 | ||
| 23 | auto& npad = | 25 | auto& npad = |
| 24 | Core::System::GetInstance() | 26 | service_manager.GetService<Service::HID::Hid>("hid") |
| 25 | .ServiceManager() | ||
| 26 | .GetService<Service::HID::Hid>("hid") | ||
| 27 | ->GetAppletResource() | 27 | ->GetAppletResource() |
| 28 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); | 28 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); |
| 29 | 29 | ||
| 30 | auto& players = Settings::values.players; | 30 | auto& players = Settings::values.players.GetValue(); |
| 31 | 31 | ||
| 32 | const std::size_t min_supported_players = | 32 | const std::size_t min_supported_players = |
| 33 | parameters.enable_single_mode ? 1 : parameters.min_players; | 33 | parameters.enable_single_mode ? 1 : parameters.min_players; |
| 34 | 34 | ||
| 35 | // Disconnect Handheld first. | 35 | // Disconnect Handheld first. |
| 36 | npad.DisconnectNPadAtIndex(8); | 36 | npad.DisconnectNpadAtIndex(8); |
| 37 | 37 | ||
| 38 | // Deduce the best configuration based on the input parameters. | 38 | // Deduce the best configuration based on the input parameters. |
| 39 | for (std::size_t index = 0; index < players.size() - 2; ++index) { | 39 | for (std::size_t index = 0; index < players.size() - 2; ++index) { |
| 40 | // First, disconnect all controllers regardless of the value of keep_controllers_connected. | 40 | // First, disconnect all controllers regardless of the value of keep_controllers_connected. |
| 41 | // This makes it easy to connect the desired controllers. | 41 | // This makes it easy to connect the desired controllers. |
| 42 | npad.DisconnectNPadAtIndex(index); | 42 | npad.DisconnectNpadAtIndex(index); |
| 43 | 43 | ||
| 44 | // Only connect the minimum number of required players. | 44 | // Only connect the minimum number of required players. |
| 45 | if (index >= min_supported_players) { | 45 | if (index >= min_supported_players) { |
| @@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 66 | npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); | 66 | npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); |
| 67 | } | 67 | } |
| 68 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | 68 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && |
| 69 | !Settings::values.use_docked_mode) { | 69 | !Settings::values.use_docked_mode.GetValue()) { |
| 70 | // We should *never* reach here under any normal circumstances. | 70 | // We should *never* reach here under any normal circumstances. |
| 71 | npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), | 71 | npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), |
| 72 | index); | 72 | index); |
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index a227f15cd..dff71d8d9 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | 10 | ||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Core::Frontend { | 15 | namespace Core::Frontend { |
| 12 | 16 | ||
| 13 | using BorderColor = std::array<u8, 4>; | 17 | using BorderColor = std::array<u8, 4>; |
| @@ -34,15 +38,19 @@ public: | |||
| 34 | virtual ~ControllerApplet(); | 38 | virtual ~ControllerApplet(); |
| 35 | 39 | ||
| 36 | virtual void ReconfigureControllers(std::function<void()> callback, | 40 | virtual void ReconfigureControllers(std::function<void()> callback, |
| 37 | ControllerParameters parameters) const = 0; | 41 | const ControllerParameters& parameters) const = 0; |
| 38 | }; | 42 | }; |
| 39 | 43 | ||
| 40 | class DefaultControllerApplet final : public ControllerApplet { | 44 | class DefaultControllerApplet final : public ControllerApplet { |
| 41 | public: | 45 | public: |
| 46 | explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); | ||
| 42 | ~DefaultControllerApplet() override; | 47 | ~DefaultControllerApplet() override; |
| 43 | 48 | ||
| 44 | void ReconfigureControllers(std::function<void()> callback, | 49 | void ReconfigureControllers(std::function<void()> callback, |
| 45 | ControllerParameters parameters) const override; | 50 | const ControllerParameters& parameters) const override; |
| 51 | |||
| 52 | private: | ||
| 53 | Service::SM::ServiceManager& service_manager; | ||
| 46 | }; | 54 | }; |
| 47 | 55 | ||
| 48 | } // namespace Core::Frontend | 56 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp index 4002a9211..dceb20ff8 100644 --- a/src/core/frontend/applets/error.cpp +++ b/src/core/frontend/applets/error.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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" | ||
| 5 | #include "core/frontend/applets/error.h" | 6 | #include "core/frontend/applets/error.h" |
| 6 | 7 | ||
| 7 | namespace Core::Frontend { | 8 | namespace Core::Frontend { |
| @@ -10,7 +11,7 @@ ErrorApplet::~ErrorApplet() = default; | |||
| 10 | 11 | ||
| 11 | void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const { | 12 | void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const { |
| 12 | LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", | 13 | LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", |
| 13 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); | 14 | error.module.Value(), error.description.Value(), error.raw); |
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, | 17 | void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, |
| @@ -18,7 +19,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::s | |||
| 18 | LOG_CRITICAL( | 19 | LOG_CRITICAL( |
| 19 | Service_Fatal, | 20 | Service_Fatal, |
| 20 | "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", | 21 | "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", |
| 21 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count()); | 22 | error.module.Value(), error.description.Value(), error.raw, time.count()); |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text, | 25 | void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text, |
| @@ -26,7 +27,7 @@ void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_ | |||
| 26 | std::function<void()> finished) const { | 27 | std::function<void()> finished) const { |
| 27 | LOG_CRITICAL(Service_Fatal, | 28 | LOG_CRITICAL(Service_Fatal, |
| 28 | "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", | 29 | "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", |
| 29 | static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); | 30 | error.module.Value(), error.description.Value(), error.raw); |
| 30 | LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); | 31 | LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); |
| 31 | LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); | 32 | LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); |
| 32 | } | 33 | } |
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp index c30b36de7..7483ffb76 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general_frontend.cpp | |||
| @@ -53,72 +53,4 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con | |||
| 53 | finished(); | 53 | finished(); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | ECommerceApplet::~ECommerceApplet() = default; | ||
| 57 | |||
| 58 | DefaultECommerceApplet::~DefaultECommerceApplet() = default; | ||
| 59 | |||
| 60 | void DefaultECommerceApplet::ShowApplicationInformation( | ||
| 61 | std::function<void()> finished, u64 title_id, std::optional<u128> user_id, | ||
| 62 | std::optional<bool> full_display, std::optional<std::string> extra_parameter) { | ||
| 63 | const auto value = user_id.value_or(u128{}); | ||
| 64 | LOG_INFO(Service_AM, | ||
| 65 | "Application requested frontend show application information for EShop, " | ||
| 66 | "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}", | ||
| 67 | title_id, value[1], value[0], | ||
| 68 | full_display.has_value() ? fmt::format("{}", *full_display) : "null", | ||
| 69 | extra_parameter.value_or("null")); | ||
| 70 | finished(); | ||
| 71 | } | ||
| 72 | |||
| 73 | void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id, | ||
| 74 | std::optional<u128> user_id, | ||
| 75 | std::optional<bool> full_display) { | ||
| 76 | const auto value = user_id.value_or(u128{}); | ||
| 77 | LOG_INFO(Service_AM, | ||
| 78 | "Application requested frontend show add on content list for EShop, " | ||
| 79 | "title_id={:016X}, user_id={:016X}{:016X}, full_display={}", | ||
| 80 | title_id, value[1], value[0], | ||
| 81 | full_display.has_value() ? fmt::format("{}", *full_display) : "null"); | ||
| 82 | finished(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id, | ||
| 86 | std::optional<u128> user_id) { | ||
| 87 | const auto value = user_id.value_or(u128{}); | ||
| 88 | LOG_INFO(Service_AM, | ||
| 89 | "Application requested frontend show subscription list for EShop, title_id={:016X}, " | ||
| 90 | "user_id={:016X}{:016X}", | ||
| 91 | title_id, value[1], value[0]); | ||
| 92 | finished(); | ||
| 93 | } | ||
| 94 | |||
| 95 | void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id, | ||
| 96 | std::optional<u128> user_id) { | ||
| 97 | const auto value = user_id.value_or(u128{}); | ||
| 98 | LOG_INFO( | ||
| 99 | Service_AM, | ||
| 100 | "Application requested frontend show consumable item list for EShop, title_id={:016X}, " | ||
| 101 | "user_id={:016X}{:016X}", | ||
| 102 | title_id, value[1], value[0]); | ||
| 103 | finished(); | ||
| 104 | } | ||
| 105 | |||
| 106 | void DefaultECommerceApplet::ShowShopHome(std::function<void()> finished, u128 user_id, | ||
| 107 | bool full_display) { | ||
| 108 | LOG_INFO(Service_AM, | ||
| 109 | "Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, " | ||
| 110 | "full_display={}", | ||
| 111 | user_id[1], user_id[0], full_display); | ||
| 112 | finished(); | ||
| 113 | } | ||
| 114 | |||
| 115 | void DefaultECommerceApplet::ShowSettings(std::function<void()> finished, u128 user_id, | ||
| 116 | bool full_display) { | ||
| 117 | LOG_INFO(Service_AM, | ||
| 118 | "Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, " | ||
| 119 | "full_display={}", | ||
| 120 | user_id[1], user_id[0], full_display); | ||
| 121 | finished(); | ||
| 122 | } | ||
| 123 | |||
| 124 | } // namespace Core::Frontend | 56 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h index 4b63f828e..b713b14ee 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general_frontend.h | |||
| @@ -58,55 +58,4 @@ public: | |||
| 58 | void ShowAllPhotos(std::function<void()> finished) const override; | 58 | void ShowAllPhotos(std::function<void()> finished) const override; |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | class ECommerceApplet { | ||
| 62 | public: | ||
| 63 | virtual ~ECommerceApplet(); | ||
| 64 | |||
| 65 | // Shows a page with application icons, description, name, and price. | ||
| 66 | virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id, | ||
| 67 | std::optional<u128> user_id = {}, | ||
| 68 | std::optional<bool> full_display = {}, | ||
| 69 | std::optional<std::string> extra_parameter = {}) = 0; | ||
| 70 | |||
| 71 | // Shows a page with all of the add on content available for a game, with name, description, and | ||
| 72 | // price. | ||
| 73 | virtual void ShowAddOnContentList(std::function<void()> finished, u64 title_id, | ||
| 74 | std::optional<u128> user_id = {}, | ||
| 75 | std::optional<bool> full_display = {}) = 0; | ||
| 76 | |||
| 77 | // Shows a page with all of the subscriptions (recurring payments) for a game, with name, | ||
| 78 | // description, price, and renewal period. | ||
| 79 | virtual void ShowSubscriptionList(std::function<void()> finished, u64 title_id, | ||
| 80 | std::optional<u128> user_id = {}) = 0; | ||
| 81 | |||
| 82 | // Shows a page with a list of any additional game related purchasable items (DLC, | ||
| 83 | // subscriptions, etc) for a particular game, with name, description, type, and price. | ||
| 84 | virtual void ShowConsumableItemList(std::function<void()> finished, u64 title_id, | ||
| 85 | std::optional<u128> user_id = {}) = 0; | ||
| 86 | |||
| 87 | // Shows the home page of the shop. | ||
| 88 | virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0; | ||
| 89 | |||
| 90 | // Shows the user settings page of the shop. | ||
| 91 | virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0; | ||
| 92 | }; | ||
| 93 | |||
| 94 | class DefaultECommerceApplet : public ECommerceApplet { | ||
| 95 | public: | ||
| 96 | ~DefaultECommerceApplet() override; | ||
| 97 | |||
| 98 | void ShowApplicationInformation(std::function<void()> finished, u64 title_id, | ||
| 99 | std::optional<u128> user_id, std::optional<bool> full_display, | ||
| 100 | std::optional<std::string> extra_parameter) override; | ||
| 101 | void ShowAddOnContentList(std::function<void()> finished, u64 title_id, | ||
| 102 | std::optional<u128> user_id, | ||
| 103 | std::optional<bool> full_display) override; | ||
| 104 | void ShowSubscriptionList(std::function<void()> finished, u64 title_id, | ||
| 105 | std::optional<u128> user_id) override; | ||
| 106 | void ShowConsumableItemList(std::function<void()> finished, u64 title_id, | ||
| 107 | std::optional<u128> user_id) override; | ||
| 108 | void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override; | ||
| 109 | void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override; | ||
| 110 | }; | ||
| 111 | |||
| 112 | } // namespace Core::Frontend | 61 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index 528295ffc..50db6a654 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp | |||
| @@ -11,14 +11,22 @@ WebBrowserApplet::~WebBrowserApplet() = default; | |||
| 11 | 11 | ||
| 12 | DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; | 12 | DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; |
| 13 | 13 | ||
| 14 | void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename, | 14 | void DefaultWebBrowserApplet::OpenLocalWebPage( |
| 15 | std::function<void()> unpack_romfs_callback, | 15 | std::string_view local_url, std::function<void()> extract_romfs_callback, |
| 16 | std::function<void()> finished_callback) { | 16 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { |
| 17 | LOG_INFO(Service_AM, | 17 | LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", |
| 18 | "(STUBBED) called - No suitable web browser implementation found to open website page " | 18 | local_url); |
| 19 | "at '{}'!", | 19 | |
| 20 | filename); | 20 | callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); |
| 21 | finished_callback(); | 21 | } |
| 22 | |||
| 23 | void DefaultWebBrowserApplet::OpenExternalWebPage( | ||
| 24 | std::string_view external_url, | ||
| 25 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { | ||
| 26 | LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", | ||
| 27 | external_url); | ||
| 28 | |||
| 29 | callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); | ||
| 22 | } | 30 | } |
| 23 | 31 | ||
| 24 | } // namespace Core::Frontend | 32 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index 110e33bc4..1c5ef19a9 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h | |||
| @@ -7,22 +7,34 @@ | |||
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <string_view> | 8 | #include <string_view> |
| 9 | 9 | ||
| 10 | #include "core/hle/service/am/applets/web_types.h" | ||
| 11 | |||
| 10 | namespace Core::Frontend { | 12 | namespace Core::Frontend { |
| 11 | 13 | ||
| 12 | class WebBrowserApplet { | 14 | class WebBrowserApplet { |
| 13 | public: | 15 | public: |
| 14 | virtual ~WebBrowserApplet(); | 16 | virtual ~WebBrowserApplet(); |
| 15 | 17 | ||
| 16 | virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback, | 18 | virtual void OpenLocalWebPage( |
| 17 | std::function<void()> finished_callback) = 0; | 19 | std::string_view local_url, std::function<void()> extract_romfs_callback, |
| 20 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; | ||
| 21 | |||
| 22 | virtual void OpenExternalWebPage( | ||
| 23 | std::string_view external_url, | ||
| 24 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; | ||
| 18 | }; | 25 | }; |
| 19 | 26 | ||
| 20 | class DefaultWebBrowserApplet final : public WebBrowserApplet { | 27 | class DefaultWebBrowserApplet final : public WebBrowserApplet { |
| 21 | public: | 28 | public: |
| 22 | ~DefaultWebBrowserApplet() override; | 29 | ~DefaultWebBrowserApplet() override; |
| 23 | 30 | ||
| 24 | void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback, | 31 | void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback, |
| 25 | std::function<void()> finished_callback) override; | 32 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> |
| 33 | callback) const override; | ||
| 34 | |||
| 35 | void OpenExternalWebPage(std::string_view external_url, | ||
| 36 | std::function<void(Service::AM::Applets::WebExitReason, std::string)> | ||
| 37 | callback) const override; | ||
| 26 | }; | 38 | }; |
| 27 | 39 | ||
| 28 | } // namespace Core::Frontend | 40 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 9a081fbd4..8c1193894 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -84,10 +84,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 84 | return; | 84 | return; |
| 85 | 85 | ||
| 86 | std::lock_guard guard{touch_state->mutex}; | 86 | std::lock_guard guard{touch_state->mutex}; |
| 87 | touch_state->touch_x = static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / | 87 | touch_state->touch_x = |
| 88 | (framebuffer_layout.screen.right - framebuffer_layout.screen.left); | 88 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / |
| 89 | touch_state->touch_y = static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / | 89 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); |
| 90 | (framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); | 90 | touch_state->touch_y = |
| 91 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / | ||
| 92 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); | ||
| 91 | 93 | ||
| 92 | touch_state->touch_pressed = true; | 94 | touch_state->touch_pressed = true; |
| 93 | } | 95 | } |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 3e8780243..276d2b906 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -102,8 +102,8 @@ public: | |||
| 102 | float render_surface_scale = 1.0f; | 102 | float render_surface_scale = 1.0f; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | /// Polls window events | 105 | /// Called from GPU thread when a frame is displayed. |
| 106 | virtual void PollEvents() = 0; | 106 | virtual void OnFrameDisplayed() {} |
| 107 | 107 | ||
| 108 | /** | 108 | /** |
| 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. | 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. |
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index c1fbc235b..b9a270a55 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp | |||
| @@ -14,8 +14,8 @@ namespace Layout { | |||
| 14 | template <class T> | 14 | template <class T> |
| 15 | static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area, | 15 | static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area, |
| 16 | float screen_aspect_ratio) { | 16 | float screen_aspect_ratio) { |
| 17 | float scale = std::min(static_cast<float>(window_area.GetWidth()), | 17 | const float scale = std::min(static_cast<float>(window_area.GetWidth()), |
| 18 | window_area.GetHeight() / screen_aspect_ratio); | 18 | static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio); |
| 19 | return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)), | 19 | return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)), |
| 20 | static_cast<T>(std::round(scale * screen_aspect_ratio))}; | 20 | static_cast<T>(std::round(scale * screen_aspect_ratio))}; |
| 21 | } | 21 | } |
| @@ -27,7 +27,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { | |||
| 27 | // so just calculate them both even if the other isn't showing. | 27 | // so just calculate them both even if the other isn't showing. |
| 28 | FramebufferLayout res{width, height, false, {}}; | 28 | FramebufferLayout res{width, height, false, {}}; |
| 29 | 29 | ||
| 30 | const float window_aspect_ratio = static_cast<float>(height) / width; | 30 | const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width); |
| 31 | const float emulation_aspect_ratio = EmulationAspectRatio( | 31 | const float emulation_aspect_ratio = EmulationAspectRatio( |
| 32 | static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio); | 32 | static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio); |
| 33 | 33 | ||
| @@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { | |||
| 47 | FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { | 47 | FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { |
| 48 | u32 width, height; | 48 | u32 width, height; |
| 49 | 49 | ||
| 50 | if (Settings::values.use_docked_mode) { | 50 | if (Settings::values.use_docked_mode.GetValue()) { |
| 51 | width = ScreenDocked::Width * res_scale; | 51 | width = ScreenDocked::Width * res_scale; |
| 52 | height = ScreenDocked::Height * res_scale; | 52 | height = ScreenDocked::Height * res_scale; |
| 53 | } else { | 53 | } else { |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 9da0d2829..de51a754e 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -30,7 +30,12 @@ public: | |||
| 30 | virtual StatusType GetStatus() const { | 30 | virtual StatusType GetStatus() const { |
| 31 | return {}; | 31 | return {}; |
| 32 | } | 32 | } |
| 33 | virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { | 33 | virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { |
| 34 | return {}; | ||
| 35 | } | ||
| 36 | virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, | ||
| 37 | [[maybe_unused]] f32 amp_high, | ||
| 38 | [[maybe_unused]] f32 freq_high) const { | ||
| 34 | return {}; | 39 | return {}; |
| 35 | } | 40 | } |
| 36 | }; | 41 | }; |
| @@ -119,6 +124,13 @@ using ButtonDevice = InputDevice<bool>; | |||
| 119 | using AnalogDevice = InputDevice<std::tuple<float, float>>; | 124 | using AnalogDevice = InputDevice<std::tuple<float, float>>; |
| 120 | 125 | ||
| 121 | /** | 126 | /** |
| 127 | * A vibration device is an input device that returns an unsigned byte as status. | ||
| 128 | * It represents whether the vibration device supports vibration or not. | ||
| 129 | * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. | ||
| 130 | */ | ||
| 131 | using VibrationDevice = InputDevice<u8>; | ||
| 132 | |||
| 133 | /** | ||
| 122 | * A motion status is an object that returns a tuple of accelerometer state vector, | 134 | * A motion status is an object that returns a tuple of accelerometer state vector, |
| 123 | * gyroscope state vector, rotation state vector and orientation state matrix. | 135 | * gyroscope state vector, rotation state vector and orientation state matrix. |
| 124 | * | 136 | * |
| @@ -151,10 +163,15 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common | |||
| 151 | using MotionDevice = InputDevice<MotionStatus>; | 163 | using MotionDevice = InputDevice<MotionStatus>; |
| 152 | 164 | ||
| 153 | /** | 165 | /** |
| 154 | * A touch device is an input device that returns a tuple of two floats and a bool. The floats are | 166 | * A touch status is an object that returns a tuple of two floats and a bool. The floats are |
| 155 | * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. | 167 | * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. |
| 156 | */ | 168 | */ |
| 157 | using TouchDevice = InputDevice<std::tuple<float, float, bool>>; | 169 | using TouchStatus = std::tuple<float, float, bool>; |
| 170 | |||
| 171 | /** | ||
| 172 | * A touch device is an input device that returns a touch status object | ||
| 173 | */ | ||
| 174 | using TouchDevice = InputDevice<TouchStatus>; | ||
| 158 | 175 | ||
| 159 | /** | 176 | /** |
| 160 | * A mouse device is an input device that returns a tuple of two floats and four ints. | 177 | * A mouse device is an input device that returns a tuple of two floats and four ints. |
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp new file mode 100644 index 000000000..66ae506cd --- /dev/null +++ b/src/core/frontend/input_interpreter.cpp | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/frontend/input_interpreter.h" | ||
| 7 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 8 | #include "core/hle/service/hid/hid.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | InputInterpreter::InputInterpreter(Core::System& system) | ||
| 12 | : npad{system.ServiceManager() | ||
| 13 | .GetService<Service::HID::Hid>("hid") | ||
| 14 | ->GetAppletResource() | ||
| 15 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {} | ||
| 16 | |||
| 17 | InputInterpreter::~InputInterpreter() = default; | ||
| 18 | |||
| 19 | void InputInterpreter::PollInput() { | ||
| 20 | const u32 button_state = npad.GetAndResetPressState(); | ||
| 21 | |||
| 22 | previous_index = current_index; | ||
| 23 | current_index = (current_index + 1) % button_states.size(); | ||
| 24 | |||
| 25 | button_states[current_index] = button_state; | ||
| 26 | } | ||
| 27 | |||
| 28 | bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { | ||
| 29 | const bool current_press = | ||
| 30 | (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 31 | const bool previous_press = | ||
| 32 | (button_states[previous_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 33 | |||
| 34 | return current_press && !previous_press; | ||
| 35 | } | ||
| 36 | |||
| 37 | bool InputInterpreter::IsButtonHeld(HIDButton button) const { | ||
| 38 | u32 held_buttons{button_states[0]}; | ||
| 39 | |||
| 40 | for (std::size_t i = 1; i < button_states.size(); ++i) { | ||
| 41 | held_buttons &= button_states[i]; | ||
| 42 | } | ||
| 43 | |||
| 44 | return (held_buttons & (1U << static_cast<u8>(button))) != 0; | ||
| 45 | } | ||
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h new file mode 100644 index 000000000..fea9aebe6 --- /dev/null +++ b/src/core/frontend/input_interpreter.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | class Controller_NPad; | ||
| 17 | } | ||
| 18 | |||
| 19 | enum class HIDButton : u8 { | ||
| 20 | A, | ||
| 21 | B, | ||
| 22 | X, | ||
| 23 | Y, | ||
| 24 | LStick, | ||
| 25 | RStick, | ||
| 26 | L, | ||
| 27 | R, | ||
| 28 | ZL, | ||
| 29 | ZR, | ||
| 30 | Plus, | ||
| 31 | Minus, | ||
| 32 | |||
| 33 | DLeft, | ||
| 34 | DUp, | ||
| 35 | DRight, | ||
| 36 | DDown, | ||
| 37 | |||
| 38 | LStickLeft, | ||
| 39 | LStickUp, | ||
| 40 | LStickRight, | ||
| 41 | LStickDown, | ||
| 42 | |||
| 43 | RStickLeft, | ||
| 44 | RStickUp, | ||
| 45 | RStickRight, | ||
| 46 | RStickDown, | ||
| 47 | |||
| 48 | LeftSL, | ||
| 49 | LeftSR, | ||
| 50 | |||
| 51 | RightSL, | ||
| 52 | RightSR, | ||
| 53 | }; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * The InputInterpreter class interfaces with HID to retrieve button press states. | ||
| 57 | * Input is intended to be polled every 50ms so that a button is considered to be | ||
| 58 | * held down after 400ms has elapsed since the initial button press and subsequent | ||
| 59 | * repeated presses occur every 50ms. | ||
| 60 | */ | ||
| 61 | class InputInterpreter { | ||
| 62 | public: | ||
| 63 | explicit InputInterpreter(Core::System& system); | ||
| 64 | virtual ~InputInterpreter(); | ||
| 65 | |||
| 66 | /// Gets a button state from HID and inserts it into the array of button states. | ||
| 67 | void PollInput(); | ||
| 68 | |||
| 69 | /** | ||
| 70 | * The specified button is considered to be pressed once | ||
| 71 | * if it is currently pressed and not pressed previously. | ||
| 72 | * | ||
| 73 | * @param button The button to check. | ||
| 74 | * | ||
| 75 | * @returns True when the button is pressed once. | ||
| 76 | */ | ||
| 77 | [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Checks whether any of the buttons in the parameter list is pressed once. | ||
| 81 | * | ||
| 82 | * @tparam HIDButton The buttons to check. | ||
| 83 | * | ||
| 84 | * @returns True when at least one of the buttons is pressed once. | ||
| 85 | */ | ||
| 86 | template <HIDButton... T> | ||
| 87 | [[nodiscard]] bool IsAnyButtonPressedOnce() { | ||
| 88 | return (IsButtonPressedOnce(T) || ...); | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * The specified button is considered to be held down if it is pressed in all 9 button states. | ||
| 93 | * | ||
| 94 | * @param button The button to check. | ||
| 95 | * | ||
| 96 | * @returns True when the button is held down. | ||
| 97 | */ | ||
| 98 | [[nodiscard]] bool IsButtonHeld(HIDButton button) const; | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Checks whether any of the buttons in the parameter list is held down. | ||
| 102 | * | ||
| 103 | * @tparam HIDButton The buttons to check. | ||
| 104 | * | ||
| 105 | * @returns True when at least one of the buttons is held down. | ||
| 106 | */ | ||
| 107 | template <HIDButton... T> | ||
| 108 | [[nodiscard]] bool IsAnyButtonHeld() { | ||
| 109 | return (IsButtonHeld(T) || ...); | ||
| 110 | } | ||
| 111 | |||
| 112 | private: | ||
| 113 | Service::HID::Controller_NPad& npad; | ||
| 114 | |||
| 115 | /// Stores 9 consecutive button states polled from HID. | ||
| 116 | std::array<u32, 9> button_states{}; | ||
| 117 | |||
| 118 | std::size_t previous_index{}; | ||
| 119 | std::size_t current_index{}; | ||
| 120 | }; | ||
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp deleted file mode 100644 index 79f22a403..000000000 --- a/src/core/gdbstub/gdbstub.cpp +++ /dev/null | |||
| @@ -1,1397 +0,0 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <atomic> | ||
| 9 | #include <climits> | ||
| 10 | #include <csignal> | ||
| 11 | #include <cstdarg> | ||
| 12 | #include <cstdio> | ||
| 13 | #include <cstring> | ||
| 14 | #include <map> | ||
| 15 | #include <numeric> | ||
| 16 | #include <fcntl.h> | ||
| 17 | |||
| 18 | #ifdef _WIN32 | ||
| 19 | #include <winsock2.h> | ||
| 20 | // winsock2.h needs to be included first to prevent winsock.h being included by other includes | ||
| 21 | #include <io.h> | ||
| 22 | #include <iphlpapi.h> | ||
| 23 | #include <ws2tcpip.h> | ||
| 24 | #define SHUT_RDWR 2 | ||
| 25 | #else | ||
| 26 | #include <netinet/in.h> | ||
| 27 | #include <sys/select.h> | ||
| 28 | #include <sys/socket.h> | ||
| 29 | #include <sys/un.h> | ||
| 30 | #include <unistd.h> | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #include "common/logging/log.h" | ||
| 34 | #include "common/string_util.h" | ||
| 35 | #include "common/swap.h" | ||
| 36 | #include "core/arm/arm_interface.h" | ||
| 37 | #include "core/core.h" | ||
| 38 | #include "core/gdbstub/gdbstub.h" | ||
| 39 | #include "core/hle/kernel/memory/page_table.h" | ||
| 40 | #include "core/hle/kernel/process.h" | ||
| 41 | #include "core/hle/kernel/scheduler.h" | ||
| 42 | #include "core/loader/loader.h" | ||
| 43 | #include "core/memory.h" | ||
| 44 | |||
| 45 | namespace GDBStub { | ||
| 46 | namespace { | ||
| 47 | constexpr int GDB_BUFFER_SIZE = 10000; | ||
| 48 | |||
| 49 | constexpr char GDB_STUB_START = '$'; | ||
| 50 | constexpr char GDB_STUB_END = '#'; | ||
| 51 | constexpr char GDB_STUB_ACK = '+'; | ||
| 52 | constexpr char GDB_STUB_NACK = '-'; | ||
| 53 | |||
| 54 | #ifndef SIGTRAP | ||
| 55 | constexpr u32 SIGTRAP = 5; | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #ifndef SIGTERM | ||
| 59 | constexpr u32 SIGTERM = 15; | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #ifndef MSG_WAITALL | ||
| 63 | constexpr u32 MSG_WAITALL = 8; | ||
| 64 | #endif | ||
| 65 | |||
| 66 | constexpr u32 LR_REGISTER = 30; | ||
| 67 | constexpr u32 SP_REGISTER = 31; | ||
| 68 | constexpr u32 PC_REGISTER = 32; | ||
| 69 | constexpr u32 PSTATE_REGISTER = 33; | ||
| 70 | constexpr u32 UC_ARM64_REG_Q0 = 34; | ||
| 71 | constexpr u32 FPCR_REGISTER = 66; | ||
| 72 | |||
| 73 | // For sample XML files see the GDB source /gdb/features | ||
| 74 | // GDB also wants the l character at the start | ||
| 75 | // This XML defines what the registers are for this specific ARM device | ||
| 76 | constexpr char target_xml[] = | ||
| 77 | R"(l<?xml version="1.0"?> | ||
| 78 | <!DOCTYPE target SYSTEM "gdb-target.dtd"> | ||
| 79 | <target version="1.0"> | ||
| 80 | <feature name="org.gnu.gdb.aarch64.core"> | ||
| 81 | <reg name="x0" bitsize="64"/> | ||
| 82 | <reg name="x1" bitsize="64"/> | ||
| 83 | <reg name="x2" bitsize="64"/> | ||
| 84 | <reg name="x3" bitsize="64"/> | ||
| 85 | <reg name="x4" bitsize="64"/> | ||
| 86 | <reg name="x5" bitsize="64"/> | ||
| 87 | <reg name="x6" bitsize="64"/> | ||
| 88 | <reg name="x7" bitsize="64"/> | ||
| 89 | <reg name="x8" bitsize="64"/> | ||
| 90 | <reg name="x9" bitsize="64"/> | ||
| 91 | <reg name="x10" bitsize="64"/> | ||
| 92 | <reg name="x11" bitsize="64"/> | ||
| 93 | <reg name="x12" bitsize="64"/> | ||
| 94 | <reg name="x13" bitsize="64"/> | ||
| 95 | <reg name="x14" bitsize="64"/> | ||
| 96 | <reg name="x15" bitsize="64"/> | ||
| 97 | <reg name="x16" bitsize="64"/> | ||
| 98 | <reg name="x17" bitsize="64"/> | ||
| 99 | <reg name="x18" bitsize="64"/> | ||
| 100 | <reg name="x19" bitsize="64"/> | ||
| 101 | <reg name="x20" bitsize="64"/> | ||
| 102 | <reg name="x21" bitsize="64"/> | ||
| 103 | <reg name="x22" bitsize="64"/> | ||
| 104 | <reg name="x23" bitsize="64"/> | ||
| 105 | <reg name="x24" bitsize="64"/> | ||
| 106 | <reg name="x25" bitsize="64"/> | ||
| 107 | <reg name="x26" bitsize="64"/> | ||
| 108 | <reg name="x27" bitsize="64"/> | ||
| 109 | <reg name="x28" bitsize="64"/> | ||
| 110 | <reg name="x29" bitsize="64"/> | ||
| 111 | <reg name="x30" bitsize="64"/> | ||
| 112 | <reg name="sp" bitsize="64" type="data_ptr"/> | ||
| 113 | |||
| 114 | <reg name="pc" bitsize="64" type="code_ptr"/> | ||
| 115 | |||
| 116 | <flags id="pstate_flags" size="4"> | ||
| 117 | <field name="SP" start="0" end="0"/> | ||
| 118 | <field name="" start="1" end="1"/> | ||
| 119 | <field name="EL" start="2" end="3"/> | ||
| 120 | <field name="nRW" start="4" end="4"/> | ||
| 121 | <field name="" start="5" end="5"/> | ||
| 122 | <field name="F" start="6" end="6"/> | ||
| 123 | <field name="I" start="7" end="7"/> | ||
| 124 | <field name="A" start="8" end="8"/> | ||
| 125 | <field name="D" start="9" end="9"/> | ||
| 126 | |||
| 127 | <field name="IL" start="20" end="20"/> | ||
| 128 | <field name="SS" start="21" end="21"/> | ||
| 129 | |||
| 130 | <field name="V" start="28" end="28"/> | ||
| 131 | <field name="C" start="29" end="29"/> | ||
| 132 | <field name="Z" start="30" end="30"/> | ||
| 133 | <field name="N" start="31" end="31"/> | ||
| 134 | </flags> | ||
| 135 | <reg name="pstate" bitsize="32" type="pstate_flags"/> | ||
| 136 | </feature> | ||
| 137 | <feature name="org.gnu.gdb.aarch64.fpu"> | ||
| 138 | </feature> | ||
| 139 | </target> | ||
| 140 | )"; | ||
| 141 | |||
| 142 | int gdbserver_socket = -1; | ||
| 143 | bool defer_start = false; | ||
| 144 | |||
| 145 | u8 command_buffer[GDB_BUFFER_SIZE]; | ||
| 146 | u32 command_length; | ||
| 147 | |||
| 148 | u32 latest_signal = 0; | ||
| 149 | bool memory_break = false; | ||
| 150 | |||
| 151 | Kernel::Thread* current_thread = nullptr; | ||
| 152 | u32 current_core = 0; | ||
| 153 | |||
| 154 | // Binding to a port within the reserved ports range (0-1023) requires root permissions, | ||
| 155 | // so default to a port outside of that range. | ||
| 156 | u16 gdbstub_port = 24689; | ||
| 157 | |||
| 158 | bool halt_loop = true; | ||
| 159 | bool step_loop = false; | ||
| 160 | bool send_trap = false; | ||
| 161 | |||
| 162 | // If set to false, the server will never be started and no | ||
| 163 | // gdbstub-related functions will be executed. | ||
| 164 | std::atomic<bool> server_enabled(false); | ||
| 165 | |||
| 166 | #ifdef _WIN32 | ||
| 167 | WSADATA InitData; | ||
| 168 | #endif | ||
| 169 | |||
| 170 | struct Breakpoint { | ||
| 171 | bool active; | ||
| 172 | VAddr addr; | ||
| 173 | u64 len; | ||
| 174 | std::array<u8, 4> inst; | ||
| 175 | }; | ||
| 176 | |||
| 177 | using BreakpointMap = std::map<VAddr, Breakpoint>; | ||
| 178 | BreakpointMap breakpoints_execute; | ||
| 179 | BreakpointMap breakpoints_read; | ||
| 180 | BreakpointMap breakpoints_write; | ||
| 181 | |||
| 182 | struct Module { | ||
| 183 | std::string name; | ||
| 184 | VAddr beg; | ||
| 185 | VAddr end; | ||
| 186 | }; | ||
| 187 | |||
| 188 | std::vector<Module> modules; | ||
| 189 | } // Anonymous namespace | ||
| 190 | |||
| 191 | void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) { | ||
| 192 | Module module; | ||
| 193 | if (add_elf_ext) { | ||
| 194 | Common::SplitPath(name, nullptr, &module.name, nullptr); | ||
| 195 | module.name += ".elf"; | ||
| 196 | } else { | ||
| 197 | module.name = std::move(name); | ||
| 198 | } | ||
| 199 | module.beg = beg; | ||
| 200 | module.end = end; | ||
| 201 | modules.push_back(std::move(module)); | ||
| 202 | } | ||
| 203 | |||
| 204 | static Kernel::Thread* FindThreadById(s64 id) { | ||
| 205 | const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); | ||
| 206 | for (auto& thread : threads) { | ||
| 207 | if (thread->GetThreadID() == static_cast<u64>(id)) { | ||
| 208 | current_core = thread->GetProcessorID(); | ||
| 209 | return thread.get(); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | return nullptr; | ||
| 213 | } | ||
| 214 | |||
| 215 | static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) { | ||
| 216 | if (!thread) { | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | const auto& thread_context = thread->GetContext64(); | ||
| 221 | |||
| 222 | if (id < SP_REGISTER) { | ||
| 223 | return thread_context.cpu_registers[id]; | ||
| 224 | } else if (id == SP_REGISTER) { | ||
| 225 | return thread_context.sp; | ||
| 226 | } else if (id == PC_REGISTER) { | ||
| 227 | return thread_context.pc; | ||
| 228 | } else if (id == PSTATE_REGISTER) { | ||
| 229 | return thread_context.pstate; | ||
| 230 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { | ||
| 231 | return thread_context.vector_registers[id - UC_ARM64_REG_Q0][0]; | ||
| 232 | } else { | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) { | ||
| 238 | if (!thread) { | ||
| 239 | return; | ||
| 240 | } | ||
| 241 | |||
| 242 | auto& thread_context = thread->GetContext64(); | ||
| 243 | |||
| 244 | if (id < SP_REGISTER) { | ||
| 245 | thread_context.cpu_registers[id] = val; | ||
| 246 | } else if (id == SP_REGISTER) { | ||
| 247 | thread_context.sp = val; | ||
| 248 | } else if (id == PC_REGISTER) { | ||
| 249 | thread_context.pc = val; | ||
| 250 | } else if (id == PSTATE_REGISTER) { | ||
| 251 | thread_context.pstate = static_cast<u32>(val); | ||
| 252 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { | ||
| 253 | thread_context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { | ||
| 258 | if (!thread) { | ||
| 259 | return u128{0}; | ||
| 260 | } | ||
| 261 | |||
| 262 | auto& thread_context = thread->GetContext64(); | ||
| 263 | |||
| 264 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 265 | return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; | ||
| 266 | } else if (id == FPCR_REGISTER) { | ||
| 267 | return u128{thread_context.fpcr, 0}; | ||
| 268 | } else { | ||
| 269 | return u128{0}; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) { | ||
| 274 | if (!thread) { | ||
| 275 | return; | ||
| 276 | } | ||
| 277 | |||
| 278 | auto& thread_context = thread->GetContext64(); | ||
| 279 | |||
| 280 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 281 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; | ||
| 282 | } else if (id == FPCR_REGISTER) { | ||
| 283 | thread_context.fpcr = static_cast<u32>(val[0]); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | /** | ||
| 288 | * Turns hex string character into the equivalent byte. | ||
| 289 | * | ||
| 290 | * @param hex Input hex character to be turned into byte. | ||
| 291 | */ | ||
| 292 | static u8 HexCharToValue(u8 hex) { | ||
| 293 | if (hex >= '0' && hex <= '9') { | ||
| 294 | return hex - '0'; | ||
| 295 | } else if (hex >= 'a' && hex <= 'f') { | ||
| 296 | return hex - 'a' + 0xA; | ||
| 297 | } else if (hex >= 'A' && hex <= 'F') { | ||
| 298 | return hex - 'A' + 0xA; | ||
| 299 | } | ||
| 300 | |||
| 301 | LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * Turn nibble of byte into hex string character. | ||
| 307 | * | ||
| 308 | * @param n Nibble to be turned into hex character. | ||
| 309 | */ | ||
| 310 | static u8 NibbleToHex(u8 n) { | ||
| 311 | n &= 0xF; | ||
| 312 | if (n < 0xA) { | ||
| 313 | return '0' + n; | ||
| 314 | } else { | ||
| 315 | return 'a' + n - 0xA; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * Converts input hex string characters into an array of equivalent of u8 bytes. | ||
| 321 | * | ||
| 322 | * @param src Pointer to array of output hex string characters. | ||
| 323 | * @param len Length of src array. | ||
| 324 | */ | ||
| 325 | static u32 HexToInt(const u8* src, std::size_t len) { | ||
| 326 | u32 output = 0; | ||
| 327 | while (len-- > 0) { | ||
| 328 | output = (output << 4) | HexCharToValue(src[0]); | ||
| 329 | src++; | ||
| 330 | } | ||
| 331 | return output; | ||
| 332 | } | ||
| 333 | |||
| 334 | /** | ||
| 335 | * Converts input hex string characters into an array of equivalent of u8 bytes. | ||
| 336 | * | ||
| 337 | * @param src Pointer to array of output hex string characters. | ||
| 338 | * @param len Length of src array. | ||
| 339 | */ | ||
| 340 | static u64 HexToLong(const u8* src, std::size_t len) { | ||
| 341 | u64 output = 0; | ||
| 342 | while (len-- > 0) { | ||
| 343 | output = (output << 4) | HexCharToValue(src[0]); | ||
| 344 | src++; | ||
| 345 | } | ||
| 346 | return output; | ||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Converts input array of u8 bytes into their equivalent hex string characters. | ||
| 351 | * | ||
| 352 | * @param dest Pointer to buffer to store output hex string characters. | ||
| 353 | * @param src Pointer to array of u8 bytes. | ||
| 354 | * @param len Length of src array. | ||
| 355 | */ | ||
| 356 | static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) { | ||
| 357 | while (len-- > 0) { | ||
| 358 | u8 tmp = *src++; | ||
| 359 | *dest++ = NibbleToHex(tmp >> 4); | ||
| 360 | *dest++ = NibbleToHex(tmp); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * Converts input gdb-formatted hex string characters into an array of equivalent of u8 bytes. | ||
| 366 | * | ||
| 367 | * @param dest Pointer to buffer to store u8 bytes. | ||
| 368 | * @param src Pointer to array of output hex string characters. | ||
| 369 | * @param len Length of src array. | ||
| 370 | */ | ||
| 371 | static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) { | ||
| 372 | while (len-- > 0) { | ||
| 373 | *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]); | ||
| 374 | src += 2; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Convert a u32 into a gdb-formatted hex string. | ||
| 380 | * | ||
| 381 | * @param dest Pointer to buffer to store output hex string characters. | ||
| 382 | * @param v Value to convert. | ||
| 383 | */ | ||
| 384 | static void IntToGdbHex(u8* dest, u32 v) { | ||
| 385 | for (int i = 0; i < 8; i += 2) { | ||
| 386 | dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); | ||
| 387 | dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1)))); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | /** | ||
| 392 | * Convert a u64 into a gdb-formatted hex string. | ||
| 393 | * | ||
| 394 | * @param dest Pointer to buffer to store output hex string characters. | ||
| 395 | * @param v Value to convert. | ||
| 396 | */ | ||
| 397 | static void LongToGdbHex(u8* dest, u64 v) { | ||
| 398 | for (int i = 0; i < 16; i += 2) { | ||
| 399 | dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i))); | ||
| 400 | dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1)))); | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /** | ||
| 405 | * Convert a gdb-formatted hex string into a u32. | ||
| 406 | * | ||
| 407 | * @param src Pointer to hex string. | ||
| 408 | */ | ||
| 409 | static u32 GdbHexToInt(const u8* src) { | ||
| 410 | u32 output = 0; | ||
| 411 | |||
| 412 | for (int i = 0; i < 8; i += 2) { | ||
| 413 | output = (output << 4) | HexCharToValue(src[7 - i - 1]); | ||
| 414 | output = (output << 4) | HexCharToValue(src[7 - i]); | ||
| 415 | } | ||
| 416 | |||
| 417 | return output; | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Convert a gdb-formatted hex string into a u64. | ||
| 422 | * | ||
| 423 | * @param src Pointer to hex string. | ||
| 424 | */ | ||
| 425 | static u64 GdbHexToLong(const u8* src) { | ||
| 426 | u64 output = 0; | ||
| 427 | |||
| 428 | for (int i = 0; i < 16; i += 2) { | ||
| 429 | output = (output << 4) | HexCharToValue(src[15 - i - 1]); | ||
| 430 | output = (output << 4) | HexCharToValue(src[15 - i]); | ||
| 431 | } | ||
| 432 | |||
| 433 | return output; | ||
| 434 | } | ||
| 435 | |||
| 436 | /** | ||
| 437 | * Convert a gdb-formatted hex string into a u128. | ||
| 438 | * | ||
| 439 | * @param src Pointer to hex string. | ||
| 440 | */ | ||
| 441 | static u128 GdbHexToU128(const u8* src) { | ||
| 442 | u128 output; | ||
| 443 | |||
| 444 | for (int i = 0; i < 16; i += 2) { | ||
| 445 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]); | ||
| 446 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]); | ||
| 447 | } | ||
| 448 | |||
| 449 | for (int i = 0; i < 16; i += 2) { | ||
| 450 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]); | ||
| 451 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]); | ||
| 452 | } | ||
| 453 | |||
| 454 | return output; | ||
| 455 | } | ||
| 456 | |||
| 457 | /// Read a byte from the gdb client. | ||
| 458 | static u8 ReadByte() { | ||
| 459 | u8 c; | ||
| 460 | std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); | ||
| 461 | if (received_size != 1) { | ||
| 462 | LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); | ||
| 463 | Shutdown(); | ||
| 464 | } | ||
| 465 | |||
| 466 | return c; | ||
| 467 | } | ||
| 468 | |||
| 469 | /// Calculate the checksum of the current command buffer. | ||
| 470 | static u8 CalculateChecksum(const u8* buffer, std::size_t length) { | ||
| 471 | return static_cast<u8>(std::accumulate(buffer, buffer + length, u8{0}, | ||
| 472 | [](u8 lhs, u8 rhs) { return u8(lhs + rhs); })); | ||
| 473 | } | ||
| 474 | |||
| 475 | /** | ||
| 476 | * Get the map of breakpoints for a given breakpoint type. | ||
| 477 | * | ||
| 478 | * @param type Type of breakpoint map. | ||
| 479 | */ | ||
| 480 | static BreakpointMap& GetBreakpointMap(BreakpointType type) { | ||
| 481 | switch (type) { | ||
| 482 | case BreakpointType::Execute: | ||
| 483 | return breakpoints_execute; | ||
| 484 | case BreakpointType::Read: | ||
| 485 | return breakpoints_read; | ||
| 486 | case BreakpointType::Write: | ||
| 487 | return breakpoints_write; | ||
| 488 | default: | ||
| 489 | return breakpoints_read; | ||
| 490 | } | ||
| 491 | } | ||
| 492 | |||
| 493 | /** | ||
| 494 | * Remove the breakpoint from the given address of the specified type. | ||
| 495 | * | ||
| 496 | * @param type Type of breakpoint. | ||
| 497 | * @param addr Address of breakpoint. | ||
| 498 | */ | ||
| 499 | static void RemoveBreakpoint(BreakpointType type, VAddr addr) { | ||
| 500 | BreakpointMap& p = GetBreakpointMap(type); | ||
| 501 | |||
| 502 | const auto bp = p.find(addr); | ||
| 503 | if (bp == p.end()) { | ||
| 504 | return; | ||
| 505 | } | ||
| 506 | |||
| 507 | LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", | ||
| 508 | bp->second.len, bp->second.addr, static_cast<int>(type)); | ||
| 509 | |||
| 510 | if (type == BreakpointType::Execute) { | ||
| 511 | auto& system = Core::System::GetInstance(); | ||
| 512 | system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); | ||
| 513 | system.InvalidateCpuInstructionCaches(); | ||
| 514 | } | ||
| 515 | p.erase(addr); | ||
| 516 | } | ||
| 517 | |||
| 518 | BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) { | ||
| 519 | const BreakpointMap& p = GetBreakpointMap(type); | ||
| 520 | const auto next_breakpoint = p.lower_bound(addr); | ||
| 521 | BreakpointAddress breakpoint; | ||
| 522 | |||
| 523 | if (next_breakpoint != p.end()) { | ||
| 524 | breakpoint.address = next_breakpoint->first; | ||
| 525 | breakpoint.type = type; | ||
| 526 | } else { | ||
| 527 | breakpoint.address = 0; | ||
| 528 | breakpoint.type = BreakpointType::None; | ||
| 529 | } | ||
| 530 | |||
| 531 | return breakpoint; | ||
| 532 | } | ||
| 533 | |||
| 534 | bool CheckBreakpoint(VAddr addr, BreakpointType type) { | ||
| 535 | if (!IsConnected()) { | ||
| 536 | return false; | ||
| 537 | } | ||
| 538 | |||
| 539 | const BreakpointMap& p = GetBreakpointMap(type); | ||
| 540 | const auto bp = p.find(addr); | ||
| 541 | |||
| 542 | if (bp == p.end()) { | ||
| 543 | return false; | ||
| 544 | } | ||
| 545 | |||
| 546 | u64 len = bp->second.len; | ||
| 547 | |||
| 548 | // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints | ||
| 549 | // no matter if it's a 4-byte or 2-byte instruction. When you execute a | ||
| 550 | // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on | ||
| 551 | // two instructions instead of the single instruction you placed the breakpoint | ||
| 552 | // on. So, as a way to make sure that execution breakpoints are only breaking | ||
| 553 | // on the instruction that was specified, set the length of an execution | ||
| 554 | // breakpoint to 1. This should be fine since the CPU should never begin executing | ||
| 555 | // an instruction anywhere except the beginning of the instruction. | ||
| 556 | if (type == BreakpointType::Execute) { | ||
| 557 | len = 1; | ||
| 558 | } | ||
| 559 | |||
| 560 | if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { | ||
| 561 | LOG_DEBUG(Debug_GDBStub, | ||
| 562 | "Found breakpoint type {} @ {:016X}, range: {:016X}" | ||
| 563 | " - {:016X} ({:X} bytes)", | ||
| 564 | static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len); | ||
| 565 | return true; | ||
| 566 | } | ||
| 567 | |||
| 568 | return false; | ||
| 569 | } | ||
| 570 | |||
| 571 | /** | ||
| 572 | * Send packet to gdb client. | ||
| 573 | * | ||
| 574 | * @param packet Packet to be sent to client. | ||
| 575 | */ | ||
| 576 | static void SendPacket(const char packet) { | ||
| 577 | std::size_t sent_size = send(gdbserver_socket, &packet, 1, 0); | ||
| 578 | if (sent_size != 1) { | ||
| 579 | LOG_ERROR(Debug_GDBStub, "send failed"); | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | /** | ||
| 584 | * Send reply to gdb client. | ||
| 585 | * | ||
| 586 | * @param reply Reply to be sent to client. | ||
| 587 | */ | ||
| 588 | static void SendReply(const char* reply) { | ||
| 589 | if (!IsConnected()) { | ||
| 590 | return; | ||
| 591 | } | ||
| 592 | |||
| 593 | LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); | ||
| 594 | |||
| 595 | memset(command_buffer, 0, sizeof(command_buffer)); | ||
| 596 | |||
| 597 | command_length = static_cast<u32>(strlen(reply)); | ||
| 598 | if (command_length + 4 > sizeof(command_buffer)) { | ||
| 599 | LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); | ||
| 600 | return; | ||
| 601 | } | ||
| 602 | |||
| 603 | memcpy(command_buffer + 1, reply, command_length); | ||
| 604 | |||
| 605 | u8 checksum = CalculateChecksum(command_buffer, command_length + 1); | ||
| 606 | command_buffer[0] = GDB_STUB_START; | ||
| 607 | command_buffer[command_length + 1] = GDB_STUB_END; | ||
| 608 | command_buffer[command_length + 2] = NibbleToHex(checksum >> 4); | ||
| 609 | command_buffer[command_length + 3] = NibbleToHex(checksum); | ||
| 610 | |||
| 611 | u8* ptr = command_buffer; | ||
| 612 | u32 left = command_length + 4; | ||
| 613 | while (left > 0) { | ||
| 614 | int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0); | ||
| 615 | if (sent_size < 0) { | ||
| 616 | LOG_ERROR(Debug_GDBStub, "gdb: send failed"); | ||
| 617 | return Shutdown(); | ||
| 618 | } | ||
| 619 | |||
| 620 | left -= sent_size; | ||
| 621 | ptr += sent_size; | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | /// Handle query command from gdb client. | ||
| 626 | static void HandleQuery() { | ||
| 627 | LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); | ||
| 628 | |||
| 629 | const char* query = reinterpret_cast<const char*>(command_buffer + 1); | ||
| 630 | |||
| 631 | if (strcmp(query, "TStatus") == 0) { | ||
| 632 | SendReply("T0"); | ||
| 633 | } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { | ||
| 634 | // PacketSize needs to be large enough for target xml | ||
| 635 | std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; | ||
| 636 | if (!modules.empty()) { | ||
| 637 | buffer += ";qXfer:libraries:read+"; | ||
| 638 | } | ||
| 639 | SendReply(buffer.c_str()); | ||
| 640 | } else if (strncmp(query, "Xfer:features:read:target.xml:", | ||
| 641 | strlen("Xfer:features:read:target.xml:")) == 0) { | ||
| 642 | SendReply(target_xml); | ||
| 643 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { | ||
| 644 | const VAddr base_address = | ||
| 645 | Core::System::GetInstance().CurrentProcess()->PageTable().GetCodeRegionStart(); | ||
| 646 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); | ||
| 647 | SendReply(buffer.c_str()); | ||
| 648 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | ||
| 649 | std::string val = "m"; | ||
| 650 | const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); | ||
| 651 | for (const auto& thread : threads) { | ||
| 652 | val += fmt::format("{:x},", thread->GetThreadID()); | ||
| 653 | } | ||
| 654 | val.pop_back(); | ||
| 655 | SendReply(val.c_str()); | ||
| 656 | } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { | ||
| 657 | SendReply("l"); | ||
| 658 | } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { | ||
| 659 | std::string buffer; | ||
| 660 | buffer += "l<?xml version=\"1.0\"?>"; | ||
| 661 | buffer += "<threads>"; | ||
| 662 | const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList(); | ||
| 663 | for (const auto& thread : threads) { | ||
| 664 | buffer += | ||
| 665 | fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*", | ||
| 666 | thread->GetThreadID(), thread->GetProcessorID(), thread->GetThreadID()); | ||
| 667 | } | ||
| 668 | buffer += "</threads>"; | ||
| 669 | SendReply(buffer.c_str()); | ||
| 670 | } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { | ||
| 671 | std::string buffer; | ||
| 672 | buffer += "l<?xml version=\"1.0\"?>"; | ||
| 673 | buffer += "<library-list>"; | ||
| 674 | for (const auto& module : modules) { | ||
| 675 | buffer += | ||
| 676 | fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*", | ||
| 677 | module.name, module.beg); | ||
| 678 | } | ||
| 679 | buffer += "</library-list>"; | ||
| 680 | SendReply(buffer.c_str()); | ||
| 681 | } else { | ||
| 682 | SendReply(""); | ||
| 683 | } | ||
| 684 | } | ||
| 685 | |||
| 686 | /// Handle set thread command from gdb client. | ||
| 687 | static void HandleSetThread() { | ||
| 688 | int thread_id = -1; | ||
| 689 | if (command_buffer[2] != '-') { | ||
| 690 | thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2)); | ||
| 691 | } | ||
| 692 | if (thread_id >= 1) { | ||
| 693 | current_thread = FindThreadById(thread_id); | ||
| 694 | } | ||
| 695 | if (!current_thread) { | ||
| 696 | thread_id = 1; | ||
| 697 | current_thread = FindThreadById(thread_id); | ||
| 698 | } | ||
| 699 | if (current_thread) { | ||
| 700 | SendReply("OK"); | ||
| 701 | return; | ||
| 702 | } | ||
| 703 | SendReply("E01"); | ||
| 704 | } | ||
| 705 | |||
| 706 | /// Handle thread alive command from gdb client. | ||
| 707 | static void HandleThreadAlive() { | ||
| 708 | int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1)); | ||
| 709 | if (thread_id == 0) { | ||
| 710 | thread_id = 1; | ||
| 711 | } | ||
| 712 | if (FindThreadById(thread_id)) { | ||
| 713 | SendReply("OK"); | ||
| 714 | return; | ||
| 715 | } | ||
| 716 | SendReply("E01"); | ||
| 717 | } | ||
| 718 | |||
| 719 | /** | ||
| 720 | * Send signal packet to client. | ||
| 721 | * | ||
| 722 | * @param signal Signal to be sent to client. | ||
| 723 | */ | ||
| 724 | static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { | ||
| 725 | if (gdbserver_socket == -1) { | ||
| 726 | return; | ||
| 727 | } | ||
| 728 | |||
| 729 | latest_signal = signal; | ||
| 730 | |||
| 731 | if (!thread) { | ||
| 732 | full = false; | ||
| 733 | } | ||
| 734 | |||
| 735 | std::string buffer; | ||
| 736 | if (full) { | ||
| 737 | buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, | ||
| 738 | PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, | ||
| 739 | Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, | ||
| 740 | Common::swap64(RegRead(LR_REGISTER, thread))); | ||
| 741 | } else { | ||
| 742 | buffer = fmt::format("T{:02x}", latest_signal); | ||
| 743 | } | ||
| 744 | |||
| 745 | if (thread) { | ||
| 746 | buffer += fmt::format(";thread:{:x};", thread->GetThreadID()); | ||
| 747 | } | ||
| 748 | |||
| 749 | SendReply(buffer.c_str()); | ||
| 750 | } | ||
| 751 | |||
| 752 | /// Read command from gdb client. | ||
| 753 | static void ReadCommand() { | ||
| 754 | command_length = 0; | ||
| 755 | memset(command_buffer, 0, sizeof(command_buffer)); | ||
| 756 | |||
| 757 | u8 c = ReadByte(); | ||
| 758 | if (c == '+') { | ||
| 759 | // ignore ack | ||
| 760 | return; | ||
| 761 | } else if (c == 0x03) { | ||
| 762 | LOG_INFO(Debug_GDBStub, "gdb: found break command"); | ||
| 763 | halt_loop = true; | ||
| 764 | SendSignal(current_thread, SIGTRAP); | ||
| 765 | return; | ||
| 766 | } else if (c != GDB_STUB_START) { | ||
| 767 | LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); | ||
| 768 | return; | ||
| 769 | } | ||
| 770 | |||
| 771 | while ((c = ReadByte()) != GDB_STUB_END) { | ||
| 772 | if (command_length >= sizeof(command_buffer)) { | ||
| 773 | LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); | ||
| 774 | SendPacket(GDB_STUB_NACK); | ||
| 775 | return; | ||
| 776 | } | ||
| 777 | command_buffer[command_length++] = c; | ||
| 778 | } | ||
| 779 | |||
| 780 | u8 checksum_received = HexCharToValue(ReadByte()) << 4; | ||
| 781 | checksum_received |= HexCharToValue(ReadByte()); | ||
| 782 | |||
| 783 | u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); | ||
| 784 | |||
| 785 | if (checksum_received != checksum_calculated) { | ||
| 786 | LOG_ERROR(Debug_GDBStub, | ||
| 787 | "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", | ||
| 788 | checksum_calculated, checksum_received, command_buffer, command_length); | ||
| 789 | |||
| 790 | command_length = 0; | ||
| 791 | |||
| 792 | SendPacket(GDB_STUB_NACK); | ||
| 793 | return; | ||
| 794 | } | ||
| 795 | |||
| 796 | SendPacket(GDB_STUB_ACK); | ||
| 797 | } | ||
| 798 | |||
| 799 | /// Check if there is data to be read from the gdb client. | ||
| 800 | static bool IsDataAvailable() { | ||
| 801 | if (!IsConnected()) { | ||
| 802 | return false; | ||
| 803 | } | ||
| 804 | |||
| 805 | fd_set fd_socket; | ||
| 806 | |||
| 807 | FD_ZERO(&fd_socket); | ||
| 808 | FD_SET(static_cast<u32>(gdbserver_socket), &fd_socket); | ||
| 809 | |||
| 810 | struct timeval t; | ||
| 811 | t.tv_sec = 0; | ||
| 812 | t.tv_usec = 0; | ||
| 813 | |||
| 814 | if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { | ||
| 815 | LOG_ERROR(Debug_GDBStub, "select failed"); | ||
| 816 | return false; | ||
| 817 | } | ||
| 818 | |||
| 819 | return FD_ISSET(gdbserver_socket, &fd_socket) != 0; | ||
| 820 | } | ||
| 821 | |||
| 822 | /// Send requested register to gdb client. | ||
| 823 | static void ReadRegister() { | ||
| 824 | static u8 reply[64]; | ||
| 825 | memset(reply, 0, sizeof(reply)); | ||
| 826 | |||
| 827 | u32 id = HexCharToValue(command_buffer[1]); | ||
| 828 | if (command_buffer[2] != '\0') { | ||
| 829 | id <<= 4; | ||
| 830 | id |= HexCharToValue(command_buffer[2]); | ||
| 831 | } | ||
| 832 | |||
| 833 | if (id <= SP_REGISTER) { | ||
| 834 | LongToGdbHex(reply, RegRead(id, current_thread)); | ||
| 835 | } else if (id == PC_REGISTER) { | ||
| 836 | LongToGdbHex(reply, RegRead(id, current_thread)); | ||
| 837 | } else if (id == PSTATE_REGISTER) { | ||
| 838 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); | ||
| 839 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 840 | u128 r = FpuRead(id, current_thread); | ||
| 841 | LongToGdbHex(reply, r[0]); | ||
| 842 | LongToGdbHex(reply + 16, r[1]); | ||
| 843 | } else if (id == FPCR_REGISTER) { | ||
| 844 | u128 r = FpuRead(id, current_thread); | ||
| 845 | IntToGdbHex(reply, static_cast<u32>(r[0])); | ||
| 846 | } else if (id == FPCR_REGISTER + 1) { | ||
| 847 | u128 r = FpuRead(id, current_thread); | ||
| 848 | IntToGdbHex(reply, static_cast<u32>(r[0] >> 32)); | ||
| 849 | } | ||
| 850 | |||
| 851 | SendReply(reinterpret_cast<char*>(reply)); | ||
| 852 | } | ||
| 853 | |||
| 854 | /// Send all registers to the gdb client. | ||
| 855 | static void ReadRegisters() { | ||
| 856 | static u8 buffer[GDB_BUFFER_SIZE - 4]; | ||
| 857 | memset(buffer, 0, sizeof(buffer)); | ||
| 858 | |||
| 859 | u8* bufptr = buffer; | ||
| 860 | |||
| 861 | for (u32 reg = 0; reg <= SP_REGISTER; reg++) { | ||
| 862 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | ||
| 863 | } | ||
| 864 | |||
| 865 | bufptr += 32 * 16; | ||
| 866 | |||
| 867 | LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); | ||
| 868 | |||
| 869 | bufptr += 16; | ||
| 870 | |||
| 871 | IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread))); | ||
| 872 | |||
| 873 | bufptr += 8; | ||
| 874 | |||
| 875 | u128 r; | ||
| 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]); | ||
| 881 | } | ||
| 882 | |||
| 883 | bufptr += 32 * 32; | ||
| 884 | |||
| 885 | r = FpuRead(FPCR_REGISTER, current_thread); | ||
| 886 | IntToGdbHex(bufptr, static_cast<u32>(r[0])); | ||
| 887 | |||
| 888 | bufptr += 8; | ||
| 889 | |||
| 890 | SendReply(reinterpret_cast<char*>(buffer)); | ||
| 891 | } | ||
| 892 | |||
| 893 | /// Modify data of register specified by gdb client. | ||
| 894 | static void WriteRegister() { | ||
| 895 | const u8* buffer_ptr = command_buffer + 3; | ||
| 896 | |||
| 897 | u32 id = HexCharToValue(command_buffer[1]); | ||
| 898 | if (command_buffer[2] != '=') { | ||
| 899 | ++buffer_ptr; | ||
| 900 | id <<= 4; | ||
| 901 | id |= HexCharToValue(command_buffer[2]); | ||
| 902 | } | ||
| 903 | |||
| 904 | if (id <= SP_REGISTER) { | ||
| 905 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | ||
| 906 | } else if (id == PC_REGISTER) { | ||
| 907 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | ||
| 908 | } else if (id == PSTATE_REGISTER) { | ||
| 909 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | ||
| 910 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 911 | FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread); | ||
| 912 | } else if (id == FPCR_REGISTER) { | ||
| 913 | } else if (id == FPCR_REGISTER + 1) { | ||
| 914 | } | ||
| 915 | |||
| 916 | // Update ARM context, skipping scheduler - no running threads at this point | ||
| 917 | Core::System::GetInstance() | ||
| 918 | .ArmInterface(current_core) | ||
| 919 | .LoadContext(current_thread->GetContext64()); | ||
| 920 | |||
| 921 | SendReply("OK"); | ||
| 922 | } | ||
| 923 | |||
| 924 | /// Modify all registers with data received from the client. | ||
| 925 | static void WriteRegisters() { | ||
| 926 | const u8* buffer_ptr = command_buffer + 1; | ||
| 927 | |||
| 928 | if (command_buffer[0] != 'G') | ||
| 929 | return SendReply("E01"); | ||
| 930 | |||
| 931 | for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) { | ||
| 932 | if (reg <= SP_REGISTER) { | ||
| 933 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 934 | } else if (reg == PC_REGISTER) { | ||
| 935 | RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 936 | } else if (reg == PSTATE_REGISTER) { | ||
| 937 | RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); | ||
| 938 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { | ||
| 939 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 940 | } else if (reg == FPCR_REGISTER) { | ||
| 941 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 942 | } else if (reg == FPCR_REGISTER + 1) { | ||
| 943 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 944 | } | ||
| 945 | } | ||
| 946 | |||
| 947 | // Update ARM context, skipping scheduler - no running threads at this point | ||
| 948 | Core::System::GetInstance() | ||
| 949 | .ArmInterface(current_core) | ||
| 950 | .LoadContext(current_thread->GetContext64()); | ||
| 951 | |||
| 952 | SendReply("OK"); | ||
| 953 | } | ||
| 954 | |||
| 955 | /// Read location in memory specified by gdb client. | ||
| 956 | static void ReadMemory() { | ||
| 957 | static u8 reply[GDB_BUFFER_SIZE - 4]; | ||
| 958 | |||
| 959 | auto start_offset = command_buffer + 1; | ||
| 960 | const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); | ||
| 961 | const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); | ||
| 962 | |||
| 963 | start_offset = addr_pos + 1; | ||
| 964 | const u64 len = | ||
| 965 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); | ||
| 966 | |||
| 967 | LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); | ||
| 968 | |||
| 969 | if (len * 2 > sizeof(reply)) { | ||
| 970 | SendReply("E01"); | ||
| 971 | } | ||
| 972 | |||
| 973 | auto& memory = Core::System::GetInstance().Memory(); | ||
| 974 | if (!memory.IsValidVirtualAddress(addr)) { | ||
| 975 | return SendReply("E00"); | ||
| 976 | } | ||
| 977 | |||
| 978 | std::vector<u8> data(len); | ||
| 979 | memory.ReadBlock(addr, data.data(), len); | ||
| 980 | |||
| 981 | MemToGdbHex(reply, data.data(), len); | ||
| 982 | reply[len * 2] = '\0'; | ||
| 983 | SendReply(reinterpret_cast<char*>(reply)); | ||
| 984 | } | ||
| 985 | |||
| 986 | /// Modify location in memory with data received from the gdb client. | ||
| 987 | static void WriteMemory() { | ||
| 988 | auto start_offset = command_buffer + 1; | ||
| 989 | const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); | ||
| 990 | const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); | ||
| 991 | |||
| 992 | start_offset = addr_pos + 1; | ||
| 993 | const auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); | ||
| 994 | const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); | ||
| 995 | |||
| 996 | auto& system = Core::System::GetInstance(); | ||
| 997 | auto& memory = system.Memory(); | ||
| 998 | if (!memory.IsValidVirtualAddress(addr)) { | ||
| 999 | return SendReply("E00"); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | std::vector<u8> data(len); | ||
| 1003 | GdbHexToMem(data.data(), len_pos + 1, len); | ||
| 1004 | memory.WriteBlock(addr, data.data(), len); | ||
| 1005 | system.InvalidateCpuInstructionCaches(); | ||
| 1006 | SendReply("OK"); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | void Break(bool is_memory_break) { | ||
| 1010 | send_trap = true; | ||
| 1011 | |||
| 1012 | memory_break = is_memory_break; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /// Tell the CPU that it should perform a single step. | ||
| 1016 | static void Step() { | ||
| 1017 | if (command_length > 1) { | ||
| 1018 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | ||
| 1019 | // Update ARM context, skipping scheduler - no running threads at this point | ||
| 1020 | Core::System::GetInstance() | ||
| 1021 | .ArmInterface(current_core) | ||
| 1022 | .LoadContext(current_thread->GetContext64()); | ||
| 1023 | } | ||
| 1024 | step_loop = true; | ||
| 1025 | halt_loop = true; | ||
| 1026 | send_trap = true; | ||
| 1027 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /// Tell the CPU if we hit a memory breakpoint. | ||
| 1031 | bool IsMemoryBreak() { | ||
| 1032 | if (!IsConnected()) { | ||
| 1033 | return false; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | return memory_break; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | /// Tell the CPU to continue executing. | ||
| 1040 | static void Continue() { | ||
| 1041 | memory_break = false; | ||
| 1042 | step_loop = false; | ||
| 1043 | halt_loop = false; | ||
| 1044 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | /** | ||
| 1048 | * Commit breakpoint to list of breakpoints. | ||
| 1049 | * | ||
| 1050 | * @param type Type of breakpoint. | ||
| 1051 | * @param addr Address of breakpoint. | ||
| 1052 | * @param len Length of breakpoint. | ||
| 1053 | */ | ||
| 1054 | static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { | ||
| 1055 | BreakpointMap& p = GetBreakpointMap(type); | ||
| 1056 | |||
| 1057 | Breakpoint breakpoint; | ||
| 1058 | breakpoint.active = true; | ||
| 1059 | breakpoint.addr = addr; | ||
| 1060 | breakpoint.len = len; | ||
| 1061 | |||
| 1062 | auto& system = Core::System::GetInstance(); | ||
| 1063 | auto& memory = system.Memory(); | ||
| 1064 | memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); | ||
| 1065 | |||
| 1066 | static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; | ||
| 1067 | if (type == BreakpointType::Execute) { | ||
| 1068 | memory.WriteBlock(addr, btrap.data(), btrap.size()); | ||
| 1069 | system.InvalidateCpuInstructionCaches(); | ||
| 1070 | } | ||
| 1071 | p.insert({addr, breakpoint}); | ||
| 1072 | |||
| 1073 | LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", | ||
| 1074 | static_cast<int>(type), breakpoint.len, breakpoint.addr); | ||
| 1075 | |||
| 1076 | return true; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | /// Handle add breakpoint command from gdb client. | ||
| 1080 | static void AddBreakpoint() { | ||
| 1081 | BreakpointType type; | ||
| 1082 | |||
| 1083 | u8 type_id = HexCharToValue(command_buffer[1]); | ||
| 1084 | switch (type_id) { | ||
| 1085 | case 0: | ||
| 1086 | case 1: | ||
| 1087 | type = BreakpointType::Execute; | ||
| 1088 | break; | ||
| 1089 | case 2: | ||
| 1090 | type = BreakpointType::Write; | ||
| 1091 | break; | ||
| 1092 | case 3: | ||
| 1093 | type = BreakpointType::Read; | ||
| 1094 | break; | ||
| 1095 | case 4: | ||
| 1096 | type = BreakpointType::Access; | ||
| 1097 | break; | ||
| 1098 | default: | ||
| 1099 | return SendReply("E01"); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | auto start_offset = command_buffer + 3; | ||
| 1103 | auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); | ||
| 1104 | VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); | ||
| 1105 | |||
| 1106 | start_offset = addr_pos + 1; | ||
| 1107 | u64 len = | ||
| 1108 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); | ||
| 1109 | |||
| 1110 | if (type == BreakpointType::Access) { | ||
| 1111 | // Access is made up of Read and Write types, so add both breakpoints | ||
| 1112 | type = BreakpointType::Read; | ||
| 1113 | |||
| 1114 | if (!CommitBreakpoint(type, addr, len)) { | ||
| 1115 | return SendReply("E02"); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | type = BreakpointType::Write; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | if (!CommitBreakpoint(type, addr, len)) { | ||
| 1122 | return SendReply("E02"); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | SendReply("OK"); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | /// Handle remove breakpoint command from gdb client. | ||
| 1129 | static void RemoveBreakpoint() { | ||
| 1130 | BreakpointType type; | ||
| 1131 | |||
| 1132 | u8 type_id = HexCharToValue(command_buffer[1]); | ||
| 1133 | switch (type_id) { | ||
| 1134 | case 0: | ||
| 1135 | case 1: | ||
| 1136 | type = BreakpointType::Execute; | ||
| 1137 | break; | ||
| 1138 | case 2: | ||
| 1139 | type = BreakpointType::Write; | ||
| 1140 | break; | ||
| 1141 | case 3: | ||
| 1142 | type = BreakpointType::Read; | ||
| 1143 | break; | ||
| 1144 | case 4: | ||
| 1145 | type = BreakpointType::Access; | ||
| 1146 | break; | ||
| 1147 | default: | ||
| 1148 | return SendReply("E01"); | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | auto start_offset = command_buffer + 3; | ||
| 1152 | auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); | ||
| 1153 | VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); | ||
| 1154 | |||
| 1155 | if (type == BreakpointType::Access) { | ||
| 1156 | // Access is made up of Read and Write types, so add both breakpoints | ||
| 1157 | type = BreakpointType::Read; | ||
| 1158 | RemoveBreakpoint(type, addr); | ||
| 1159 | |||
| 1160 | type = BreakpointType::Write; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | RemoveBreakpoint(type, addr); | ||
| 1164 | SendReply("OK"); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | void HandlePacket() { | ||
| 1168 | if (!IsConnected()) { | ||
| 1169 | if (defer_start) { | ||
| 1170 | ToggleServer(true); | ||
| 1171 | } | ||
| 1172 | return; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | if (!IsDataAvailable()) { | ||
| 1176 | return; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | ReadCommand(); | ||
| 1180 | if (command_length == 0) { | ||
| 1181 | return; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); | ||
| 1185 | |||
| 1186 | switch (command_buffer[0]) { | ||
| 1187 | case 'q': | ||
| 1188 | HandleQuery(); | ||
| 1189 | break; | ||
| 1190 | case 'H': | ||
| 1191 | HandleSetThread(); | ||
| 1192 | break; | ||
| 1193 | case '?': | ||
| 1194 | SendSignal(current_thread, latest_signal); | ||
| 1195 | break; | ||
| 1196 | case 'k': | ||
| 1197 | Shutdown(); | ||
| 1198 | LOG_INFO(Debug_GDBStub, "killed by gdb"); | ||
| 1199 | return; | ||
| 1200 | case 'g': | ||
| 1201 | ReadRegisters(); | ||
| 1202 | break; | ||
| 1203 | case 'G': | ||
| 1204 | WriteRegisters(); | ||
| 1205 | break; | ||
| 1206 | case 'p': | ||
| 1207 | ReadRegister(); | ||
| 1208 | break; | ||
| 1209 | case 'P': | ||
| 1210 | WriteRegister(); | ||
| 1211 | break; | ||
| 1212 | case 'm': | ||
| 1213 | ReadMemory(); | ||
| 1214 | break; | ||
| 1215 | case 'M': | ||
| 1216 | WriteMemory(); | ||
| 1217 | break; | ||
| 1218 | case 's': | ||
| 1219 | Step(); | ||
| 1220 | return; | ||
| 1221 | case 'C': | ||
| 1222 | case 'c': | ||
| 1223 | Continue(); | ||
| 1224 | return; | ||
| 1225 | case 'z': | ||
| 1226 | RemoveBreakpoint(); | ||
| 1227 | break; | ||
| 1228 | case 'Z': | ||
| 1229 | AddBreakpoint(); | ||
| 1230 | break; | ||
| 1231 | case 'T': | ||
| 1232 | HandleThreadAlive(); | ||
| 1233 | break; | ||
| 1234 | default: | ||
| 1235 | SendReply(""); | ||
| 1236 | break; | ||
| 1237 | } | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | void SetServerPort(u16 port) { | ||
| 1241 | gdbstub_port = port; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | void ToggleServer(bool status) { | ||
| 1245 | if (status) { | ||
| 1246 | server_enabled = status; | ||
| 1247 | |||
| 1248 | // Start server | ||
| 1249 | if (!IsConnected() && Core::System::GetInstance().IsPoweredOn()) { | ||
| 1250 | Init(); | ||
| 1251 | } | ||
| 1252 | } else { | ||
| 1253 | // Stop server | ||
| 1254 | if (IsConnected()) { | ||
| 1255 | Shutdown(); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | server_enabled = status; | ||
| 1259 | } | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | void DeferStart() { | ||
| 1263 | defer_start = true; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | static void Init(u16 port) { | ||
| 1267 | if (!server_enabled) { | ||
| 1268 | // Set the halt loop to false in case the user enabled the gdbstub mid-execution. | ||
| 1269 | // This way the CPU can still execute normally. | ||
| 1270 | halt_loop = false; | ||
| 1271 | step_loop = false; | ||
| 1272 | return; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | // Setup initial gdbstub status | ||
| 1276 | halt_loop = true; | ||
| 1277 | step_loop = false; | ||
| 1278 | |||
| 1279 | breakpoints_execute.clear(); | ||
| 1280 | breakpoints_read.clear(); | ||
| 1281 | breakpoints_write.clear(); | ||
| 1282 | |||
| 1283 | modules.clear(); | ||
| 1284 | |||
| 1285 | // Start gdb server | ||
| 1286 | LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); | ||
| 1287 | |||
| 1288 | sockaddr_in saddr_server = {}; | ||
| 1289 | saddr_server.sin_family = AF_INET; | ||
| 1290 | saddr_server.sin_port = htons(port); | ||
| 1291 | saddr_server.sin_addr.s_addr = INADDR_ANY; | ||
| 1292 | |||
| 1293 | #ifdef _WIN32 | ||
| 1294 | WSAStartup(MAKEWORD(2, 2), &InitData); | ||
| 1295 | #endif | ||
| 1296 | |||
| 1297 | int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0)); | ||
| 1298 | if (tmpsock == -1) { | ||
| 1299 | LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | // Set socket to SO_REUSEADDR so it can always bind on the same port | ||
| 1303 | int reuse_enabled = 1; | ||
| 1304 | if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, | ||
| 1305 | sizeof(reuse_enabled)) < 0) { | ||
| 1306 | LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server); | ||
| 1310 | socklen_t server_addrlen = sizeof(saddr_server); | ||
| 1311 | if (bind(tmpsock, server_addr, server_addrlen) < 0) { | ||
| 1312 | LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | if (listen(tmpsock, 1) < 0) { | ||
| 1316 | LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | // Wait for gdb to connect | ||
| 1320 | LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); | ||
| 1321 | sockaddr_in saddr_client; | ||
| 1322 | sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client); | ||
| 1323 | socklen_t client_addrlen = sizeof(saddr_client); | ||
| 1324 | gdbserver_socket = static_cast<int>(accept(tmpsock, client_addr, &client_addrlen)); | ||
| 1325 | if (gdbserver_socket < 0) { | ||
| 1326 | // In the case that we couldn't start the server for whatever reason, just start CPU | ||
| 1327 | // execution like normal. | ||
| 1328 | halt_loop = false; | ||
| 1329 | step_loop = false; | ||
| 1330 | |||
| 1331 | LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); | ||
| 1332 | } else { | ||
| 1333 | LOG_INFO(Debug_GDBStub, "Client connected."); | ||
| 1334 | saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | // Clean up temporary socket if it's still alive at this point. | ||
| 1338 | if (tmpsock != -1) { | ||
| 1339 | shutdown(tmpsock, SHUT_RDWR); | ||
| 1340 | } | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | void Init() { | ||
| 1344 | Init(gdbstub_port); | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | void Shutdown() { | ||
| 1348 | if (!server_enabled) { | ||
| 1349 | return; | ||
| 1350 | } | ||
| 1351 | defer_start = false; | ||
| 1352 | |||
| 1353 | LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); | ||
| 1354 | if (gdbserver_socket != -1) { | ||
| 1355 | shutdown(gdbserver_socket, SHUT_RDWR); | ||
| 1356 | gdbserver_socket = -1; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | #ifdef _WIN32 | ||
| 1360 | WSACleanup(); | ||
| 1361 | #endif | ||
| 1362 | |||
| 1363 | LOG_INFO(Debug_GDBStub, "GDB stopped."); | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | bool IsServerEnabled() { | ||
| 1367 | return server_enabled; | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | bool IsConnected() { | ||
| 1371 | return IsServerEnabled() && gdbserver_socket != -1; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | bool GetCpuHaltFlag() { | ||
| 1375 | return halt_loop; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | bool GetCpuStepFlag() { | ||
| 1379 | return step_loop; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | void SetCpuStepFlag(bool is_step) { | ||
| 1383 | step_loop = is_step; | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | void SendTrap(Kernel::Thread* thread, int trap) { | ||
| 1387 | if (!send_trap) { | ||
| 1388 | return; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | current_thread = thread; | ||
| 1392 | SendSignal(thread, trap); | ||
| 1393 | |||
| 1394 | halt_loop = true; | ||
| 1395 | send_trap = false; | ||
| 1396 | } | ||
| 1397 | }; // namespace GDBStub | ||
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h deleted file mode 100644 index 8fe3c320b..000000000 --- a/src/core/gdbstub/gdbstub.h +++ /dev/null | |||
| @@ -1,114 +0,0 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. | ||
| 6 | |||
| 7 | #pragma once | ||
| 8 | |||
| 9 | #include <string> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | |||
| 13 | namespace GDBStub { | ||
| 14 | |||
| 15 | /// Breakpoint Method | ||
| 16 | enum class BreakpointType { | ||
| 17 | None, ///< None | ||
| 18 | Execute, ///< Execution Breakpoint | ||
| 19 | Read, ///< Read Breakpoint | ||
| 20 | Write, ///< Write Breakpoint | ||
| 21 | Access ///< Access (R/W) Breakpoint | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct BreakpointAddress { | ||
| 25 | VAddr address; | ||
| 26 | BreakpointType type; | ||
| 27 | }; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Set the port the gdbstub should use to listen for connections. | ||
| 31 | * | ||
| 32 | * @param port Port to listen for connection | ||
| 33 | */ | ||
| 34 | void SetServerPort(u16 port); | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Starts or stops the server if possible. | ||
| 38 | * | ||
| 39 | * @param status Set the server to enabled or disabled. | ||
| 40 | */ | ||
| 41 | void ToggleServer(bool status); | ||
| 42 | |||
| 43 | /// Start the gdbstub server. | ||
| 44 | void Init(); | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Defer initialization of the gdbstub to the first packet processing functions. | ||
| 48 | * This avoids a case where the gdbstub thread is frozen after initialization | ||
| 49 | * and fails to respond in time to packets. | ||
| 50 | */ | ||
| 51 | void DeferStart(); | ||
| 52 | |||
| 53 | /// Stop gdbstub server. | ||
| 54 | void Shutdown(); | ||
| 55 | |||
| 56 | /// Checks if the gdbstub server is enabled. | ||
| 57 | bool IsServerEnabled(); | ||
| 58 | |||
| 59 | /// Returns true if there is an active socket connection. | ||
| 60 | bool IsConnected(); | ||
| 61 | |||
| 62 | /// Register module. | ||
| 63 | void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext = true); | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Signal to the gdbstub server that it should halt CPU execution. | ||
| 67 | * | ||
| 68 | * @param is_memory_break If true, the break resulted from a memory breakpoint. | ||
| 69 | */ | ||
| 70 | void Break(bool is_memory_break = false); | ||
| 71 | |||
| 72 | /// Determine if there was a memory breakpoint. | ||
| 73 | bool IsMemoryBreak(); | ||
| 74 | |||
| 75 | /// Read and handle packet from gdb client. | ||
| 76 | void HandlePacket(); | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Get the nearest breakpoint of the specified type at the given address. | ||
| 80 | * | ||
| 81 | * @param addr Address to search from. | ||
| 82 | * @param type Type of breakpoint. | ||
| 83 | */ | ||
| 84 | BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Check if a breakpoint of the specified type exists at the given address. | ||
| 88 | * | ||
| 89 | * @param addr Address of breakpoint. | ||
| 90 | * @param type Type of breakpoint. | ||
| 91 | */ | ||
| 92 | bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type); | ||
| 93 | |||
| 94 | /// If set to true, the CPU will halt at the beginning of the next CPU loop. | ||
| 95 | bool GetCpuHaltFlag(); | ||
| 96 | |||
| 97 | /// If set to true and the CPU is halted, the CPU will step one instruction. | ||
| 98 | bool GetCpuStepFlag(); | ||
| 99 | |||
| 100 | /** | ||
| 101 | * When set to true, the CPU will step one instruction when the CPU is halted next. | ||
| 102 | * | ||
| 103 | * @param is_step | ||
| 104 | */ | ||
| 105 | void SetCpuStepFlag(bool is_step); | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Send trap signal from thread back to the gdbstub server. | ||
| 109 | * | ||
| 110 | * @param thread Sending thread. | ||
| 111 | * @param trap Trap no. | ||
| 112 | */ | ||
| 113 | void SendTrap(Kernel::Thread* thread, int trap); | ||
| 114 | } // namespace GDBStub | ||
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 1b503331f..56cc911d1 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <utility> | 12 | #include <utility> |
| 13 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "core/core.h" | ||
| 16 | #include "core/hle/ipc.h" | 15 | #include "core/hle/ipc.h" |
| 17 | #include "core/hle/kernel/client_port.h" | 16 | #include "core/hle/kernel/client_port.h" |
| 18 | #include "core/hle/kernel/client_session.h" | 17 | #include "core/hle/kernel/client_session.h" |
| @@ -38,10 +37,11 @@ public: | |||
| 38 | explicit RequestHelperBase(Kernel::HLERequestContext& context) | 37 | explicit RequestHelperBase(Kernel::HLERequestContext& context) |
| 39 | : context(&context), cmdbuf(context.CommandBuffer()) {} | 38 | : context(&context), cmdbuf(context.CommandBuffer()) {} |
| 40 | 39 | ||
| 41 | void Skip(unsigned size_in_words, bool set_to_null) { | 40 | void Skip(u32 size_in_words, bool set_to_null) { |
| 42 | if (set_to_null) | 41 | if (set_to_null) { |
| 43 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); | 42 | memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); |
| 44 | index += size_in_words; | 43 | } |
| 44 | index += static_cast<ptrdiff_t>(size_in_words); | ||
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| @@ -49,15 +49,15 @@ public: | |||
| 49 | */ | 49 | */ |
| 50 | void AlignWithPadding() { | 50 | void AlignWithPadding() { |
| 51 | if (index & 3) { | 51 | if (index & 3) { |
| 52 | Skip(4 - (index & 3), true); | 52 | Skip(static_cast<u32>(4 - (index & 3)), true); |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | unsigned GetCurrentOffset() const { | 56 | u32 GetCurrentOffset() const { |
| 57 | return static_cast<unsigned>(index); | 57 | return static_cast<u32>(index); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | void SetCurrentOffset(unsigned offset) { | 60 | void SetCurrentOffset(u32 offset) { |
| 61 | index = static_cast<ptrdiff_t>(offset); | 61 | index = static_cast<ptrdiff_t>(offset); |
| 62 | } | 62 | } |
| 63 | }; | 63 | }; |
| @@ -72,14 +72,12 @@ public: | |||
| 72 | AlwaysMoveHandles = 1, | 72 | AlwaysMoveHandles = 1, |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | explicit ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} | ||
| 76 | |||
| 77 | explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, | 75 | explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, |
| 78 | u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, | 76 | u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, |
| 79 | Flags flags = Flags::None) | 77 | Flags flags = Flags::None) |
| 80 | |||
| 81 | : RequestHelperBase(context), normal_params_size(normal_params_size), | 78 | : RequestHelperBase(context), normal_params_size(normal_params_size), |
| 82 | num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) { | 79 | num_handles_to_copy(num_handles_to_copy), |
| 80 | num_objects_to_move(num_objects_to_move), kernel{context.kernel} { | ||
| 83 | 81 | ||
| 84 | memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); | 82 | memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); |
| 85 | 83 | ||
| @@ -89,7 +87,7 @@ public: | |||
| 89 | 87 | ||
| 90 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory | 88 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory |
| 91 | // padding. | 89 | // padding. |
| 92 | u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; | 90 | u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; |
| 93 | 91 | ||
| 94 | u32 num_handles_to_move{}; | 92 | u32 num_handles_to_move{}; |
| 95 | u32 num_domain_objects{}; | 93 | u32 num_domain_objects{}; |
| @@ -105,7 +103,7 @@ public: | |||
| 105 | raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; | 103 | raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; |
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | header.data_size.Assign(raw_data_size); | 106 | header.data_size.Assign(static_cast<u32>(raw_data_size)); |
| 109 | if (num_handles_to_copy || num_handles_to_move) { | 107 | if (num_handles_to_copy || num_handles_to_move) { |
| 110 | header.enable_handle_descriptor.Assign(1); | 108 | header.enable_handle_descriptor.Assign(1); |
| 111 | } | 109 | } |
| @@ -139,7 +137,6 @@ public: | |||
| 139 | if (context->Session()->IsDomain()) { | 137 | if (context->Session()->IsDomain()) { |
| 140 | context->AddDomainObject(std::move(iface)); | 138 | context->AddDomainObject(std::move(iface)); |
| 141 | } else { | 139 | } else { |
| 142 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 143 | auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); | 140 | auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); |
| 144 | context->AddMoveObject(std::move(client)); | 141 | context->AddMoveObject(std::move(client)); |
| 145 | iface->ClientConnected(std::move(server)); | 142 | iface->ClientConnected(std::move(server)); |
| @@ -169,8 +166,23 @@ public: | |||
| 169 | ValidateHeader(); | 166 | ValidateHeader(); |
| 170 | } | 167 | } |
| 171 | 168 | ||
| 169 | void PushImpl(s8 value); | ||
| 170 | void PushImpl(s16 value); | ||
| 171 | void PushImpl(s32 value); | ||
| 172 | void PushImpl(s64 value); | ||
| 173 | void PushImpl(u8 value); | ||
| 174 | void PushImpl(u16 value); | ||
| 175 | void PushImpl(u32 value); | ||
| 176 | void PushImpl(u64 value); | ||
| 177 | void PushImpl(float value); | ||
| 178 | void PushImpl(double value); | ||
| 179 | void PushImpl(bool value); | ||
| 180 | void PushImpl(ResultCode value); | ||
| 181 | |||
| 172 | template <typename T> | 182 | template <typename T> |
| 173 | void Push(T value); | 183 | void Push(T value) { |
| 184 | return PushImpl(value); | ||
| 185 | } | ||
| 174 | 186 | ||
| 175 | template <typename First, typename... Other> | 187 | template <typename First, typename... Other> |
| 176 | void Push(const First& first_value, const Other&... other_values); | 188 | void Push(const First& first_value, const Other&... other_values); |
| @@ -213,17 +225,16 @@ private: | |||
| 213 | u32 num_handles_to_copy{}; | 225 | u32 num_handles_to_copy{}; |
| 214 | u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent | 226 | u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent |
| 215 | std::ptrdiff_t datapayload_index{}; | 227 | std::ptrdiff_t datapayload_index{}; |
| 228 | Kernel::KernelCore& kernel; | ||
| 216 | }; | 229 | }; |
| 217 | 230 | ||
| 218 | /// Push /// | 231 | /// Push /// |
| 219 | 232 | ||
| 220 | template <> | 233 | inline void ResponseBuilder::PushImpl(s32 value) { |
| 221 | inline void ResponseBuilder::Push(s32 value) { | ||
| 222 | cmdbuf[index++] = static_cast<u32>(value); | 234 | cmdbuf[index++] = static_cast<u32>(value); |
| 223 | } | 235 | } |
| 224 | 236 | ||
| 225 | template <> | 237 | inline void ResponseBuilder::PushImpl(u32 value) { |
| 226 | inline void ResponseBuilder::Push(u32 value) { | ||
| 227 | cmdbuf[index++] = value; | 238 | cmdbuf[index++] = value; |
| 228 | } | 239 | } |
| 229 | 240 | ||
| @@ -235,62 +246,52 @@ void ResponseBuilder::PushRaw(const T& value) { | |||
| 235 | index += (sizeof(T) + 3) / 4; // round up to word length | 246 | index += (sizeof(T) + 3) / 4; // round up to word length |
| 236 | } | 247 | } |
| 237 | 248 | ||
| 238 | template <> | 249 | inline void ResponseBuilder::PushImpl(ResultCode value) { |
| 239 | inline void ResponseBuilder::Push(ResultCode value) { | ||
| 240 | // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded. | 250 | // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded. |
| 241 | Push(value.raw); | 251 | Push(value.raw); |
| 242 | Push<u32>(0); | 252 | Push<u32>(0); |
| 243 | } | 253 | } |
| 244 | 254 | ||
| 245 | template <> | 255 | inline void ResponseBuilder::PushImpl(s8 value) { |
| 246 | inline void ResponseBuilder::Push(s8 value) { | ||
| 247 | PushRaw(value); | 256 | PushRaw(value); |
| 248 | } | 257 | } |
| 249 | 258 | ||
| 250 | template <> | 259 | inline void ResponseBuilder::PushImpl(s16 value) { |
| 251 | inline void ResponseBuilder::Push(s16 value) { | ||
| 252 | PushRaw(value); | 260 | PushRaw(value); |
| 253 | } | 261 | } |
| 254 | 262 | ||
| 255 | template <> | 263 | inline void ResponseBuilder::PushImpl(s64 value) { |
| 256 | inline void ResponseBuilder::Push(s64 value) { | 264 | PushImpl(static_cast<u32>(value)); |
| 257 | Push(static_cast<u32>(value)); | 265 | PushImpl(static_cast<u32>(value >> 32)); |
| 258 | Push(static_cast<u32>(value >> 32)); | ||
| 259 | } | 266 | } |
| 260 | 267 | ||
| 261 | template <> | 268 | inline void ResponseBuilder::PushImpl(u8 value) { |
| 262 | inline void ResponseBuilder::Push(u8 value) { | ||
| 263 | PushRaw(value); | 269 | PushRaw(value); |
| 264 | } | 270 | } |
| 265 | 271 | ||
| 266 | template <> | 272 | inline void ResponseBuilder::PushImpl(u16 value) { |
| 267 | inline void ResponseBuilder::Push(u16 value) { | ||
| 268 | PushRaw(value); | 273 | PushRaw(value); |
| 269 | } | 274 | } |
| 270 | 275 | ||
| 271 | template <> | 276 | inline void ResponseBuilder::PushImpl(u64 value) { |
| 272 | inline void ResponseBuilder::Push(u64 value) { | 277 | PushImpl(static_cast<u32>(value)); |
| 273 | Push(static_cast<u32>(value)); | 278 | PushImpl(static_cast<u32>(value >> 32)); |
| 274 | Push(static_cast<u32>(value >> 32)); | ||
| 275 | } | 279 | } |
| 276 | 280 | ||
| 277 | template <> | 281 | inline void ResponseBuilder::PushImpl(float value) { |
| 278 | inline void ResponseBuilder::Push(float value) { | ||
| 279 | u32 integral; | 282 | u32 integral; |
| 280 | std::memcpy(&integral, &value, sizeof(u32)); | 283 | std::memcpy(&integral, &value, sizeof(u32)); |
| 281 | Push(integral); | 284 | PushImpl(integral); |
| 282 | } | 285 | } |
| 283 | 286 | ||
| 284 | template <> | 287 | inline void ResponseBuilder::PushImpl(double value) { |
| 285 | inline void ResponseBuilder::Push(double value) { | ||
| 286 | u64 integral; | 288 | u64 integral; |
| 287 | std::memcpy(&integral, &value, sizeof(u64)); | 289 | std::memcpy(&integral, &value, sizeof(u64)); |
| 288 | Push(integral); | 290 | PushImpl(integral); |
| 289 | } | 291 | } |
| 290 | 292 | ||
| 291 | template <> | 293 | inline void ResponseBuilder::PushImpl(bool value) { |
| 292 | inline void ResponseBuilder::Push(bool value) { | 294 | PushImpl(static_cast<u8>(value)); |
| 293 | Push(static_cast<u8>(value)); | ||
| 294 | } | 295 | } |
| 295 | 296 | ||
| 296 | template <typename First, typename... Other> | 297 | template <typename First, typename... Other> |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index b882eaa0f..20ffa7d47 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -12,8 +12,9 @@ | |||
| 12 | #include "core/hle/kernel/address_arbiter.h" | 12 | #include "core/hle/kernel/address_arbiter.h" |
| 13 | #include "core/hle/kernel/errors.h" | 13 | #include "core/hle/kernel/errors.h" |
| 14 | #include "core/hle/kernel/handle_table.h" | 14 | #include "core/hle/kernel/handle_table.h" |
| 15 | #include "core/hle/kernel/k_scheduler.h" | ||
| 16 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/scheduler.h" | ||
| 17 | #include "core/hle/kernel/thread.h" | 18 | #include "core/hle/kernel/thread.h" |
| 18 | #include "core/hle/kernel/time_manager.h" | 19 | #include "core/hle/kernel/time_manager.h" |
| 19 | #include "core/hle/result.h" | 20 | #include "core/hle/result.h" |
| @@ -58,7 +59,7 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v | |||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { | 61 | ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { |
| 61 | SchedulerLock lock(system.Kernel()); | 62 | KScopedSchedulerLock lock(system.Kernel()); |
| 62 | const std::vector<std::shared_ptr<Thread>> waiting_threads = | 63 | const std::vector<std::shared_ptr<Thread>> waiting_threads = |
| 63 | GetThreadsWaitingOnAddress(address); | 64 | GetThreadsWaitingOnAddress(address); |
| 64 | WakeThreads(waiting_threads, num_to_wake); | 65 | WakeThreads(waiting_threads, num_to_wake); |
| @@ -67,7 +68,7 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { | |||
| 67 | 68 | ||
| 68 | ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, | 69 | ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, |
| 69 | s32 num_to_wake) { | 70 | s32 num_to_wake) { |
| 70 | SchedulerLock lock(system.Kernel()); | 71 | KScopedSchedulerLock lock(system.Kernel()); |
| 71 | auto& memory = system.Memory(); | 72 | auto& memory = system.Memory(); |
| 72 | 73 | ||
| 73 | // Ensure that we can write to the address. | 74 | // Ensure that we can write to the address. |
| @@ -92,7 +93,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 | |||
| 92 | 93 | ||
| 93 | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, | 94 | ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, |
| 94 | s32 num_to_wake) { | 95 | s32 num_to_wake) { |
| 95 | SchedulerLock lock(system.Kernel()); | 96 | KScopedSchedulerLock lock(system.Kernel()); |
| 96 | auto& memory = system.Memory(); | 97 | auto& memory = system.Memory(); |
| 97 | 98 | ||
| 98 | // Ensure that we can write to the address. | 99 | // Ensure that we can write to the address. |
| @@ -153,11 +154,11 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 153 | bool should_decrement) { | 154 | bool should_decrement) { |
| 154 | auto& memory = system.Memory(); | 155 | auto& memory = system.Memory(); |
| 155 | auto& kernel = system.Kernel(); | 156 | auto& kernel = system.Kernel(); |
| 156 | Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); | 157 | Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 157 | 158 | ||
| 158 | Handle event_handle = InvalidHandle; | 159 | Handle event_handle = InvalidHandle; |
| 159 | { | 160 | { |
| 160 | SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 161 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); |
| 161 | 162 | ||
| 162 | if (current_thread->IsPendingTermination()) { | 163 | if (current_thread->IsPendingTermination()) { |
| 163 | lock.CancelSleep(); | 164 | lock.CancelSleep(); |
| @@ -210,7 +211,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 210 | } | 211 | } |
| 211 | 212 | ||
| 212 | { | 213 | { |
| 213 | SchedulerLock lock(kernel); | 214 | KScopedSchedulerLock lock(kernel); |
| 214 | if (current_thread->IsWaitingForArbitration()) { | 215 | if (current_thread->IsWaitingForArbitration()) { |
| 215 | RemoveThread(SharedFrom(current_thread)); | 216 | RemoveThread(SharedFrom(current_thread)); |
| 216 | current_thread->WaitForArbitration(false); | 217 | current_thread->WaitForArbitration(false); |
| @@ -223,11 +224,11 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 | |||
| 223 | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { | 224 | ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { |
| 224 | auto& memory = system.Memory(); | 225 | auto& memory = system.Memory(); |
| 225 | auto& kernel = system.Kernel(); | 226 | auto& kernel = system.Kernel(); |
| 226 | Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); | 227 | Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 227 | 228 | ||
| 228 | Handle event_handle = InvalidHandle; | 229 | Handle event_handle = InvalidHandle; |
| 229 | { | 230 | { |
| 230 | SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); | 231 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); |
| 231 | 232 | ||
| 232 | if (current_thread->IsPendingTermination()) { | 233 | if (current_thread->IsPendingTermination()) { |
| 233 | lock.CancelSleep(); | 234 | lock.CancelSleep(); |
| @@ -265,7 +266,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t | |||
| 265 | } | 266 | } |
| 266 | 267 | ||
| 267 | { | 268 | { |
| 268 | SchedulerLock lock(kernel); | 269 | KScopedSchedulerLock lock(kernel); |
| 269 | if (current_thread->IsWaitingForArbitration()) { | 270 | if (current_thread->IsWaitingForArbitration()) { |
| 270 | RemoveThread(SharedFrom(current_thread)); | 271 | RemoveThread(SharedFrom(current_thread)); |
| 271 | current_thread->WaitForArbitration(false); | 272 | current_thread->WaitForArbitration(false); |
| @@ -275,12 +276,6 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t | |||
| 275 | return current_thread->GetSignalingResult(); | 276 | return current_thread->GetSignalingResult(); |
| 276 | } | 277 | } |
| 277 | 278 | ||
| 278 | void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) { | ||
| 279 | ASSERT(thread->GetStatus() == ThreadStatus::WaitArb); | ||
| 280 | RemoveThread(thread); | ||
| 281 | thread->SetArbiterWaitAddress(0); | ||
| 282 | } | ||
| 283 | |||
| 284 | void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { | 279 | void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { |
| 285 | const VAddr arb_addr = thread->GetArbiterWaitAddress(); | 280 | const VAddr arb_addr = thread->GetArbiterWaitAddress(); |
| 286 | std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; | 281 | std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; |
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 0b05d533c..b91edc67d 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -50,9 +50,6 @@ public: | |||
| 50 | /// Waits on an address with a particular arbitration type. | 50 | /// Waits on an address with a particular arbitration type. |
| 51 | ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); | 51 | ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); |
| 52 | 52 | ||
| 53 | /// Removes a thread from the container and resets its address arbiter adress to 0 | ||
| 54 | void HandleWakeupThread(std::shared_ptr<Thread> thread); | ||
| 55 | |||
| 56 | private: | 53 | private: |
| 57 | /// Signals an address being waited on. | 54 | /// Signals an address being waited on. |
| 58 | ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); | 55 | ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); |
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp new file mode 100644 index 000000000..a133e8ed0 --- /dev/null +++ b/src/core/hle/kernel/global_scheduler_context.cpp | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <mutex> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/hle/kernel/global_scheduler_context.h" | ||
| 10 | #include "core/hle/kernel/k_scheduler.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) | ||
| 16 | : kernel{kernel}, scheduler_lock{kernel} {} | ||
| 17 | |||
| 18 | GlobalSchedulerContext::~GlobalSchedulerContext() = default; | ||
| 19 | |||
| 20 | void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) { | ||
| 21 | std::scoped_lock lock{global_list_guard}; | ||
| 22 | thread_list.push_back(std::move(thread)); | ||
| 23 | } | ||
| 24 | |||
| 25 | void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) { | ||
| 26 | std::scoped_lock lock{global_list_guard}; | ||
| 27 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | ||
| 28 | thread_list.end()); | ||
| 29 | } | ||
| 30 | |||
| 31 | void GlobalSchedulerContext::PreemptThreads() { | ||
| 32 | // The priority levels at which the global scheduler preempts threads every 10 ms. They are | ||
| 33 | // ordered from Core 0 to Core 3. | ||
| 34 | static constexpr std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities{ | ||
| 35 | 59, | ||
| 36 | 59, | ||
| 37 | 59, | ||
| 38 | 63, | ||
| 39 | }; | ||
| 40 | |||
| 41 | ASSERT(IsLocked()); | ||
| 42 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||
| 43 | const u32 priority = preemption_priorities[core_id]; | ||
| 44 | kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | bool GlobalSchedulerContext::IsLocked() const { | ||
| 49 | return scheduler_lock.IsLockedByCurrentThread(); | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h new file mode 100644 index 000000000..5c7b89290 --- /dev/null +++ b/src/core/hle/kernel/global_scheduler_context.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/spin_lock.h" | ||
| 12 | #include "core/hardware_properties.h" | ||
| 13 | #include "core/hle/kernel/k_priority_queue.h" | ||
| 14 | #include "core/hle/kernel/k_scheduler_lock.h" | ||
| 15 | #include "core/hle/kernel/thread.h" | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | class KernelCore; | ||
| 20 | class SchedulerLock; | ||
| 21 | |||
| 22 | using KSchedulerPriorityQueue = | ||
| 23 | KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>; | ||
| 24 | constexpr s32 HighestCoreMigrationAllowedPriority = 2; | ||
| 25 | |||
| 26 | class GlobalSchedulerContext final { | ||
| 27 | friend class KScheduler; | ||
| 28 | |||
| 29 | public: | ||
| 30 | using LockType = KAbstractSchedulerLock<KScheduler>; | ||
| 31 | |||
| 32 | explicit GlobalSchedulerContext(KernelCore& kernel); | ||
| 33 | ~GlobalSchedulerContext(); | ||
| 34 | |||
| 35 | /// Adds a new thread to the scheduler | ||
| 36 | void AddThread(std::shared_ptr<Thread> thread); | ||
| 37 | |||
| 38 | /// Removes a thread from the scheduler | ||
| 39 | void RemoveThread(std::shared_ptr<Thread> thread); | ||
| 40 | |||
| 41 | /// Returns a list of all threads managed by the scheduler | ||
| 42 | [[nodiscard]] const std::vector<std::shared_ptr<Thread>>& GetThreadList() const { | ||
| 43 | return thread_list; | ||
| 44 | } | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Rotates the scheduling queues of threads at a preemption priority and then does | ||
| 48 | * some core rebalancing. Preemption priorities can be found in the array | ||
| 49 | * 'preemption_priorities'. | ||
| 50 | * | ||
| 51 | * @note This operation happens every 10ms. | ||
| 52 | */ | ||
| 53 | void PreemptThreads(); | ||
| 54 | |||
| 55 | /// Returns true if the global scheduler lock is acquired | ||
| 56 | bool IsLocked() const; | ||
| 57 | |||
| 58 | [[nodiscard]] LockType& SchedulerLock() { | ||
| 59 | return scheduler_lock; | ||
| 60 | } | ||
| 61 | |||
| 62 | [[nodiscard]] const LockType& SchedulerLock() const { | ||
| 63 | return scheduler_lock; | ||
| 64 | } | ||
| 65 | |||
| 66 | private: | ||
| 67 | friend class KScopedSchedulerLock; | ||
| 68 | friend class KScopedSchedulerLockAndSleep; | ||
| 69 | |||
| 70 | KernelCore& kernel; | ||
| 71 | |||
| 72 | std::atomic_bool scheduler_update_needed{}; | ||
| 73 | KSchedulerPriorityQueue priority_queue; | ||
| 74 | LockType scheduler_lock; | ||
| 75 | |||
| 76 | /// Lists all thread ids that aren't deleted/etc. | ||
| 77 | std::vector<std::shared_ptr<Thread>> thread_list; | ||
| 78 | Common::SpinLock global_list_guard{}; | ||
| 79 | }; | ||
| 80 | |||
| 81 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index fb30b6f8b..40988b0fd 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 10 | #include "core/hle/kernel/handle_table.h" | 10 | #include "core/hle/kernel/handle_table.h" |
| 11 | #include "core/hle/kernel/k_scheduler.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/scheduler.h" | ||
| 14 | #include "core/hle/kernel/thread.h" | 14 | #include "core/hle/kernel/thread.h" |
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| @@ -105,7 +105,7 @@ bool HandleTable::IsValid(Handle handle) const { | |||
| 105 | 105 | ||
| 106 | std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { | 106 | std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { |
| 107 | if (handle == CurrentThread) { | 107 | if (handle == CurrentThread) { |
| 108 | return SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); | 108 | return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread()); |
| 109 | } else if (handle == CurrentProcess) { | 109 | } else if (handle == CurrentProcess) { |
| 110 | return SharedFrom(kernel.CurrentProcess()); | 110 | return SharedFrom(kernel.CurrentProcess()); |
| 111 | } | 111 | } |
| @@ -118,7 +118,7 @@ std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { | |||
| 118 | 118 | ||
| 119 | void HandleTable::Clear() { | 119 | void HandleTable::Clear() { |
| 120 | for (u16 i = 0; i < table_size; ++i) { | 120 | for (u16 i = 0; i < table_size; ++i) { |
| 121 | generations[i] = i + 1; | 121 | generations[i] = static_cast<u16>(i + 1); |
| 122 | objects[i] = nullptr; | 122 | objects[i] = nullptr; |
| 123 | } | 123 | } |
| 124 | next_free_slot = 0; | 124 | next_free_slot = 0; |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 81f85643b..83decf6cf 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -17,11 +17,12 @@ | |||
| 17 | #include "core/hle/kernel/errors.h" | 17 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/handle_table.h" | 18 | #include "core/hle/kernel/handle_table.h" |
| 19 | #include "core/hle/kernel/hle_ipc.h" | 19 | #include "core/hle/kernel/hle_ipc.h" |
| 20 | #include "core/hle/kernel/k_scheduler.h" | ||
| 21 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 20 | #include "core/hle/kernel/kernel.h" | 22 | #include "core/hle/kernel/kernel.h" |
| 21 | #include "core/hle/kernel/object.h" | 23 | #include "core/hle/kernel/object.h" |
| 22 | #include "core/hle/kernel/process.h" | 24 | #include "core/hle/kernel/process.h" |
| 23 | #include "core/hle/kernel/readable_event.h" | 25 | #include "core/hle/kernel/readable_event.h" |
| 24 | #include "core/hle/kernel/scheduler.h" | ||
| 25 | #include "core/hle/kernel/server_session.h" | 26 | #include "core/hle/kernel/server_session.h" |
| 26 | #include "core/hle/kernel/thread.h" | 27 | #include "core/hle/kernel/thread.h" |
| 27 | #include "core/hle/kernel/time_manager.h" | 28 | #include "core/hle/kernel/time_manager.h" |
| @@ -45,44 +46,6 @@ void SessionRequestHandler::ClientDisconnected( | |||
| 45 | boost::range::remove_erase(connected_sessions, server_session); | 46 | boost::range::remove_erase(connected_sessions, server_session); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( | ||
| 49 | const std::string& reason, u64 timeout, WakeupCallback&& callback, | ||
| 50 | std::shared_ptr<WritableEvent> writable_event) { | ||
| 51 | // Put the client thread to sleep until the wait event is signaled or the timeout expires. | ||
| 52 | |||
| 53 | if (!writable_event) { | ||
| 54 | // Create event if not provided | ||
| 55 | const auto pair = WritableEvent::CreateEventPair(kernel, "HLE Pause Event: " + reason); | ||
| 56 | writable_event = pair.writable; | ||
| 57 | } | ||
| 58 | |||
| 59 | { | ||
| 60 | Handle event_handle = InvalidHandle; | ||
| 61 | SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout); | ||
| 62 | thread->SetHLECallback( | ||
| 63 | [context = *this, callback](std::shared_ptr<Thread> thread) mutable -> bool { | ||
| 64 | ThreadWakeupReason reason = thread->GetSignalingResult() == RESULT_TIMEOUT | ||
| 65 | ? ThreadWakeupReason::Timeout | ||
| 66 | : ThreadWakeupReason::Signal; | ||
| 67 | callback(thread, context, reason); | ||
| 68 | context.WriteToOutgoingCommandBuffer(*thread); | ||
| 69 | return true; | ||
| 70 | }); | ||
| 71 | const auto readable_event{writable_event->GetReadableEvent()}; | ||
| 72 | writable_event->Clear(); | ||
| 73 | thread->SetHLESyncObject(readable_event.get()); | ||
| 74 | thread->SetStatus(ThreadStatus::WaitHLEEvent); | ||
| 75 | thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); | ||
| 76 | readable_event->AddWaitingThread(thread); | ||
| 77 | lock.Release(); | ||
| 78 | thread->SetHLETimeEvent(event_handle); | ||
| 79 | } | ||
| 80 | |||
| 81 | is_thread_waiting = true; | ||
| 82 | |||
| 83 | return writable_event; | ||
| 84 | } | ||
| 85 | |||
| 86 | HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, | 49 | HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, |
| 87 | std::shared_ptr<ServerSession> server_session, | 50 | std::shared_ptr<ServerSession> server_session, |
| 88 | std::shared_ptr<Thread> thread) | 51 | std::shared_ptr<Thread> thread) |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index f3277b766..b112e1ebd 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -24,6 +24,10 @@ namespace Core::Memory { | |||
| 24 | class Memory; | 24 | class Memory; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | namespace IPC { | ||
| 28 | class ResponseBuilder; | ||
| 29 | } | ||
| 30 | |||
| 27 | namespace Service { | 31 | namespace Service { |
| 28 | class ServiceFrameworkBase; | 32 | class ServiceFrameworkBase; |
| 29 | } | 33 | } |
| @@ -125,23 +129,6 @@ public: | |||
| 125 | using WakeupCallback = std::function<void( | 129 | using WakeupCallback = std::function<void( |
| 126 | std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; | 130 | std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; |
| 127 | 131 | ||
| 128 | /** | ||
| 129 | * Puts the specified guest thread to sleep until the returned event is signaled or until the | ||
| 130 | * specified timeout expires. | ||
| 131 | * @param reason Reason for pausing the thread, to be used for debugging purposes. | ||
| 132 | * @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback | ||
| 133 | * invoked with a Timeout reason. | ||
| 134 | * @param callback Callback to be invoked when the thread is resumed. This callback must write | ||
| 135 | * the entire command response once again, regardless of the state of it before this function | ||
| 136 | * was called. | ||
| 137 | * @param writable_event Event to use to wake up the thread. If unspecified, an event will be | ||
| 138 | * created. | ||
| 139 | * @returns Event that when signaled will resume the thread and call the callback function. | ||
| 140 | */ | ||
| 141 | std::shared_ptr<WritableEvent> SleepClientThread( | ||
| 142 | const std::string& reason, u64 timeout, WakeupCallback&& callback, | ||
| 143 | std::shared_ptr<WritableEvent> writable_event = nullptr); | ||
| 144 | |||
| 145 | /// Populates this context with data from the requesting process/thread. | 132 | /// Populates this context with data from the requesting process/thread. |
| 146 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, | 133 | ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, |
| 147 | u32_le* src_cmdbuf); | 134 | u32_le* src_cmdbuf); |
| @@ -287,6 +274,8 @@ public: | |||
| 287 | } | 274 | } |
| 288 | 275 | ||
| 289 | private: | 276 | private: |
| 277 | friend class IPC::ResponseBuilder; | ||
| 278 | |||
| 290 | void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); | 279 | void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); |
| 291 | 280 | ||
| 292 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | 281 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; |
diff --git a/src/core/hle/kernel/k_affinity_mask.h b/src/core/hle/kernel/k_affinity_mask.h new file mode 100644 index 000000000..dd73781cd --- /dev/null +++ b/src/core/hle/kernel/k_affinity_mask.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/hardware_properties.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class KAffinityMask { | ||
| 17 | public: | ||
| 18 | constexpr KAffinityMask() = default; | ||
| 19 | |||
| 20 | [[nodiscard]] constexpr u64 GetAffinityMask() const { | ||
| 21 | return this->mask; | ||
| 22 | } | ||
| 23 | |||
| 24 | constexpr void SetAffinityMask(u64 new_mask) { | ||
| 25 | ASSERT((new_mask & ~AllowedAffinityMask) == 0); | ||
| 26 | this->mask = new_mask; | ||
| 27 | } | ||
| 28 | |||
| 29 | [[nodiscard]] constexpr bool GetAffinity(s32 core) const { | ||
| 30 | return this->mask & GetCoreBit(core); | ||
| 31 | } | ||
| 32 | |||
| 33 | constexpr void SetAffinity(s32 core, bool set) { | ||
| 34 | ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 35 | |||
| 36 | if (set) { | ||
| 37 | this->mask |= GetCoreBit(core); | ||
| 38 | } else { | ||
| 39 | this->mask &= ~GetCoreBit(core); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | constexpr void SetAll() { | ||
| 44 | this->mask = AllowedAffinityMask; | ||
| 45 | } | ||
| 46 | |||
| 47 | private: | ||
| 48 | [[nodiscard]] static constexpr u64 GetCoreBit(s32 core) { | ||
| 49 | ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | ||
| 50 | return (1ULL << core); | ||
| 51 | } | ||
| 52 | |||
| 53 | static constexpr u64 AllowedAffinityMask = (1ULL << Core::Hardware::NUM_CPU_CORES) - 1; | ||
| 54 | |||
| 55 | u64 mask{}; | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h new file mode 100644 index 000000000..99fb8fe93 --- /dev/null +++ b/src/core/hle/kernel/k_priority_queue.h | |||
| @@ -0,0 +1,451 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include <array> | ||
| 11 | #include <concepts> | ||
| 12 | |||
| 13 | #include "common/assert.h" | ||
| 14 | #include "common/bit_set.h" | ||
| 15 | #include "common/bit_util.h" | ||
| 16 | #include "common/common_types.h" | ||
| 17 | #include "common/concepts.h" | ||
| 18 | |||
| 19 | namespace Kernel { | ||
| 20 | |||
| 21 | class Thread; | ||
| 22 | |||
| 23 | template <typename T> | ||
| 24 | concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { | ||
| 25 | { t.GetAffinityMask() } | ||
| 26 | ->Common::ConvertibleTo<u64>; | ||
| 27 | {t.SetAffinityMask(std::declval<u64>())}; | ||
| 28 | |||
| 29 | { t.GetAffinity(std::declval<int32_t>()) } | ||
| 30 | ->std::same_as<bool>; | ||
| 31 | {t.SetAffinity(std::declval<int32_t>(), std::declval<bool>())}; | ||
| 32 | {t.SetAll()}; | ||
| 33 | }; | ||
| 34 | |||
| 35 | template <typename T> | ||
| 36 | concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { | ||
| 37 | {typename T::QueueEntry()}; | ||
| 38 | {(typename T::QueueEntry()).Initialize()}; | ||
| 39 | {(typename T::QueueEntry()).SetPrev(std::addressof(t))}; | ||
| 40 | {(typename T::QueueEntry()).SetNext(std::addressof(t))}; | ||
| 41 | { (typename T::QueueEntry()).GetNext() } | ||
| 42 | ->std::same_as<T*>; | ||
| 43 | { (typename T::QueueEntry()).GetPrev() } | ||
| 44 | ->std::same_as<T*>; | ||
| 45 | { t.GetPriorityQueueEntry(std::declval<s32>()) } | ||
| 46 | ->std::same_as<typename T::QueueEntry&>; | ||
| 47 | |||
| 48 | {t.GetAffinityMask()}; | ||
| 49 | { typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() } | ||
| 50 | ->KPriorityQueueAffinityMask; | ||
| 51 | |||
| 52 | { t.GetActiveCore() } | ||
| 53 | ->Common::ConvertibleTo<s32>; | ||
| 54 | { t.GetPriority() } | ||
| 55 | ->Common::ConvertibleTo<s32>; | ||
| 56 | }; | ||
| 57 | |||
| 58 | template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority> | ||
| 59 | requires KPriorityQueueMember<Member> class KPriorityQueue { | ||
| 60 | public: | ||
| 61 | using AffinityMaskType = typename std::remove_cv_t< | ||
| 62 | typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>; | ||
| 63 | |||
| 64 | static_assert(LowestPriority >= 0); | ||
| 65 | static_assert(HighestPriority >= 0); | ||
| 66 | static_assert(LowestPriority >= HighestPriority); | ||
| 67 | static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1; | ||
| 68 | static constexpr size_t NumCores = _NumCores; | ||
| 69 | |||
| 70 | static constexpr bool IsValidCore(s32 core) { | ||
| 71 | return 0 <= core && core < static_cast<s32>(NumCores); | ||
| 72 | } | ||
| 73 | |||
| 74 | static constexpr bool IsValidPriority(s32 priority) { | ||
| 75 | return HighestPriority <= priority && priority <= LowestPriority + 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | private: | ||
| 79 | using Entry = typename Member::QueueEntry; | ||
| 80 | |||
| 81 | public: | ||
| 82 | class KPerCoreQueue { | ||
| 83 | private: | ||
| 84 | std::array<Entry, NumCores> root{}; | ||
| 85 | |||
| 86 | public: | ||
| 87 | constexpr KPerCoreQueue() { | ||
| 88 | for (auto& per_core_root : root) { | ||
| 89 | per_core_root.Initialize(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | constexpr bool PushBack(s32 core, Member* member) { | ||
| 94 | // Get the entry associated with the member. | ||
| 95 | Entry& member_entry = member->GetPriorityQueueEntry(core); | ||
| 96 | |||
| 97 | // Get the entry associated with the end of the queue. | ||
| 98 | Member* tail = this->root[core].GetPrev(); | ||
| 99 | Entry& tail_entry = | ||
| 100 | (tail != nullptr) ? tail->GetPriorityQueueEntry(core) : this->root[core]; | ||
| 101 | |||
| 102 | // Link the entries. | ||
| 103 | member_entry.SetPrev(tail); | ||
| 104 | member_entry.SetNext(nullptr); | ||
| 105 | tail_entry.SetNext(member); | ||
| 106 | this->root[core].SetPrev(member); | ||
| 107 | |||
| 108 | return tail == nullptr; | ||
| 109 | } | ||
| 110 | |||
| 111 | constexpr bool PushFront(s32 core, Member* member) { | ||
| 112 | // Get the entry associated with the member. | ||
| 113 | Entry& member_entry = member->GetPriorityQueueEntry(core); | ||
| 114 | |||
| 115 | // Get the entry associated with the front of the queue. | ||
| 116 | Member* head = this->root[core].GetNext(); | ||
| 117 | Entry& head_entry = | ||
| 118 | (head != nullptr) ? head->GetPriorityQueueEntry(core) : this->root[core]; | ||
| 119 | |||
| 120 | // Link the entries. | ||
| 121 | member_entry.SetPrev(nullptr); | ||
| 122 | member_entry.SetNext(head); | ||
| 123 | head_entry.SetPrev(member); | ||
| 124 | this->root[core].SetNext(member); | ||
| 125 | |||
| 126 | return (head == nullptr); | ||
| 127 | } | ||
| 128 | |||
| 129 | constexpr bool Remove(s32 core, Member* member) { | ||
| 130 | // Get the entry associated with the member. | ||
| 131 | Entry& member_entry = member->GetPriorityQueueEntry(core); | ||
| 132 | |||
| 133 | // Get the entries associated with next and prev. | ||
| 134 | Member* prev = member_entry.GetPrev(); | ||
| 135 | Member* next = member_entry.GetNext(); | ||
| 136 | Entry& prev_entry = | ||
| 137 | (prev != nullptr) ? prev->GetPriorityQueueEntry(core) : this->root[core]; | ||
| 138 | Entry& next_entry = | ||
| 139 | (next != nullptr) ? next->GetPriorityQueueEntry(core) : this->root[core]; | ||
| 140 | |||
| 141 | // Unlink. | ||
| 142 | prev_entry.SetNext(next); | ||
| 143 | next_entry.SetPrev(prev); | ||
| 144 | |||
| 145 | return (this->GetFront(core) == nullptr); | ||
| 146 | } | ||
| 147 | |||
| 148 | constexpr Member* GetFront(s32 core) const { | ||
| 149 | return this->root[core].GetNext(); | ||
| 150 | } | ||
| 151 | }; | ||
| 152 | |||
| 153 | class KPriorityQueueImpl { | ||
| 154 | public: | ||
| 155 | constexpr KPriorityQueueImpl() = default; | ||
| 156 | |||
| 157 | constexpr void PushBack(s32 priority, s32 core, Member* member) { | ||
| 158 | ASSERT(IsValidCore(core)); | ||
| 159 | ASSERT(IsValidPriority(priority)); | ||
| 160 | |||
| 161 | if (priority > LowestPriority) { | ||
| 162 | return; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (this->queues[priority].PushBack(core, member)) { | ||
| 166 | this->available_priorities[core].SetBit(priority); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | constexpr void PushFront(s32 priority, s32 core, Member* member) { | ||
| 171 | ASSERT(IsValidCore(core)); | ||
| 172 | ASSERT(IsValidPriority(priority)); | ||
| 173 | |||
| 174 | if (priority > LowestPriority) { | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | |||
| 178 | if (this->queues[priority].PushFront(core, member)) { | ||
| 179 | this->available_priorities[core].SetBit(priority); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | constexpr void Remove(s32 priority, s32 core, Member* member) { | ||
| 184 | ASSERT(IsValidCore(core)); | ||
| 185 | ASSERT(IsValidPriority(priority)); | ||
| 186 | |||
| 187 | if (priority > LowestPriority) { | ||
| 188 | return; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (this->queues[priority].Remove(core, member)) { | ||
| 192 | this->available_priorities[core].ClearBit(priority); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | constexpr Member* GetFront(s32 core) const { | ||
| 197 | ASSERT(IsValidCore(core)); | ||
| 198 | |||
| 199 | const s32 priority = | ||
| 200 | static_cast<s32>(this->available_priorities[core].CountLeadingZero()); | ||
| 201 | if (priority <= LowestPriority) { | ||
| 202 | return this->queues[priority].GetFront(core); | ||
| 203 | } else { | ||
| 204 | return nullptr; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | constexpr Member* GetFront(s32 priority, s32 core) const { | ||
| 209 | ASSERT(IsValidCore(core)); | ||
| 210 | ASSERT(IsValidPriority(priority)); | ||
| 211 | |||
| 212 | if (priority <= LowestPriority) { | ||
| 213 | return this->queues[priority].GetFront(core); | ||
| 214 | } else { | ||
| 215 | return nullptr; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | constexpr Member* GetNext(s32 core, const Member* member) const { | ||
| 220 | ASSERT(IsValidCore(core)); | ||
| 221 | |||
| 222 | Member* next = member->GetPriorityQueueEntry(core).GetNext(); | ||
| 223 | if (next == nullptr) { | ||
| 224 | const s32 priority = static_cast<s32>( | ||
| 225 | this->available_priorities[core].GetNextSet(member->GetPriority())); | ||
| 226 | if (priority <= LowestPriority) { | ||
| 227 | next = this->queues[priority].GetFront(core); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | return next; | ||
| 231 | } | ||
| 232 | |||
| 233 | constexpr void MoveToFront(s32 priority, s32 core, Member* member) { | ||
| 234 | ASSERT(IsValidCore(core)); | ||
| 235 | ASSERT(IsValidPriority(priority)); | ||
| 236 | |||
| 237 | if (priority <= LowestPriority) { | ||
| 238 | this->queues[priority].Remove(core, member); | ||
| 239 | this->queues[priority].PushFront(core, member); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | constexpr Member* MoveToBack(s32 priority, s32 core, Member* member) { | ||
| 244 | ASSERT(IsValidCore(core)); | ||
| 245 | ASSERT(IsValidPriority(priority)); | ||
| 246 | |||
| 247 | if (priority <= LowestPriority) { | ||
| 248 | this->queues[priority].Remove(core, member); | ||
| 249 | this->queues[priority].PushBack(core, member); | ||
| 250 | return this->queues[priority].GetFront(core); | ||
| 251 | } else { | ||
| 252 | return nullptr; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | private: | ||
| 257 | std::array<KPerCoreQueue, NumPriority> queues{}; | ||
| 258 | std::array<Common::BitSet64<NumPriority>, NumCores> available_priorities{}; | ||
| 259 | }; | ||
| 260 | |||
| 261 | private: | ||
| 262 | KPriorityQueueImpl scheduled_queue; | ||
| 263 | KPriorityQueueImpl suggested_queue; | ||
| 264 | |||
| 265 | private: | ||
| 266 | constexpr void ClearAffinityBit(u64& affinity, s32 core) { | ||
| 267 | affinity &= ~(u64(1) << core); | ||
| 268 | } | ||
| 269 | |||
| 270 | constexpr s32 GetNextCore(u64& affinity) { | ||
| 271 | const s32 core = Common::CountTrailingZeroes64(affinity); | ||
| 272 | ClearAffinityBit(affinity, core); | ||
| 273 | return core; | ||
| 274 | } | ||
| 275 | |||
| 276 | constexpr void PushBack(s32 priority, Member* member) { | ||
| 277 | ASSERT(IsValidPriority(priority)); | ||
| 278 | |||
| 279 | // Push onto the scheduled queue for its core, if we can. | ||
| 280 | u64 affinity = member->GetAffinityMask().GetAffinityMask(); | ||
| 281 | if (const s32 core = member->GetActiveCore(); core >= 0) { | ||
| 282 | this->scheduled_queue.PushBack(priority, core, member); | ||
| 283 | ClearAffinityBit(affinity, core); | ||
| 284 | } | ||
| 285 | |||
| 286 | // And suggest the thread for all other cores. | ||
| 287 | while (affinity) { | ||
| 288 | this->suggested_queue.PushBack(priority, GetNextCore(affinity), member); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | constexpr void PushFront(s32 priority, Member* member) { | ||
| 293 | ASSERT(IsValidPriority(priority)); | ||
| 294 | |||
| 295 | // Push onto the scheduled queue for its core, if we can. | ||
| 296 | u64 affinity = member->GetAffinityMask().GetAffinityMask(); | ||
| 297 | if (const s32 core = member->GetActiveCore(); core >= 0) { | ||
| 298 | this->scheduled_queue.PushFront(priority, core, member); | ||
| 299 | ClearAffinityBit(affinity, core); | ||
| 300 | } | ||
| 301 | |||
| 302 | // And suggest the thread for all other cores. | ||
| 303 | // Note: Nintendo pushes onto the back of the suggested queue, not the front. | ||
| 304 | while (affinity) { | ||
| 305 | this->suggested_queue.PushBack(priority, GetNextCore(affinity), member); | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | constexpr void Remove(s32 priority, Member* member) { | ||
| 310 | ASSERT(IsValidPriority(priority)); | ||
| 311 | |||
| 312 | // Remove from the scheduled queue for its core. | ||
| 313 | u64 affinity = member->GetAffinityMask().GetAffinityMask(); | ||
| 314 | if (const s32 core = member->GetActiveCore(); core >= 0) { | ||
| 315 | this->scheduled_queue.Remove(priority, core, member); | ||
| 316 | ClearAffinityBit(affinity, core); | ||
| 317 | } | ||
| 318 | |||
| 319 | // Remove from the suggested queue for all other cores. | ||
| 320 | while (affinity) { | ||
| 321 | this->suggested_queue.Remove(priority, GetNextCore(affinity), member); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | public: | ||
| 326 | constexpr KPriorityQueue() = default; | ||
| 327 | |||
| 328 | // Getters. | ||
| 329 | constexpr Member* GetScheduledFront(s32 core) const { | ||
| 330 | return this->scheduled_queue.GetFront(core); | ||
| 331 | } | ||
| 332 | |||
| 333 | constexpr Member* GetScheduledFront(s32 core, s32 priority) const { | ||
| 334 | return this->scheduled_queue.GetFront(priority, core); | ||
| 335 | } | ||
| 336 | |||
| 337 | constexpr Member* GetSuggestedFront(s32 core) const { | ||
| 338 | return this->suggested_queue.GetFront(core); | ||
| 339 | } | ||
| 340 | |||
| 341 | constexpr Member* GetSuggestedFront(s32 core, s32 priority) const { | ||
| 342 | return this->suggested_queue.GetFront(priority, core); | ||
| 343 | } | ||
| 344 | |||
| 345 | constexpr Member* GetScheduledNext(s32 core, const Member* member) const { | ||
| 346 | return this->scheduled_queue.GetNext(core, member); | ||
| 347 | } | ||
| 348 | |||
| 349 | constexpr Member* GetSuggestedNext(s32 core, const Member* member) const { | ||
| 350 | return this->suggested_queue.GetNext(core, member); | ||
| 351 | } | ||
| 352 | |||
| 353 | constexpr Member* GetSamePriorityNext(s32 core, const Member* member) const { | ||
| 354 | return member->GetPriorityQueueEntry(core).GetNext(); | ||
| 355 | } | ||
| 356 | |||
| 357 | // Mutators. | ||
| 358 | constexpr void PushBack(Member* member) { | ||
| 359 | this->PushBack(member->GetPriority(), member); | ||
| 360 | } | ||
| 361 | |||
| 362 | constexpr void Remove(Member* member) { | ||
| 363 | this->Remove(member->GetPriority(), member); | ||
| 364 | } | ||
| 365 | |||
| 366 | constexpr void MoveToScheduledFront(Member* member) { | ||
| 367 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); | ||
| 368 | } | ||
| 369 | |||
| 370 | constexpr Thread* MoveToScheduledBack(Member* member) { | ||
| 371 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), | ||
| 372 | member); | ||
| 373 | } | ||
| 374 | |||
| 375 | // First class fancy operations. | ||
| 376 | constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { | ||
| 377 | ASSERT(IsValidPriority(prev_priority)); | ||
| 378 | |||
| 379 | // Remove the member from the queues. | ||
| 380 | const s32 new_priority = member->GetPriority(); | ||
| 381 | this->Remove(prev_priority, member); | ||
| 382 | |||
| 383 | // And enqueue. If the member is running, we want to keep it running. | ||
| 384 | if (is_running) { | ||
| 385 | this->PushFront(new_priority, member); | ||
| 386 | } else { | ||
| 387 | this->PushBack(new_priority, member); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, | ||
| 392 | Member* member) { | ||
| 393 | // Get the new information. | ||
| 394 | const s32 priority = member->GetPriority(); | ||
| 395 | const AffinityMaskType& new_affinity = member->GetAffinityMask(); | ||
| 396 | const s32 new_core = member->GetActiveCore(); | ||
| 397 | |||
| 398 | // Remove the member from all queues it was in before. | ||
| 399 | for (s32 core = 0; core < static_cast<s32>(NumCores); core++) { | ||
| 400 | if (prev_affinity.GetAffinity(core)) { | ||
| 401 | if (core == prev_core) { | ||
| 402 | this->scheduled_queue.Remove(priority, core, member); | ||
| 403 | } else { | ||
| 404 | this->suggested_queue.Remove(priority, core, member); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | // And add the member to all queues it should be in now. | ||
| 410 | for (s32 core = 0; core < static_cast<s32>(NumCores); core++) { | ||
| 411 | if (new_affinity.GetAffinity(core)) { | ||
| 412 | if (core == new_core) { | ||
| 413 | this->scheduled_queue.PushBack(priority, core, member); | ||
| 414 | } else { | ||
| 415 | this->suggested_queue.PushBack(priority, core, member); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { | ||
| 422 | // Get the new information. | ||
| 423 | const s32 new_core = member->GetActiveCore(); | ||
| 424 | const s32 priority = member->GetPriority(); | ||
| 425 | |||
| 426 | // We don't need to do anything if the core is the same. | ||
| 427 | if (prev_core != new_core) { | ||
| 428 | // Remove from the scheduled queue for the previous core. | ||
| 429 | if (prev_core >= 0) { | ||
| 430 | this->scheduled_queue.Remove(priority, prev_core, member); | ||
| 431 | } | ||
| 432 | |||
| 433 | // Remove from the suggested queue and add to the scheduled queue for the new core. | ||
| 434 | if (new_core >= 0) { | ||
| 435 | this->suggested_queue.Remove(priority, new_core, member); | ||
| 436 | if (to_front) { | ||
| 437 | this->scheduled_queue.PushFront(priority, new_core, member); | ||
| 438 | } else { | ||
| 439 | this->scheduled_queue.PushBack(priority, new_core, member); | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | // Add to the suggested queue for the previous core. | ||
| 444 | if (prev_core >= 0) { | ||
| 445 | this->suggested_queue.PushBack(priority, prev_core, member); | ||
| 446 | } | ||
| 447 | } | ||
| 448 | } | ||
| 449 | }; | ||
| 450 | |||
| 451 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp new file mode 100644 index 000000000..c5fd82a6b --- /dev/null +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -0,0 +1,784 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/bit_util.h" | ||
| 10 | #include "common/fiber.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "core/arm/arm_interface.h" | ||
| 13 | #include "core/core.h" | ||
| 14 | #include "core/core_timing.h" | ||
| 15 | #include "core/cpu_manager.h" | ||
| 16 | #include "core/hle/kernel/k_scheduler.h" | ||
| 17 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 18 | #include "core/hle/kernel/kernel.h" | ||
| 19 | #include "core/hle/kernel/physical_core.h" | ||
| 20 | #include "core/hle/kernel/process.h" | ||
| 21 | #include "core/hle/kernel/thread.h" | ||
| 22 | #include "core/hle/kernel/time_manager.h" | ||
| 23 | |||
| 24 | namespace Kernel { | ||
| 25 | |||
| 26 | static void IncrementScheduledCount(Kernel::Thread* thread) { | ||
| 27 | if (auto process = thread->GetOwnerProcess(); process) { | ||
| 28 | process->IncrementScheduledCount(); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, | ||
| 33 | Core::EmuThreadHandle global_thread) { | ||
| 34 | u32 current_core = global_thread.host_handle; | ||
| 35 | bool must_context_switch = global_thread.guest_handle != InvalidHandle && | ||
| 36 | (current_core < Core::Hardware::NUM_CPU_CORES); | ||
| 37 | |||
| 38 | while (cores_pending_reschedule != 0) { | ||
| 39 | u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule); | ||
| 40 | ASSERT(core < Core::Hardware::NUM_CPU_CORES); | ||
| 41 | if (!must_context_switch || core != current_core) { | ||
| 42 | auto& phys_core = kernel.PhysicalCore(core); | ||
| 43 | phys_core.Interrupt(); | ||
| 44 | } else { | ||
| 45 | must_context_switch = true; | ||
| 46 | } | ||
| 47 | cores_pending_reschedule &= ~(1ULL << core); | ||
| 48 | } | ||
| 49 | if (must_context_switch) { | ||
| 50 | auto core_scheduler = kernel.CurrentScheduler(); | ||
| 51 | kernel.ExitSVCProfile(); | ||
| 52 | core_scheduler->RescheduleCurrentCore(); | ||
| 53 | kernel.EnterSVCProfile(); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) { | ||
| 58 | std::scoped_lock lock{guard}; | ||
| 59 | if (Thread* prev_highest_thread = this->state.highest_priority_thread; | ||
| 60 | prev_highest_thread != highest_thread) { | ||
| 61 | if (prev_highest_thread != nullptr) { | ||
| 62 | IncrementScheduledCount(prev_highest_thread); | ||
| 63 | prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks()); | ||
| 64 | } | ||
| 65 | if (this->state.should_count_idle) { | ||
| 66 | if (highest_thread != nullptr) { | ||
| 67 | // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { | ||
| 68 | // process->SetRunningThread(this->core_id, highest_thread, | ||
| 69 | // this->state.idle_count); | ||
| 70 | //} | ||
| 71 | } else { | ||
| 72 | this->state.idle_count++; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | this->state.highest_priority_thread = highest_thread; | ||
| 77 | this->state.needs_scheduling = true; | ||
| 78 | return (1ULL << this->core_id); | ||
| 79 | } else { | ||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { | ||
| 85 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 86 | |||
| 87 | // Clear that we need to update. | ||
| 88 | ClearSchedulerUpdateNeeded(kernel); | ||
| 89 | |||
| 90 | u64 cores_needing_scheduling = 0, idle_cores = 0; | ||
| 91 | Thread* top_threads[Core::Hardware::NUM_CPU_CORES]; | ||
| 92 | auto& priority_queue = GetPriorityQueue(kernel); | ||
| 93 | |||
| 94 | /// We want to go over all cores, finding the highest priority thread and determining if | ||
| 95 | /// scheduling is needed for that core. | ||
| 96 | for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||
| 97 | Thread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id)); | ||
| 98 | if (top_thread != nullptr) { | ||
| 99 | // If the thread has no waiters, we need to check if the process has a thread pinned. | ||
| 100 | // TODO(bunnei): Implement thread pinning | ||
| 101 | } else { | ||
| 102 | idle_cores |= (1ULL << core_id); | ||
| 103 | } | ||
| 104 | |||
| 105 | top_threads[core_id] = top_thread; | ||
| 106 | cores_needing_scheduling |= | ||
| 107 | kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]); | ||
| 108 | } | ||
| 109 | |||
| 110 | // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. | ||
| 111 | while (idle_cores != 0) { | ||
| 112 | u32 core_id = Common::CountTrailingZeroes64(idle_cores); | ||
| 113 | if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { | ||
| 114 | s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; | ||
| 115 | size_t num_candidates = 0; | ||
| 116 | |||
| 117 | // While we have a suggested thread, try to migrate it! | ||
| 118 | while (suggested != nullptr) { | ||
| 119 | // Check if the suggested thread is the top thread on its core. | ||
| 120 | const s32 suggested_core = suggested->GetActiveCore(); | ||
| 121 | if (Thread* top_thread = | ||
| 122 | (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; | ||
| 123 | top_thread != suggested) { | ||
| 124 | // Make sure we're not dealing with threads too high priority for migration. | ||
| 125 | if (top_thread != nullptr && | ||
| 126 | top_thread->GetPriority() < HighestCoreMigrationAllowedPriority) { | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | |||
| 130 | // The suggested thread isn't bound to its core, so we can migrate it! | ||
| 131 | suggested->SetActiveCore(core_id); | ||
| 132 | priority_queue.ChangeCore(suggested_core, suggested); | ||
| 133 | |||
| 134 | top_threads[core_id] = suggested; | ||
| 135 | cores_needing_scheduling |= | ||
| 136 | kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]); | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | |||
| 140 | // Note this core as a candidate for migration. | ||
| 141 | ASSERT(num_candidates < Core::Hardware::NUM_CPU_CORES); | ||
| 142 | migration_candidates[num_candidates++] = suggested_core; | ||
| 143 | suggested = priority_queue.GetSuggestedNext(core_id, suggested); | ||
| 144 | } | ||
| 145 | |||
| 146 | // If suggested is nullptr, we failed to migrate a specific thread. So let's try all our | ||
| 147 | // candidate cores' top threads. | ||
| 148 | if (suggested == nullptr) { | ||
| 149 | for (size_t i = 0; i < num_candidates; i++) { | ||
| 150 | // Check if there's some other thread that can run on the candidate core. | ||
| 151 | const s32 candidate_core = migration_candidates[i]; | ||
| 152 | suggested = top_threads[candidate_core]; | ||
| 153 | if (Thread* next_on_candidate_core = | ||
| 154 | priority_queue.GetScheduledNext(candidate_core, suggested); | ||
| 155 | next_on_candidate_core != nullptr) { | ||
| 156 | // The candidate core can run some other thread! We'll migrate its current | ||
| 157 | // top thread to us. | ||
| 158 | top_threads[candidate_core] = next_on_candidate_core; | ||
| 159 | cores_needing_scheduling |= | ||
| 160 | kernel.Scheduler(candidate_core) | ||
| 161 | .UpdateHighestPriorityThread(top_threads[candidate_core]); | ||
| 162 | |||
| 163 | // Perform the migration. | ||
| 164 | suggested->SetActiveCore(core_id); | ||
| 165 | priority_queue.ChangeCore(candidate_core, suggested); | ||
| 166 | |||
| 167 | top_threads[core_id] = suggested; | ||
| 168 | cores_needing_scheduling |= | ||
| 169 | kernel.Scheduler(core_id).UpdateHighestPriorityThread( | ||
| 170 | top_threads[core_id]); | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | idle_cores &= ~(1ULL << core_id); | ||
| 178 | } | ||
| 179 | |||
| 180 | return cores_needing_scheduling; | ||
| 181 | } | ||
| 182 | |||
| 183 | void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, u32 old_state) { | ||
| 184 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 185 | |||
| 186 | // Check if the state has changed, because if it hasn't there's nothing to do. | ||
| 187 | const auto cur_state = thread->scheduling_state; | ||
| 188 | if (cur_state == old_state) { | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | |||
| 192 | // Update the priority queues. | ||
| 193 | if (old_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 194 | // If we were previously runnable, then we're not runnable now, and we should remove. | ||
| 195 | GetPriorityQueue(kernel).Remove(thread); | ||
| 196 | IncrementScheduledCount(thread); | ||
| 197 | SetSchedulerUpdateNeeded(kernel); | ||
| 198 | } else if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 199 | // If we're now runnable, then we weren't previously, and we should add. | ||
| 200 | GetPriorityQueue(kernel).PushBack(thread); | ||
| 201 | IncrementScheduledCount(thread); | ||
| 202 | SetSchedulerUpdateNeeded(kernel); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, Thread* current_thread, | ||
| 207 | u32 old_priority) { | ||
| 208 | |||
| 209 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 210 | |||
| 211 | // If the thread is runnable, we want to change its priority in the queue. | ||
| 212 | if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 213 | GetPriorityQueue(kernel).ChangePriority( | ||
| 214 | old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread); | ||
| 215 | IncrementScheduledCount(thread); | ||
| 216 | SetSchedulerUpdateNeeded(kernel); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, | ||
| 221 | const KAffinityMask& old_affinity, s32 old_core) { | ||
| 222 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 223 | |||
| 224 | // If the thread is runnable, we want to change its affinity in the queue. | ||
| 225 | if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 226 | GetPriorityQueue(kernel).ChangeAffinityMask(old_core, old_affinity, thread); | ||
| 227 | IncrementScheduledCount(thread); | ||
| 228 | SetSchedulerUpdateNeeded(kernel); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { | ||
| 233 | ASSERT(system.GlobalSchedulerContext().IsLocked()); | ||
| 234 | |||
| 235 | // Get a reference to the priority queue. | ||
| 236 | auto& kernel = system.Kernel(); | ||
| 237 | auto& priority_queue = GetPriorityQueue(kernel); | ||
| 238 | |||
| 239 | // Rotate the front of the queue to the end. | ||
| 240 | Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority); | ||
| 241 | Thread* next_thread = nullptr; | ||
| 242 | if (top_thread != nullptr) { | ||
| 243 | next_thread = priority_queue.MoveToScheduledBack(top_thread); | ||
| 244 | if (next_thread != top_thread) { | ||
| 245 | IncrementScheduledCount(top_thread); | ||
| 246 | IncrementScheduledCount(next_thread); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | // While we have a suggested thread, try to migrate it! | ||
| 251 | { | ||
| 252 | Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority); | ||
| 253 | while (suggested != nullptr) { | ||
| 254 | // Check if the suggested thread is the top thread on its core. | ||
| 255 | const s32 suggested_core = suggested->GetActiveCore(); | ||
| 256 | if (Thread* top_on_suggested_core = | ||
| 257 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | ||
| 258 | : nullptr; | ||
| 259 | top_on_suggested_core != suggested) { | ||
| 260 | // If the next thread is a new thread that has been waiting longer than our | ||
| 261 | // suggestion, we prefer it to our suggestion. | ||
| 262 | if (top_thread != next_thread && next_thread != nullptr && | ||
| 263 | next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick()) { | ||
| 264 | suggested = nullptr; | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | |||
| 268 | // If we're allowed to do a migration, do one. | ||
| 269 | // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the suggestion | ||
| 270 | // to the front of the queue. | ||
| 271 | if (top_on_suggested_core == nullptr || | ||
| 272 | top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { | ||
| 273 | suggested->SetActiveCore(core_id); | ||
| 274 | priority_queue.ChangeCore(suggested_core, suggested, true); | ||
| 275 | IncrementScheduledCount(suggested); | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | // Get the next suggestion. | ||
| 281 | suggested = priority_queue.GetSamePriorityNext(core_id, suggested); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | // Now that we might have migrated a thread with the same priority, check if we can do better. | ||
| 286 | |||
| 287 | { | ||
| 288 | Thread* best_thread = priority_queue.GetScheduledFront(core_id); | ||
| 289 | if (best_thread == GetCurrentThread()) { | ||
| 290 | best_thread = priority_queue.GetScheduledNext(core_id, best_thread); | ||
| 291 | } | ||
| 292 | |||
| 293 | // If the best thread we can choose has a priority the same or worse than ours, try to | ||
| 294 | // migrate a higher priority thread. | ||
| 295 | if (best_thread != nullptr && best_thread->GetPriority() >= static_cast<u32>(priority)) { | ||
| 296 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | ||
| 297 | while (suggested != nullptr) { | ||
| 298 | // If the suggestion's priority is the same as ours, don't bother. | ||
| 299 | if (suggested->GetPriority() >= best_thread->GetPriority()) { | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | |||
| 303 | // Check if the suggested thread is the top thread on its core. | ||
| 304 | const s32 suggested_core = suggested->GetActiveCore(); | ||
| 305 | if (Thread* top_on_suggested_core = | ||
| 306 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | ||
| 307 | : nullptr; | ||
| 308 | top_on_suggested_core != suggested) { | ||
| 309 | // If we're allowed to do a migration, do one. | ||
| 310 | // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the | ||
| 311 | // suggestion to the front of the queue. | ||
| 312 | if (top_on_suggested_core == nullptr || | ||
| 313 | top_on_suggested_core->GetPriority() >= | ||
| 314 | HighestCoreMigrationAllowedPriority) { | ||
| 315 | suggested->SetActiveCore(core_id); | ||
| 316 | priority_queue.ChangeCore(suggested_core, suggested, true); | ||
| 317 | IncrementScheduledCount(suggested); | ||
| 318 | break; | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | // Get the next suggestion. | ||
| 323 | suggested = priority_queue.GetSuggestedNext(core_id, suggested); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | // After a rotation, we need a scheduler update. | ||
| 329 | SetSchedulerUpdateNeeded(kernel); | ||
| 330 | } | ||
| 331 | |||
| 332 | bool KScheduler::CanSchedule(KernelCore& kernel) { | ||
| 333 | return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; | ||
| 334 | } | ||
| 335 | |||
| 336 | bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { | ||
| 337 | return kernel.GlobalSchedulerContext().scheduler_update_needed.load(std::memory_order_acquire); | ||
| 338 | } | ||
| 339 | |||
| 340 | void KScheduler::SetSchedulerUpdateNeeded(KernelCore& kernel) { | ||
| 341 | kernel.GlobalSchedulerContext().scheduler_update_needed.store(true, std::memory_order_release); | ||
| 342 | } | ||
| 343 | |||
| 344 | void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) { | ||
| 345 | kernel.GlobalSchedulerContext().scheduler_update_needed.store(false, std::memory_order_release); | ||
| 346 | } | ||
| 347 | |||
| 348 | void KScheduler::DisableScheduling(KernelCore& kernel) { | ||
| 349 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { | ||
| 350 | ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0); | ||
| 351 | scheduler->GetCurrentThread()->DisableDispatch(); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, | ||
| 356 | Core::EmuThreadHandle global_thread) { | ||
| 357 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { | ||
| 358 | scheduler->GetCurrentThread()->EnableDispatch(); | ||
| 359 | } | ||
| 360 | RescheduleCores(kernel, cores_needing_scheduling, global_thread); | ||
| 361 | } | ||
| 362 | |||
| 363 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | ||
| 364 | if (IsSchedulerUpdateNeeded(kernel)) { | ||
| 365 | return UpdateHighestPriorityThreadsImpl(kernel); | ||
| 366 | } else { | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) { | ||
| 372 | return kernel.GlobalSchedulerContext().priority_queue; | ||
| 373 | } | ||
| 374 | |||
| 375 | void KScheduler::YieldWithoutCoreMigration() { | ||
| 376 | auto& kernel = system.Kernel(); | ||
| 377 | |||
| 378 | // Validate preconditions. | ||
| 379 | ASSERT(CanSchedule(kernel)); | ||
| 380 | ASSERT(kernel.CurrentProcess() != nullptr); | ||
| 381 | |||
| 382 | // Get the current thread and process. | ||
| 383 | Thread& cur_thread = *GetCurrentThread(); | ||
| 384 | Process& cur_process = *kernel.CurrentProcess(); | ||
| 385 | |||
| 386 | // If the thread's yield count matches, there's nothing for us to do. | ||
| 387 | if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { | ||
| 388 | return; | ||
| 389 | } | ||
| 390 | |||
| 391 | // Get a reference to the priority queue. | ||
| 392 | auto& priority_queue = GetPriorityQueue(kernel); | ||
| 393 | |||
| 394 | // Perform the yield. | ||
| 395 | { | ||
| 396 | KScopedSchedulerLock lock(kernel); | ||
| 397 | |||
| 398 | const auto cur_state = cur_thread.scheduling_state; | ||
| 399 | if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 400 | // Put the current thread at the back of the queue. | ||
| 401 | Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); | ||
| 402 | IncrementScheduledCount(std::addressof(cur_thread)); | ||
| 403 | |||
| 404 | // If the next thread is different, we have an update to perform. | ||
| 405 | if (next_thread != std::addressof(cur_thread)) { | ||
| 406 | SetSchedulerUpdateNeeded(kernel); | ||
| 407 | } else { | ||
| 408 | // Otherwise, set the thread's yield count so that we won't waste work until the | ||
| 409 | // process is scheduled again. | ||
| 410 | cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | void KScheduler::YieldWithCoreMigration() { | ||
| 417 | auto& kernel = system.Kernel(); | ||
| 418 | |||
| 419 | // Validate preconditions. | ||
| 420 | ASSERT(CanSchedule(kernel)); | ||
| 421 | ASSERT(kernel.CurrentProcess() != nullptr); | ||
| 422 | |||
| 423 | // Get the current thread and process. | ||
| 424 | Thread& cur_thread = *GetCurrentThread(); | ||
| 425 | Process& cur_process = *kernel.CurrentProcess(); | ||
| 426 | |||
| 427 | // If the thread's yield count matches, there's nothing for us to do. | ||
| 428 | if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { | ||
| 429 | return; | ||
| 430 | } | ||
| 431 | |||
| 432 | // Get a reference to the priority queue. | ||
| 433 | auto& priority_queue = GetPriorityQueue(kernel); | ||
| 434 | |||
| 435 | // Perform the yield. | ||
| 436 | { | ||
| 437 | KScopedSchedulerLock lock(kernel); | ||
| 438 | |||
| 439 | const auto cur_state = cur_thread.scheduling_state; | ||
| 440 | if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 441 | // Get the current active core. | ||
| 442 | const s32 core_id = cur_thread.GetActiveCore(); | ||
| 443 | |||
| 444 | // Put the current thread at the back of the queue. | ||
| 445 | Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); | ||
| 446 | IncrementScheduledCount(std::addressof(cur_thread)); | ||
| 447 | |||
| 448 | // While we have a suggested thread, try to migrate it! | ||
| 449 | bool recheck = false; | ||
| 450 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | ||
| 451 | while (suggested != nullptr) { | ||
| 452 | // Check if the suggested thread is the thread running on its core. | ||
| 453 | const s32 suggested_core = suggested->GetActiveCore(); | ||
| 454 | |||
| 455 | if (Thread* running_on_suggested_core = | ||
| 456 | (suggested_core >= 0) | ||
| 457 | ? kernel.Scheduler(suggested_core).state.highest_priority_thread | ||
| 458 | : nullptr; | ||
| 459 | running_on_suggested_core != suggested) { | ||
| 460 | // If the current thread's priority is higher than our suggestion's we prefer | ||
| 461 | // the next thread to the suggestion. We also prefer the next thread when the | ||
| 462 | // current thread's priority is equal to the suggestions, but the next thread | ||
| 463 | // has been waiting longer. | ||
| 464 | if ((suggested->GetPriority() > cur_thread.GetPriority()) || | ||
| 465 | (suggested->GetPriority() == cur_thread.GetPriority() && | ||
| 466 | next_thread != std::addressof(cur_thread) && | ||
| 467 | next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick())) { | ||
| 468 | suggested = nullptr; | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | |||
| 472 | // If we're allowed to do a migration, do one. | ||
| 473 | // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the | ||
| 474 | // suggestion to the front of the queue. | ||
| 475 | if (running_on_suggested_core == nullptr || | ||
| 476 | running_on_suggested_core->GetPriority() >= | ||
| 477 | HighestCoreMigrationAllowedPriority) { | ||
| 478 | suggested->SetActiveCore(core_id); | ||
| 479 | priority_queue.ChangeCore(suggested_core, suggested, true); | ||
| 480 | IncrementScheduledCount(suggested); | ||
| 481 | break; | ||
| 482 | } else { | ||
| 483 | // We couldn't perform a migration, but we should check again on a future | ||
| 484 | // yield. | ||
| 485 | recheck = true; | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | // Get the next suggestion. | ||
| 490 | suggested = priority_queue.GetSuggestedNext(core_id, suggested); | ||
| 491 | } | ||
| 492 | |||
| 493 | // If we still have a suggestion or the next thread is different, we have an update to | ||
| 494 | // perform. | ||
| 495 | if (suggested != nullptr || next_thread != std::addressof(cur_thread)) { | ||
| 496 | SetSchedulerUpdateNeeded(kernel); | ||
| 497 | } else if (!recheck) { | ||
| 498 | // Otherwise if we don't need to re-check, set the thread's yield count so that we | ||
| 499 | // won't waste work until the process is scheduled again. | ||
| 500 | cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | void KScheduler::YieldToAnyThread() { | ||
| 507 | auto& kernel = system.Kernel(); | ||
| 508 | |||
| 509 | // Validate preconditions. | ||
| 510 | ASSERT(CanSchedule(kernel)); | ||
| 511 | ASSERT(kernel.CurrentProcess() != nullptr); | ||
| 512 | |||
| 513 | // Get the current thread and process. | ||
| 514 | Thread& cur_thread = *GetCurrentThread(); | ||
| 515 | Process& cur_process = *kernel.CurrentProcess(); | ||
| 516 | |||
| 517 | // If the thread's yield count matches, there's nothing for us to do. | ||
| 518 | if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { | ||
| 519 | return; | ||
| 520 | } | ||
| 521 | |||
| 522 | // Get a reference to the priority queue. | ||
| 523 | auto& priority_queue = GetPriorityQueue(kernel); | ||
| 524 | |||
| 525 | // Perform the yield. | ||
| 526 | { | ||
| 527 | KScopedSchedulerLock lock(kernel); | ||
| 528 | |||
| 529 | const auto cur_state = cur_thread.scheduling_state; | ||
| 530 | if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 531 | // Get the current active core. | ||
| 532 | const s32 core_id = cur_thread.GetActiveCore(); | ||
| 533 | |||
| 534 | // Migrate the current thread to core -1. | ||
| 535 | cur_thread.SetActiveCore(-1); | ||
| 536 | priority_queue.ChangeCore(core_id, std::addressof(cur_thread)); | ||
| 537 | IncrementScheduledCount(std::addressof(cur_thread)); | ||
| 538 | |||
| 539 | // If there's nothing scheduled, we can try to perform a migration. | ||
| 540 | if (priority_queue.GetScheduledFront(core_id) == nullptr) { | ||
| 541 | // While we have a suggested thread, try to migrate it! | ||
| 542 | Thread* suggested = priority_queue.GetSuggestedFront(core_id); | ||
| 543 | while (suggested != nullptr) { | ||
| 544 | // Check if the suggested thread is the top thread on its core. | ||
| 545 | const s32 suggested_core = suggested->GetActiveCore(); | ||
| 546 | if (Thread* top_on_suggested_core = | ||
| 547 | (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) | ||
| 548 | : nullptr; | ||
| 549 | top_on_suggested_core != suggested) { | ||
| 550 | // If we're allowed to do a migration, do one. | ||
| 551 | if (top_on_suggested_core == nullptr || | ||
| 552 | top_on_suggested_core->GetPriority() >= | ||
| 553 | HighestCoreMigrationAllowedPriority) { | ||
| 554 | suggested->SetActiveCore(core_id); | ||
| 555 | priority_queue.ChangeCore(suggested_core, suggested); | ||
| 556 | IncrementScheduledCount(suggested); | ||
| 557 | } | ||
| 558 | |||
| 559 | // Regardless of whether we migrated, we had a candidate, so we're done. | ||
| 560 | break; | ||
| 561 | } | ||
| 562 | |||
| 563 | // Get the next suggestion. | ||
| 564 | suggested = priority_queue.GetSuggestedNext(core_id, suggested); | ||
| 565 | } | ||
| 566 | |||
| 567 | // If the suggestion is different from the current thread, we need to perform an | ||
| 568 | // update. | ||
| 569 | if (suggested != std::addressof(cur_thread)) { | ||
| 570 | SetSchedulerUpdateNeeded(kernel); | ||
| 571 | } else { | ||
| 572 | // Otherwise, set the thread's yield count so that we won't waste work until the | ||
| 573 | // process is scheduled again. | ||
| 574 | cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); | ||
| 575 | } | ||
| 576 | } else { | ||
| 577 | // Otherwise, we have an update to perform. | ||
| 578 | SetSchedulerUpdateNeeded(kernel); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | KScheduler::KScheduler(Core::System& system, std::size_t core_id) | ||
| 585 | : system(system), core_id(core_id) { | ||
| 586 | switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); | ||
| 587 | this->state.needs_scheduling = true; | ||
| 588 | this->state.interrupt_task_thread_runnable = false; | ||
| 589 | this->state.should_count_idle = false; | ||
| 590 | this->state.idle_count = 0; | ||
| 591 | this->state.idle_thread_stack = nullptr; | ||
| 592 | this->state.highest_priority_thread = nullptr; | ||
| 593 | } | ||
| 594 | |||
| 595 | KScheduler::~KScheduler() = default; | ||
| 596 | |||
| 597 | Thread* KScheduler::GetCurrentThread() const { | ||
| 598 | if (current_thread) { | ||
| 599 | return current_thread; | ||
| 600 | } | ||
| 601 | return idle_thread; | ||
| 602 | } | ||
| 603 | |||
| 604 | u64 KScheduler::GetLastContextSwitchTicks() const { | ||
| 605 | return last_context_switch_time; | ||
| 606 | } | ||
| 607 | |||
| 608 | void KScheduler::RescheduleCurrentCore() { | ||
| 609 | ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); | ||
| 610 | |||
| 611 | auto& phys_core = system.Kernel().PhysicalCore(core_id); | ||
| 612 | if (phys_core.IsInterrupted()) { | ||
| 613 | phys_core.ClearInterrupt(); | ||
| 614 | } | ||
| 615 | guard.lock(); | ||
| 616 | if (this->state.needs_scheduling) { | ||
| 617 | Schedule(); | ||
| 618 | } else { | ||
| 619 | guard.unlock(); | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | void KScheduler::OnThreadStart() { | ||
| 624 | SwitchContextStep2(); | ||
| 625 | } | ||
| 626 | |||
| 627 | void KScheduler::Unload(Thread* thread) { | ||
| 628 | if (thread) { | ||
| 629 | thread->SetIsRunning(false); | ||
| 630 | if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { | ||
| 631 | system.ArmInterface(core_id).ExceptionalExit(); | ||
| 632 | thread->SetContinuousOnSVC(false); | ||
| 633 | } | ||
| 634 | if (!thread->IsHLEThread() && !thread->HasExited()) { | ||
| 635 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | ||
| 636 | cpu_core.SaveContext(thread->GetContext32()); | ||
| 637 | cpu_core.SaveContext(thread->GetContext64()); | ||
| 638 | // Save the TPIDR_EL0 system register in case it was modified. | ||
| 639 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); | ||
| 640 | cpu_core.ClearExclusiveState(); | ||
| 641 | } | ||
| 642 | thread->context_guard.unlock(); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | |||
| 646 | void KScheduler::Reload(Thread* thread) { | ||
| 647 | if (thread) { | ||
| 648 | ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, | ||
| 649 | "Thread must be runnable."); | ||
| 650 | |||
| 651 | // Cancel any outstanding wakeup events for this thread | ||
| 652 | thread->SetIsRunning(true); | ||
| 653 | thread->SetWasRunning(false); | ||
| 654 | |||
| 655 | auto* const thread_owner_process = thread->GetOwnerProcess(); | ||
| 656 | if (thread_owner_process != nullptr) { | ||
| 657 | system.Kernel().MakeCurrentProcess(thread_owner_process); | ||
| 658 | } | ||
| 659 | if (!thread->IsHLEThread()) { | ||
| 660 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | ||
| 661 | cpu_core.LoadContext(thread->GetContext32()); | ||
| 662 | cpu_core.LoadContext(thread->GetContext64()); | ||
| 663 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); | ||
| 664 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); | ||
| 665 | cpu_core.ClearExclusiveState(); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | void KScheduler::SwitchContextStep2() { | ||
| 671 | // Load context of new thread | ||
| 672 | Reload(current_thread); | ||
| 673 | |||
| 674 | RescheduleCurrentCore(); | ||
| 675 | } | ||
| 676 | |||
| 677 | void KScheduler::ScheduleImpl() { | ||
| 678 | Thread* previous_thread = current_thread; | ||
| 679 | current_thread = state.highest_priority_thread; | ||
| 680 | |||
| 681 | this->state.needs_scheduling = false; | ||
| 682 | |||
| 683 | if (current_thread == previous_thread) { | ||
| 684 | guard.unlock(); | ||
| 685 | return; | ||
| 686 | } | ||
| 687 | |||
| 688 | Process* const previous_process = system.Kernel().CurrentProcess(); | ||
| 689 | |||
| 690 | UpdateLastContextSwitchTime(previous_thread, previous_process); | ||
| 691 | |||
| 692 | // Save context for previous thread | ||
| 693 | Unload(previous_thread); | ||
| 694 | |||
| 695 | std::shared_ptr<Common::Fiber>* old_context; | ||
| 696 | if (previous_thread != nullptr) { | ||
| 697 | old_context = &previous_thread->GetHostContext(); | ||
| 698 | } else { | ||
| 699 | old_context = &idle_thread->GetHostContext(); | ||
| 700 | } | ||
| 701 | guard.unlock(); | ||
| 702 | |||
| 703 | Common::Fiber::YieldTo(*old_context, switch_fiber); | ||
| 704 | /// When a thread wakes up, the scheduler may have changed to other in another core. | ||
| 705 | auto& next_scheduler = *system.Kernel().CurrentScheduler(); | ||
| 706 | next_scheduler.SwitchContextStep2(); | ||
| 707 | } | ||
| 708 | |||
| 709 | void KScheduler::OnSwitch(void* this_scheduler) { | ||
| 710 | KScheduler* sched = static_cast<KScheduler*>(this_scheduler); | ||
| 711 | sched->SwitchToCurrent(); | ||
| 712 | } | ||
| 713 | |||
| 714 | void KScheduler::SwitchToCurrent() { | ||
| 715 | while (true) { | ||
| 716 | { | ||
| 717 | std::scoped_lock lock{guard}; | ||
| 718 | current_thread = state.highest_priority_thread; | ||
| 719 | this->state.needs_scheduling = false; | ||
| 720 | } | ||
| 721 | const auto is_switch_pending = [this] { | ||
| 722 | std::scoped_lock lock{guard}; | ||
| 723 | return state.needs_scheduling.load(std::memory_order_relaxed); | ||
| 724 | }; | ||
| 725 | do { | ||
| 726 | if (current_thread != nullptr && !current_thread->IsHLEThread()) { | ||
| 727 | current_thread->context_guard.lock(); | ||
| 728 | if (!current_thread->IsRunnable()) { | ||
| 729 | current_thread->context_guard.unlock(); | ||
| 730 | break; | ||
| 731 | } | ||
| 732 | if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) { | ||
| 733 | current_thread->context_guard.unlock(); | ||
| 734 | break; | ||
| 735 | } | ||
| 736 | } | ||
| 737 | std::shared_ptr<Common::Fiber>* next_context; | ||
| 738 | if (current_thread != nullptr) { | ||
| 739 | next_context = ¤t_thread->GetHostContext(); | ||
| 740 | } else { | ||
| 741 | next_context = &idle_thread->GetHostContext(); | ||
| 742 | } | ||
| 743 | Common::Fiber::YieldTo(switch_fiber, *next_context); | ||
| 744 | } while (!is_switch_pending()); | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | ||
| 749 | const u64 prev_switch_ticks = last_context_switch_time; | ||
| 750 | const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 751 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; | ||
| 752 | |||
| 753 | if (thread != nullptr) { | ||
| 754 | thread->UpdateCPUTimeTicks(update_ticks); | ||
| 755 | } | ||
| 756 | |||
| 757 | if (process != nullptr) { | ||
| 758 | process->UpdateCPUTimeTicks(update_ticks); | ||
| 759 | } | ||
| 760 | |||
| 761 | last_context_switch_time = most_recent_switch_ticks; | ||
| 762 | } | ||
| 763 | |||
| 764 | void KScheduler::Initialize() { | ||
| 765 | std::string name = "Idle Thread Id:" + std::to_string(core_id); | ||
| 766 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); | ||
| 767 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 768 | ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); | ||
| 769 | auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, | ||
| 770 | nullptr, std::move(init_func), init_func_parameter); | ||
| 771 | idle_thread = thread_res.Unwrap().get(); | ||
| 772 | |||
| 773 | { | ||
| 774 | KScopedSchedulerLock lock{system.Kernel()}; | ||
| 775 | idle_thread->SetStatus(ThreadStatus::Ready); | ||
| 776 | } | ||
| 777 | } | ||
| 778 | |||
| 779 | KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) | ||
| 780 | : KScopedLock(kernel.GlobalSchedulerContext().SchedulerLock()) {} | ||
| 781 | |||
| 782 | KScopedSchedulerLock::~KScopedSchedulerLock() = default; | ||
| 783 | |||
| 784 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h new file mode 100644 index 000000000..e84abc84c --- /dev/null +++ b/src/core/hle/kernel/k_scheduler.h | |||
| @@ -0,0 +1,201 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include <atomic> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/spin_lock.h" | ||
| 14 | #include "core/hle/kernel/global_scheduler_context.h" | ||
| 15 | #include "core/hle/kernel/k_priority_queue.h" | ||
| 16 | #include "core/hle/kernel/k_scheduler_lock.h" | ||
| 17 | #include "core/hle/kernel/k_scoped_lock.h" | ||
| 18 | |||
| 19 | namespace Common { | ||
| 20 | class Fiber; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Core { | ||
| 24 | class System; | ||
| 25 | } | ||
| 26 | |||
| 27 | namespace Kernel { | ||
| 28 | |||
| 29 | class KernelCore; | ||
| 30 | class Process; | ||
| 31 | class SchedulerLock; | ||
| 32 | class Thread; | ||
| 33 | |||
| 34 | class KScheduler final { | ||
| 35 | public: | ||
| 36 | explicit KScheduler(Core::System& system, std::size_t core_id); | ||
| 37 | ~KScheduler(); | ||
| 38 | |||
| 39 | /// Reschedules to the next available thread (call after current thread is suspended) | ||
| 40 | void RescheduleCurrentCore(); | ||
| 41 | |||
| 42 | /// Reschedules cores pending reschedule, to be called on EnableScheduling. | ||
| 43 | static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, | ||
| 44 | Core::EmuThreadHandle global_thread); | ||
| 45 | |||
| 46 | /// The next two are for SingleCore Only. | ||
| 47 | /// Unload current thread before preempting core. | ||
| 48 | void Unload(Thread* thread); | ||
| 49 | |||
| 50 | /// Reload current thread after core preemption. | ||
| 51 | void Reload(Thread* thread); | ||
| 52 | |||
| 53 | /// Gets the current running thread | ||
| 54 | [[nodiscard]] Thread* GetCurrentThread() const; | ||
| 55 | |||
| 56 | /// Gets the timestamp for the last context switch in ticks. | ||
| 57 | [[nodiscard]] u64 GetLastContextSwitchTicks() const; | ||
| 58 | |||
| 59 | [[nodiscard]] bool ContextSwitchPending() const { | ||
| 60 | return state.needs_scheduling.load(std::memory_order_relaxed); | ||
| 61 | } | ||
| 62 | |||
| 63 | void Initialize(); | ||
| 64 | |||
| 65 | void OnThreadStart(); | ||
| 66 | |||
| 67 | [[nodiscard]] std::shared_ptr<Common::Fiber>& ControlContext() { | ||
| 68 | return switch_fiber; | ||
| 69 | } | ||
| 70 | |||
| 71 | [[nodiscard]] const std::shared_ptr<Common::Fiber>& ControlContext() const { | ||
| 72 | return switch_fiber; | ||
| 73 | } | ||
| 74 | |||
| 75 | [[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Takes a thread and moves it to the back of the it's priority list. | ||
| 79 | * | ||
| 80 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 81 | */ | ||
| 82 | void YieldWithoutCoreMigration(); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Takes a thread and moves it to the back of the it's priority list. | ||
| 86 | * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or | ||
| 87 | * a better priority than the next thread in the core. | ||
| 88 | * | ||
| 89 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 90 | */ | ||
| 91 | void YieldWithCoreMigration(); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Takes a thread and moves it out of the scheduling queue. | ||
| 95 | * and into the suggested queue. If no thread can be scheduled afterwards in that core, | ||
| 96 | * a suggested thread is obtained instead. | ||
| 97 | * | ||
| 98 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 99 | */ | ||
| 100 | void YieldToAnyThread(); | ||
| 101 | |||
| 102 | /// Notify the scheduler a thread's status has changed. | ||
| 103 | static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, u32 old_state); | ||
| 104 | |||
| 105 | /// Notify the scheduler a thread's priority has changed. | ||
| 106 | static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, Thread* current_thread, | ||
| 107 | u32 old_priority); | ||
| 108 | |||
| 109 | /// Notify the scheduler a thread's core and/or affinity mask has changed. | ||
| 110 | static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, | ||
| 111 | const KAffinityMask& old_affinity, s32 old_core); | ||
| 112 | |||
| 113 | static bool CanSchedule(KernelCore& kernel); | ||
| 114 | static bool IsSchedulerUpdateNeeded(const KernelCore& kernel); | ||
| 115 | static void SetSchedulerUpdateNeeded(KernelCore& kernel); | ||
| 116 | static void ClearSchedulerUpdateNeeded(KernelCore& kernel); | ||
| 117 | static void DisableScheduling(KernelCore& kernel); | ||
| 118 | static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, | ||
| 119 | Core::EmuThreadHandle global_thread); | ||
| 120 | [[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel); | ||
| 121 | |||
| 122 | private: | ||
| 123 | friend class GlobalSchedulerContext; | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Takes care of selecting the new scheduled threads in three steps: | ||
| 127 | * | ||
| 128 | * 1. First a thread is selected from the top of the priority queue. If no thread | ||
| 129 | * is obtained then we move to step two, else we are done. | ||
| 130 | * | ||
| 131 | * 2. Second we try to get a suggested thread that's not assigned to any core or | ||
| 132 | * that is not the top thread in that core. | ||
| 133 | * | ||
| 134 | * 3. Third is no suggested thread is found, we do a second pass and pick a running | ||
| 135 | * thread in another core and swap it with its current thread. | ||
| 136 | * | ||
| 137 | * returns the cores needing scheduling. | ||
| 138 | */ | ||
| 139 | [[nodiscard]] static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel); | ||
| 140 | |||
| 141 | [[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel); | ||
| 142 | |||
| 143 | void RotateScheduledQueue(s32 core_id, s32 priority); | ||
| 144 | |||
| 145 | void Schedule() { | ||
| 146 | ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); | ||
| 147 | this->ScheduleImpl(); | ||
| 148 | } | ||
| 149 | |||
| 150 | /// Switches the CPU's active thread context to that of the specified thread | ||
| 151 | void ScheduleImpl(); | ||
| 152 | |||
| 153 | /// When a thread wakes up, it must run this through it's new scheduler | ||
| 154 | void SwitchContextStep2(); | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Called on every context switch to update the internal timestamp | ||
| 158 | * This also updates the running time ticks for the given thread and | ||
| 159 | * process using the following difference: | ||
| 160 | * | ||
| 161 | * ticks += most_recent_ticks - last_context_switch_ticks | ||
| 162 | * | ||
| 163 | * The internal tick timestamp for the scheduler is simply the | ||
| 164 | * most recent tick count retrieved. No special arithmetic is | ||
| 165 | * applied to it. | ||
| 166 | */ | ||
| 167 | void UpdateLastContextSwitchTime(Thread* thread, Process* process); | ||
| 168 | |||
| 169 | static void OnSwitch(void* this_scheduler); | ||
| 170 | void SwitchToCurrent(); | ||
| 171 | |||
| 172 | Thread* current_thread{}; | ||
| 173 | Thread* idle_thread{}; | ||
| 174 | |||
| 175 | std::shared_ptr<Common::Fiber> switch_fiber{}; | ||
| 176 | |||
| 177 | struct SchedulingState { | ||
| 178 | std::atomic<bool> needs_scheduling; | ||
| 179 | bool interrupt_task_thread_runnable{}; | ||
| 180 | bool should_count_idle{}; | ||
| 181 | u64 idle_count{}; | ||
| 182 | Thread* highest_priority_thread{}; | ||
| 183 | void* idle_thread_stack{}; | ||
| 184 | }; | ||
| 185 | |||
| 186 | SchedulingState state; | ||
| 187 | |||
| 188 | Core::System& system; | ||
| 189 | u64 last_context_switch_time{}; | ||
| 190 | const std::size_t core_id; | ||
| 191 | |||
| 192 | Common::SpinLock guard{}; | ||
| 193 | }; | ||
| 194 | |||
| 195 | class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> { | ||
| 196 | public: | ||
| 197 | explicit KScopedSchedulerLock(KernelCore& kernel); | ||
| 198 | ~KScopedSchedulerLock(); | ||
| 199 | }; | ||
| 200 | |||
| 201 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h new file mode 100644 index 000000000..2f1c1f691 --- /dev/null +++ b/src/core/hle/kernel/k_scheduler_lock.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/spin_lock.h" | ||
| 12 | #include "core/hardware_properties.h" | ||
| 13 | #include "core/hle/kernel/kernel.h" | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | class KernelCore; | ||
| 18 | |||
| 19 | template <typename SchedulerType> | ||
| 20 | class KAbstractSchedulerLock { | ||
| 21 | public: | ||
| 22 | explicit KAbstractSchedulerLock(KernelCore& kernel) : kernel{kernel} {} | ||
| 23 | |||
| 24 | bool IsLockedByCurrentThread() const { | ||
| 25 | return this->owner_thread == kernel.GetCurrentEmuThreadID(); | ||
| 26 | } | ||
| 27 | |||
| 28 | void Lock() { | ||
| 29 | if (this->IsLockedByCurrentThread()) { | ||
| 30 | // If we already own the lock, we can just increment the count. | ||
| 31 | ASSERT(this->lock_count > 0); | ||
| 32 | this->lock_count++; | ||
| 33 | } else { | ||
| 34 | // Otherwise, we want to disable scheduling and acquire the spinlock. | ||
| 35 | SchedulerType::DisableScheduling(kernel); | ||
| 36 | this->spin_lock.lock(); | ||
| 37 | |||
| 38 | // For debug, ensure that our state is valid. | ||
| 39 | ASSERT(this->lock_count == 0); | ||
| 40 | ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle()); | ||
| 41 | |||
| 42 | // Increment count, take ownership. | ||
| 43 | this->lock_count = 1; | ||
| 44 | this->owner_thread = kernel.GetCurrentEmuThreadID(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void Unlock() { | ||
| 49 | ASSERT(this->IsLockedByCurrentThread()); | ||
| 50 | ASSERT(this->lock_count > 0); | ||
| 51 | |||
| 52 | // Release an instance of the lock. | ||
| 53 | if ((--this->lock_count) == 0) { | ||
| 54 | // We're no longer going to hold the lock. Take note of what cores need scheduling. | ||
| 55 | const u64 cores_needing_scheduling = | ||
| 56 | SchedulerType::UpdateHighestPriorityThreads(kernel); | ||
| 57 | Core::EmuThreadHandle leaving_thread = owner_thread; | ||
| 58 | |||
| 59 | // Note that we no longer hold the lock, and unlock the spinlock. | ||
| 60 | this->owner_thread = Core::EmuThreadHandle::InvalidHandle(); | ||
| 61 | this->spin_lock.unlock(); | ||
| 62 | |||
| 63 | // Enable scheduling, and perform a rescheduling operation. | ||
| 64 | SchedulerType::EnableScheduling(kernel, cores_needing_scheduling, leaving_thread); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | private: | ||
| 69 | KernelCore& kernel; | ||
| 70 | Common::SpinLock spin_lock{}; | ||
| 71 | s32 lock_count{}; | ||
| 72 | Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()}; | ||
| 73 | }; | ||
| 74 | |||
| 75 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h new file mode 100644 index 000000000..d7cc557b2 --- /dev/null +++ b/src/core/hle/kernel/k_scoped_lock.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | template <typename T> | ||
| 15 | concept KLockable = !std::is_reference_v<T> && requires(T & t) { | ||
| 16 | { t.Lock() } | ||
| 17 | ->std::same_as<void>; | ||
| 18 | { t.Unlock() } | ||
| 19 | ->std::same_as<void>; | ||
| 20 | }; | ||
| 21 | |||
| 22 | template <typename T> | ||
| 23 | requires KLockable<T> class KScopedLock { | ||
| 24 | public: | ||
| 25 | explicit KScopedLock(T* l) : lock_ptr(l) { | ||
| 26 | this->lock_ptr->Lock(); | ||
| 27 | } | ||
| 28 | explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */ | ||
| 29 | } | ||
| 30 | ~KScopedLock() { | ||
| 31 | this->lock_ptr->Unlock(); | ||
| 32 | } | ||
| 33 | |||
| 34 | KScopedLock(const KScopedLock&) = delete; | ||
| 35 | KScopedLock(KScopedLock&&) = delete; | ||
| 36 | |||
| 37 | private: | ||
| 38 | T* lock_ptr; | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h new file mode 100644 index 000000000..2bb3817fa --- /dev/null +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/handle_table.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/kernel/time_manager.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | |||
| 18 | class KScopedSchedulerLockAndSleep { | ||
| 19 | public: | ||
| 20 | explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t, | ||
| 21 | s64 timeout) | ||
| 22 | : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) { | ||
| 23 | event_handle = InvalidHandle; | ||
| 24 | |||
| 25 | // Lock the scheduler. | ||
| 26 | kernel.GlobalSchedulerContext().scheduler_lock.Lock(); | ||
| 27 | } | ||
| 28 | |||
| 29 | ~KScopedSchedulerLockAndSleep() { | ||
| 30 | // Register the sleep. | ||
| 31 | if (this->timeout_tick > 0) { | ||
| 32 | kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick); | ||
| 33 | } | ||
| 34 | |||
| 35 | // Unlock the scheduler. | ||
| 36 | kernel.GlobalSchedulerContext().scheduler_lock.Unlock(); | ||
| 37 | } | ||
| 38 | |||
| 39 | void CancelSleep() { | ||
| 40 | this->timeout_tick = 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | private: | ||
| 44 | KernelCore& kernel; | ||
| 45 | Handle& event_handle; | ||
| 46 | Thread* thread{}; | ||
| 47 | s64 timeout_tick{}; | ||
| 48 | }; | ||
| 49 | |||
| 50 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f2b0fe2fd..e8ece8164 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -7,15 +7,15 @@ | |||
| 7 | #include <bitset> | 7 | #include <bitset> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <mutex> | ||
| 11 | #include <thread> | 10 | #include <thread> |
| 12 | #include <unordered_map> | 11 | #include <unordered_set> |
| 13 | #include <utility> | 12 | #include <utility> |
| 14 | 13 | ||
| 15 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| 16 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 17 | #include "common/microprofile.h" | 16 | #include "common/microprofile.h" |
| 18 | #include "common/thread.h" | 17 | #include "common/thread.h" |
| 18 | #include "common/thread_worker.h" | ||
| 19 | #include "core/arm/arm_interface.h" | 19 | #include "core/arm/arm_interface.h" |
| 20 | #include "core/arm/cpu_interrupt_handler.h" | 20 | #include "core/arm/cpu_interrupt_handler.h" |
| 21 | #include "core/arm/exclusive_monitor.h" | 21 | #include "core/arm/exclusive_monitor.h" |
| @@ -28,6 +28,7 @@ | |||
| 28 | #include "core/hle/kernel/client_port.h" | 28 | #include "core/hle/kernel/client_port.h" |
| 29 | #include "core/hle/kernel/errors.h" | 29 | #include "core/hle/kernel/errors.h" |
| 30 | #include "core/hle/kernel/handle_table.h" | 30 | #include "core/hle/kernel/handle_table.h" |
| 31 | #include "core/hle/kernel/k_scheduler.h" | ||
| 31 | #include "core/hle/kernel/kernel.h" | 32 | #include "core/hle/kernel/kernel.h" |
| 32 | #include "core/hle/kernel/memory/memory_layout.h" | 33 | #include "core/hle/kernel/memory/memory_layout.h" |
| 33 | #include "core/hle/kernel/memory/memory_manager.h" | 34 | #include "core/hle/kernel/memory/memory_manager.h" |
| @@ -35,7 +36,7 @@ | |||
| 35 | #include "core/hle/kernel/physical_core.h" | 36 | #include "core/hle/kernel/physical_core.h" |
| 36 | #include "core/hle/kernel/process.h" | 37 | #include "core/hle/kernel/process.h" |
| 37 | #include "core/hle/kernel/resource_limit.h" | 38 | #include "core/hle/kernel/resource_limit.h" |
| 38 | #include "core/hle/kernel/scheduler.h" | 39 | #include "core/hle/kernel/service_thread.h" |
| 39 | #include "core/hle/kernel/shared_memory.h" | 40 | #include "core/hle/kernel/shared_memory.h" |
| 40 | #include "core/hle/kernel/synchronization.h" | 41 | #include "core/hle/kernel/synchronization.h" |
| 41 | #include "core/hle/kernel/thread.h" | 42 | #include "core/hle/kernel/thread.h" |
| @@ -50,17 +51,20 @@ namespace Kernel { | |||
| 50 | 51 | ||
| 51 | struct KernelCore::Impl { | 52 | struct KernelCore::Impl { |
| 52 | explicit Impl(Core::System& system, KernelCore& kernel) | 53 | explicit Impl(Core::System& system, KernelCore& kernel) |
| 53 | : global_scheduler{kernel}, synchronization{system}, time_manager{system}, | 54 | : synchronization{system}, time_manager{system}, global_handle_table{kernel}, system{ |
| 54 | global_handle_table{kernel}, system{system} {} | 55 | system} {} |
| 55 | 56 | ||
| 56 | void SetMulticore(bool is_multicore) { | 57 | void SetMulticore(bool is_multicore) { |
| 57 | this->is_multicore = is_multicore; | 58 | this->is_multicore = is_multicore; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | void Initialize(KernelCore& kernel) { | 61 | void Initialize(KernelCore& kernel) { |
| 61 | Shutdown(); | ||
| 62 | RegisterHostThread(); | 62 | RegisterHostThread(); |
| 63 | 63 | ||
| 64 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | ||
| 65 | service_thread_manager = | ||
| 66 | std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); | ||
| 67 | |||
| 64 | InitializePhysicalCores(); | 68 | InitializePhysicalCores(); |
| 65 | InitializeSystemResourceLimit(kernel); | 69 | InitializeSystemResourceLimit(kernel); |
| 66 | InitializeMemoryLayout(); | 70 | InitializeMemoryLayout(); |
| @@ -69,7 +73,19 @@ struct KernelCore::Impl { | |||
| 69 | InitializeSuspendThreads(); | 73 | InitializeSuspendThreads(); |
| 70 | } | 74 | } |
| 71 | 75 | ||
| 76 | void InitializeCores() { | ||
| 77 | for (auto& core : cores) { | ||
| 78 | core.Initialize(current_process->Is64BitProcess()); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 72 | void Shutdown() { | 82 | void Shutdown() { |
| 83 | process_list.clear(); | ||
| 84 | |||
| 85 | // Ensures all service threads gracefully shutdown | ||
| 86 | service_thread_manager.reset(); | ||
| 87 | service_threads.clear(); | ||
| 88 | |||
| 73 | next_object_id = 0; | 89 | next_object_id = 0; |
| 74 | next_kernel_process_id = Process::InitialKIPIDMin; | 90 | next_kernel_process_id = Process::InitialKIPIDMin; |
| 75 | next_user_process_id = Process::ProcessIDMin; | 91 | next_user_process_id = Process::ProcessIDMin; |
| @@ -81,41 +97,30 @@ struct KernelCore::Impl { | |||
| 81 | } | 97 | } |
| 82 | } | 98 | } |
| 83 | 99 | ||
| 84 | for (std::size_t i = 0; i < cores.size(); i++) { | ||
| 85 | cores[i].Shutdown(); | ||
| 86 | schedulers[i].reset(); | ||
| 87 | } | ||
| 88 | cores.clear(); | 100 | cores.clear(); |
| 89 | 101 | ||
| 90 | registered_core_threads.reset(); | ||
| 91 | |||
| 92 | process_list.clear(); | ||
| 93 | current_process = nullptr; | 102 | current_process = nullptr; |
| 94 | 103 | ||
| 95 | system_resource_limit = nullptr; | 104 | system_resource_limit = nullptr; |
| 96 | 105 | ||
| 97 | global_handle_table.Clear(); | 106 | global_handle_table.Clear(); |
| 98 | preemption_event = nullptr; | ||
| 99 | 107 | ||
| 100 | global_scheduler.Shutdown(); | 108 | preemption_event = nullptr; |
| 101 | 109 | ||
| 102 | named_ports.clear(); | 110 | named_ports.clear(); |
| 103 | 111 | ||
| 104 | for (auto& core : cores) { | ||
| 105 | core.Shutdown(); | ||
| 106 | } | ||
| 107 | cores.clear(); | ||
| 108 | |||
| 109 | exclusive_monitor.reset(); | 112 | exclusive_monitor.reset(); |
| 110 | host_thread_ids.clear(); | 113 | |
| 114 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others | ||
| 115 | next_host_thread_id = Core::Hardware::NUM_CPU_CORES; | ||
| 111 | } | 116 | } |
| 112 | 117 | ||
| 113 | void InitializePhysicalCores() { | 118 | void InitializePhysicalCores() { |
| 114 | exclusive_monitor = | 119 | exclusive_monitor = |
| 115 | Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); | 120 | Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); |
| 116 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 121 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 117 | schedulers[i] = std::make_unique<Kernel::Scheduler>(system, i); | 122 | schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i); |
| 118 | cores.emplace_back(system, i, *schedulers[i], interrupts[i]); | 123 | cores.emplace_back(i, system, *schedulers[i], interrupts); |
| 119 | } | 124 | } |
| 120 | } | 125 | } |
| 121 | 126 | ||
| @@ -147,8 +152,8 @@ struct KernelCore::Impl { | |||
| 147 | preemption_event = Core::Timing::CreateEvent( | 152 | preemption_event = Core::Timing::CreateEvent( |
| 148 | "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { | 153 | "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { |
| 149 | { | 154 | { |
| 150 | SchedulerLock lock(kernel); | 155 | KScopedSchedulerLock lock(kernel); |
| 151 | global_scheduler.PreemptThreads(); | 156 | global_scheduler_context->PreemptThreads(); |
| 152 | } | 157 | } |
| 153 | const auto time_interval = std::chrono::nanoseconds{ | 158 | const auto time_interval = std::chrono::nanoseconds{ |
| 154 | Core::Timing::msToCycles(std::chrono::milliseconds(10))}; | 159 | Core::Timing::msToCycles(std::chrono::milliseconds(10))}; |
| @@ -177,63 +182,62 @@ struct KernelCore::Impl { | |||
| 177 | 182 | ||
| 178 | void MakeCurrentProcess(Process* process) { | 183 | void MakeCurrentProcess(Process* process) { |
| 179 | current_process = process; | 184 | current_process = process; |
| 180 | |||
| 181 | if (process == nullptr) { | 185 | if (process == nullptr) { |
| 182 | return; | 186 | return; |
| 183 | } | 187 | } |
| 184 | 188 | ||
| 185 | u32 core_id = GetCurrentHostThreadID(); | 189 | const u32 core_id = GetCurrentHostThreadID(); |
| 186 | if (core_id < Core::Hardware::NUM_CPU_CORES) { | 190 | if (core_id < Core::Hardware::NUM_CPU_CORES) { |
| 187 | system.Memory().SetCurrentPageTable(*process, core_id); | 191 | system.Memory().SetCurrentPageTable(*process, core_id); |
| 188 | } | 192 | } |
| 189 | } | 193 | } |
| 190 | 194 | ||
| 195 | /// Creates a new host thread ID, should only be called by GetHostThreadId | ||
| 196 | u32 AllocateHostThreadId(std::optional<std::size_t> core_id) { | ||
| 197 | if (core_id) { | ||
| 198 | // The first for slots are reserved for CPU core threads | ||
| 199 | ASSERT(*core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 200 | return static_cast<u32>(*core_id); | ||
| 201 | } else { | ||
| 202 | return next_host_thread_id++; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | /// Gets the host thread ID for the caller, allocating a new one if this is the first time | ||
| 207 | u32 GetHostThreadId(std::optional<std::size_t> core_id = std::nullopt) { | ||
| 208 | const thread_local auto host_thread_id{AllocateHostThreadId(core_id)}; | ||
| 209 | return host_thread_id; | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Registers a CPU core thread by allocating a host thread ID for it | ||
| 191 | void RegisterCoreThread(std::size_t core_id) { | 213 | void RegisterCoreThread(std::size_t core_id) { |
| 192 | std::unique_lock lock{register_thread_mutex}; | 214 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); |
| 215 | const auto this_id = GetHostThreadId(core_id); | ||
| 193 | if (!is_multicore) { | 216 | if (!is_multicore) { |
| 194 | single_core_thread_id = std::this_thread::get_id(); | 217 | single_core_thread_id = this_id; |
| 195 | } | 218 | } |
| 196 | const std::thread::id this_id = std::this_thread::get_id(); | ||
| 197 | const auto it = host_thread_ids.find(this_id); | ||
| 198 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 199 | ASSERT(it == host_thread_ids.end()); | ||
| 200 | ASSERT(!registered_core_threads[core_id]); | ||
| 201 | host_thread_ids[this_id] = static_cast<u32>(core_id); | ||
| 202 | registered_core_threads.set(core_id); | ||
| 203 | } | 219 | } |
| 204 | 220 | ||
| 221 | /// Registers a new host thread by allocating a host thread ID for it | ||
| 205 | void RegisterHostThread() { | 222 | void RegisterHostThread() { |
| 206 | std::unique_lock lock{register_thread_mutex}; | 223 | [[maybe_unused]] const auto this_id = GetHostThreadId(); |
| 207 | const std::thread::id this_id = std::this_thread::get_id(); | ||
| 208 | const auto it = host_thread_ids.find(this_id); | ||
| 209 | if (it != host_thread_ids.end()) { | ||
| 210 | return; | ||
| 211 | } | ||
| 212 | host_thread_ids[this_id] = registered_thread_ids++; | ||
| 213 | } | 224 | } |
| 214 | 225 | ||
| 215 | u32 GetCurrentHostThreadID() const { | 226 | [[nodiscard]] u32 GetCurrentHostThreadID() { |
| 216 | const std::thread::id this_id = std::this_thread::get_id(); | 227 | const auto this_id = GetHostThreadId(); |
| 217 | if (!is_multicore) { | 228 | if (!is_multicore && single_core_thread_id == this_id) { |
| 218 | if (single_core_thread_id == this_id) { | 229 | return static_cast<u32>(system.GetCpuManager().CurrentCore()); |
| 219 | return static_cast<u32>(system.GetCpuManager().CurrentCore()); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | std::unique_lock lock{register_thread_mutex}; | ||
| 223 | const auto it = host_thread_ids.find(this_id); | ||
| 224 | if (it == host_thread_ids.end()) { | ||
| 225 | return Core::INVALID_HOST_THREAD_ID; | ||
| 226 | } | 230 | } |
| 227 | return it->second; | 231 | return this_id; |
| 228 | } | 232 | } |
| 229 | 233 | ||
| 230 | Core::EmuThreadHandle GetCurrentEmuThreadID() const { | 234 | [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() { |
| 231 | Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); | 235 | Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); |
| 232 | result.host_handle = GetCurrentHostThreadID(); | 236 | result.host_handle = GetCurrentHostThreadID(); |
| 233 | if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { | 237 | if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { |
| 234 | return result; | 238 | return result; |
| 235 | } | 239 | } |
| 236 | const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); | 240 | const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler(); |
| 237 | const Kernel::Thread* current = sched.GetCurrentThread(); | 241 | const Kernel::Thread* current = sched.GetCurrentThread(); |
| 238 | if (current != nullptr && !current->IsPhantomMode()) { | 242 | if (current != nullptr && !current->IsPhantomMode()) { |
| 239 | result.guest_handle = current->GetGlobalHandle(); | 243 | result.guest_handle = current->GetGlobalHandle(); |
| @@ -302,7 +306,7 @@ struct KernelCore::Impl { | |||
| 302 | // Lists all processes that exist in the current session. | 306 | // Lists all processes that exist in the current session. |
| 303 | std::vector<std::shared_ptr<Process>> process_list; | 307 | std::vector<std::shared_ptr<Process>> process_list; |
| 304 | Process* current_process = nullptr; | 308 | Process* current_process = nullptr; |
| 305 | Kernel::GlobalScheduler global_scheduler; | 309 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 306 | Kernel::Synchronization synchronization; | 310 | Kernel::Synchronization synchronization; |
| 307 | Kernel::TimeManager time_manager; | 311 | Kernel::TimeManager time_manager; |
| 308 | 312 | ||
| @@ -321,11 +325,8 @@ struct KernelCore::Impl { | |||
| 321 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 325 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| 322 | std::vector<Kernel::PhysicalCore> cores; | 326 | std::vector<Kernel::PhysicalCore> cores; |
| 323 | 327 | ||
| 324 | // 0-3 IDs represent core threads, >3 represent others | 328 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others |
| 325 | std::unordered_map<std::thread::id, u32> host_thread_ids; | 329 | std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; |
| 326 | u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; | ||
| 327 | std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; | ||
| 328 | mutable std::mutex register_thread_mutex; | ||
| 329 | 330 | ||
| 330 | // Kernel memory management | 331 | // Kernel memory management |
| 331 | std::unique_ptr<Memory::MemoryManager> memory_manager; | 332 | std::unique_ptr<Memory::MemoryManager> memory_manager; |
| @@ -337,12 +338,19 @@ struct KernelCore::Impl { | |||
| 337 | std::shared_ptr<Kernel::SharedMemory> irs_shared_mem; | 338 | std::shared_ptr<Kernel::SharedMemory> irs_shared_mem; |
| 338 | std::shared_ptr<Kernel::SharedMemory> time_shared_mem; | 339 | std::shared_ptr<Kernel::SharedMemory> time_shared_mem; |
| 339 | 340 | ||
| 341 | // Threads used for services | ||
| 342 | std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; | ||
| 343 | |||
| 344 | // Service threads are managed by a worker thread, so that a calling service thread can queue up | ||
| 345 | // the release of itself | ||
| 346 | std::unique_ptr<Common::ThreadWorker> service_thread_manager; | ||
| 347 | |||
| 340 | std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; | 348 | std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; |
| 341 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 349 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 342 | std::array<std::unique_ptr<Kernel::Scheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 350 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 343 | 351 | ||
| 344 | bool is_multicore{}; | 352 | bool is_multicore{}; |
| 345 | std::thread::id single_core_thread_id{}; | 353 | u32 single_core_thread_id{}; |
| 346 | 354 | ||
| 347 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; | 355 | std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; |
| 348 | 356 | ||
| @@ -363,6 +371,10 @@ void KernelCore::Initialize() { | |||
| 363 | impl->Initialize(*this); | 371 | impl->Initialize(*this); |
| 364 | } | 372 | } |
| 365 | 373 | ||
| 374 | void KernelCore::InitializeCores() { | ||
| 375 | impl->InitializeCores(); | ||
| 376 | } | ||
| 377 | |||
| 366 | void KernelCore::Shutdown() { | 378 | void KernelCore::Shutdown() { |
| 367 | impl->Shutdown(); | 379 | impl->Shutdown(); |
| 368 | } | 380 | } |
| @@ -395,19 +407,19 @@ const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const | |||
| 395 | return impl->process_list; | 407 | return impl->process_list; |
| 396 | } | 408 | } |
| 397 | 409 | ||
| 398 | Kernel::GlobalScheduler& KernelCore::GlobalScheduler() { | 410 | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { |
| 399 | return impl->global_scheduler; | 411 | return *impl->global_scheduler_context; |
| 400 | } | 412 | } |
| 401 | 413 | ||
| 402 | const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { | 414 | const Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() const { |
| 403 | return impl->global_scheduler; | 415 | return *impl->global_scheduler_context; |
| 404 | } | 416 | } |
| 405 | 417 | ||
| 406 | Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { | 418 | Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) { |
| 407 | return *impl->schedulers[id]; | 419 | return *impl->schedulers[id]; |
| 408 | } | 420 | } |
| 409 | 421 | ||
| 410 | const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { | 422 | const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const { |
| 411 | return *impl->schedulers[id]; | 423 | return *impl->schedulers[id]; |
| 412 | } | 424 | } |
| 413 | 425 | ||
| @@ -431,16 +443,13 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { | |||
| 431 | return impl->cores[core_id]; | 443 | return impl->cores[core_id]; |
| 432 | } | 444 | } |
| 433 | 445 | ||
| 434 | Kernel::Scheduler& KernelCore::CurrentScheduler() { | 446 | Kernel::KScheduler* KernelCore::CurrentScheduler() { |
| 435 | u32 core_id = impl->GetCurrentHostThreadID(); | 447 | u32 core_id = impl->GetCurrentHostThreadID(); |
| 436 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | 448 | if (core_id >= Core::Hardware::NUM_CPU_CORES) { |
| 437 | return *impl->schedulers[core_id]; | 449 | // This is expected when called from not a guest thread |
| 438 | } | 450 | return {}; |
| 439 | 451 | } | |
| 440 | const Kernel::Scheduler& KernelCore::CurrentScheduler() const { | 452 | return impl->schedulers[core_id].get(); |
| 441 | u32 core_id = impl->GetCurrentHostThreadID(); | ||
| 442 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 443 | return *impl->schedulers[core_id]; | ||
| 444 | } | 453 | } |
| 445 | 454 | ||
| 446 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() { | 455 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() { |
| @@ -477,12 +486,17 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { | |||
| 477 | } | 486 | } |
| 478 | 487 | ||
| 479 | void KernelCore::InvalidateAllInstructionCaches() { | 488 | void KernelCore::InvalidateAllInstructionCaches() { |
| 480 | auto& threads = GlobalScheduler().GetThreadList(); | 489 | for (auto& physical_core : impl->cores) { |
| 481 | for (auto& thread : threads) { | 490 | physical_core.ArmInterface().ClearInstructionCache(); |
| 482 | if (!thread->IsHLEThread()) { | 491 | } |
| 483 | auto& arm_interface = thread->ArmInterface(); | 492 | } |
| 484 | arm_interface.ClearInstructionCache(); | 493 | |
| 494 | void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { | ||
| 495 | for (auto& physical_core : impl->cores) { | ||
| 496 | if (!physical_core.IsInitialized()) { | ||
| 497 | continue; | ||
| 485 | } | 498 | } |
| 499 | physical_core.ArmInterface().InvalidateCacheRange(addr, size); | ||
| 486 | } | 500 | } |
| 487 | } | 501 | } |
| 488 | 502 | ||
| @@ -598,7 +612,7 @@ const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const { | |||
| 598 | void KernelCore::Suspend(bool in_suspention) { | 612 | void KernelCore::Suspend(bool in_suspention) { |
| 599 | const bool should_suspend = exception_exited || in_suspention; | 613 | const bool should_suspend = exception_exited || in_suspention; |
| 600 | { | 614 | { |
| 601 | SchedulerLock lock(*this); | 615 | KScopedSchedulerLock lock(*this); |
| 602 | ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; | 616 | ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; |
| 603 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 617 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 604 | impl->suspend_threads[i]->SetStatus(status); | 618 | impl->suspend_threads[i]->SetStatus(status); |
| @@ -625,4 +639,19 @@ void KernelCore::ExitSVCProfile() { | |||
| 625 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); | 639 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); |
| 626 | } | 640 | } |
| 627 | 641 | ||
| 642 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { | ||
| 643 | auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name); | ||
| 644 | impl->service_thread_manager->QueueWork( | ||
| 645 | [this, service_thread] { impl->service_threads.emplace(service_thread); }); | ||
| 646 | return service_thread; | ||
| 647 | } | ||
| 648 | |||
| 649 | void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) { | ||
| 650 | impl->service_thread_manager->QueueWork([this, service_thread] { | ||
| 651 | if (auto strong_ptr = service_thread.lock()) { | ||
| 652 | impl->service_threads.erase(strong_ptr); | ||
| 653 | } | ||
| 654 | }); | ||
| 655 | } | ||
| 656 | |||
| 628 | } // namespace Kernel | 657 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 16285c3f0..e3169f5a7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -35,13 +35,14 @@ class SlabHeap; | |||
| 35 | 35 | ||
| 36 | class AddressArbiter; | 36 | class AddressArbiter; |
| 37 | class ClientPort; | 37 | class ClientPort; |
| 38 | class GlobalScheduler; | 38 | class GlobalSchedulerContext; |
| 39 | class HandleTable; | 39 | class HandleTable; |
| 40 | class PhysicalCore; | 40 | class PhysicalCore; |
| 41 | class Process; | 41 | class Process; |
| 42 | class ResourceLimit; | 42 | class ResourceLimit; |
| 43 | class Scheduler; | 43 | class KScheduler; |
| 44 | class SharedMemory; | 44 | class SharedMemory; |
| 45 | class ServiceThread; | ||
| 45 | class Synchronization; | 46 | class Synchronization; |
| 46 | class Thread; | 47 | class Thread; |
| 47 | class TimeManager; | 48 | class TimeManager; |
| @@ -74,6 +75,9 @@ public: | |||
| 74 | /// Resets the kernel to a clean slate for use. | 75 | /// Resets the kernel to a clean slate for use. |
| 75 | void Initialize(); | 76 | void Initialize(); |
| 76 | 77 | ||
| 78 | /// Initializes the CPU cores. | ||
| 79 | void InitializeCores(); | ||
| 80 | |||
| 77 | /// Clears all resources in use by the kernel instance. | 81 | /// Clears all resources in use by the kernel instance. |
| 78 | void Shutdown(); | 82 | void Shutdown(); |
| 79 | 83 | ||
| @@ -99,16 +103,16 @@ public: | |||
| 99 | const std::vector<std::shared_ptr<Process>>& GetProcessList() const; | 103 | const std::vector<std::shared_ptr<Process>>& GetProcessList() const; |
| 100 | 104 | ||
| 101 | /// Gets the sole instance of the global scheduler | 105 | /// Gets the sole instance of the global scheduler |
| 102 | Kernel::GlobalScheduler& GlobalScheduler(); | 106 | Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); |
| 103 | 107 | ||
| 104 | /// Gets the sole instance of the global scheduler | 108 | /// Gets the sole instance of the global scheduler |
| 105 | const Kernel::GlobalScheduler& GlobalScheduler() const; | 109 | const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const; |
| 106 | 110 | ||
| 107 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' | 111 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' |
| 108 | Kernel::Scheduler& Scheduler(std::size_t id); | 112 | Kernel::KScheduler& Scheduler(std::size_t id); |
| 109 | 113 | ||
| 110 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' | 114 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' |
| 111 | const Kernel::Scheduler& Scheduler(std::size_t id) const; | 115 | const Kernel::KScheduler& Scheduler(std::size_t id) const; |
| 112 | 116 | ||
| 113 | /// Gets the an instance of the respective physical CPU core. | 117 | /// Gets the an instance of the respective physical CPU core. |
| 114 | Kernel::PhysicalCore& PhysicalCore(std::size_t id); | 118 | Kernel::PhysicalCore& PhysicalCore(std::size_t id); |
| @@ -117,10 +121,7 @@ public: | |||
| 117 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; | 121 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; |
| 118 | 122 | ||
| 119 | /// Gets the sole instance of the Scheduler at the current running core. | 123 | /// Gets the sole instance of the Scheduler at the current running core. |
| 120 | Kernel::Scheduler& CurrentScheduler(); | 124 | Kernel::KScheduler* CurrentScheduler(); |
| 121 | |||
| 122 | /// Gets the sole instance of the Scheduler at the current running core. | ||
| 123 | const Kernel::Scheduler& CurrentScheduler() const; | ||
| 124 | 125 | ||
| 125 | /// Gets the an instance of the current physical CPU core. | 126 | /// Gets the an instance of the current physical CPU core. |
| 126 | Kernel::PhysicalCore& CurrentPhysicalCore(); | 127 | Kernel::PhysicalCore& CurrentPhysicalCore(); |
| @@ -153,6 +154,8 @@ public: | |||
| 153 | 154 | ||
| 154 | void InvalidateAllInstructionCaches(); | 155 | void InvalidateAllInstructionCaches(); |
| 155 | 156 | ||
| 157 | void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); | ||
| 158 | |||
| 156 | /// Adds a port to the named port table | 159 | /// Adds a port to the named port table |
| 157 | void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); | 160 | void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); |
| 158 | 161 | ||
| @@ -225,6 +228,22 @@ public: | |||
| 225 | 228 | ||
| 226 | void ExitSVCProfile(); | 229 | void ExitSVCProfile(); |
| 227 | 230 | ||
| 231 | /** | ||
| 232 | * Creates an HLE service thread, which are used to execute service routines asynchronously. | ||
| 233 | * While these are allocated per ServerSession, these need to be owned and managed outside of | ||
| 234 | * ServerSession to avoid a circular dependency. | ||
| 235 | * @param name String name for the ServerSession creating this thread, used for debug purposes. | ||
| 236 | * @returns The a weak pointer newly created service thread. | ||
| 237 | */ | ||
| 238 | std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); | ||
| 239 | |||
| 240 | /** | ||
| 241 | * Releases a HLE service thread, instructing KernelCore to free it. This should be called when | ||
| 242 | * the ServerSession associated with the thread is destroyed. | ||
| 243 | * @param service_thread Service thread to release. | ||
| 244 | */ | ||
| 245 | void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread); | ||
| 246 | |||
| 228 | private: | 247 | private: |
| 229 | friend class Object; | 248 | friend class Object; |
| 230 | friend class Process; | 249 | friend class Process; |
diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp index e4288cab4..6cf43ba24 100644 --- a/src/core/hle/kernel/memory/address_space_info.cpp +++ b/src/core/hle/kernel/memory/address_space_info.cpp | |||
| @@ -96,6 +96,7 @@ u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { | |||
| 96 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; | 96 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; |
| 97 | } | 97 | } |
| 98 | UNREACHABLE(); | 98 | UNREACHABLE(); |
| 99 | return 0; | ||
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { | 102 | std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { |
| @@ -112,6 +113,7 @@ std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) | |||
| 112 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; | 113 | return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; |
| 113 | } | 114 | } |
| 114 | UNREACHABLE(); | 115 | UNREACHABLE(); |
| 116 | return 0; | ||
| 115 | } | 117 | } |
| 116 | 118 | ||
| 117 | } // namespace Kernel::Memory | 119 | } // namespace Kernel::Memory |
diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h index 9d7839d08..83acece1e 100644 --- a/src/core/hle/kernel/memory/memory_block.h +++ b/src/core/hle/kernel/memory/memory_block.h | |||
| @@ -73,12 +73,12 @@ enum class MemoryState : u32 { | |||
| 73 | ThreadLocal = | 73 | ThreadLocal = |
| 74 | static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, | 74 | static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, |
| 75 | 75 | ||
| 76 | Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | | 76 | Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | |
| 77 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | | 77 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | |
| 78 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 78 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 79 | 79 | ||
| 80 | SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | | 80 | SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | |
| 81 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 81 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 82 | 82 | ||
| 83 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | | 83 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | |
| 84 | FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 84 | FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| @@ -111,8 +111,8 @@ static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09); | |||
| 111 | static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A); | 111 | static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A); |
| 112 | static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B); | 112 | static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B); |
| 113 | static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C); | 113 | static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C); |
| 114 | static_assert(static_cast<u32>(MemoryState::Transfered) == 0x015C3C0D); | 114 | static_assert(static_cast<u32>(MemoryState::Transferred) == 0x015C3C0D); |
| 115 | static_assert(static_cast<u32>(MemoryState::SharedTransfered) == 0x005C380E); | 115 | static_assert(static_cast<u32>(MemoryState::SharedTransferred) == 0x005C380E); |
| 116 | static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F); | 116 | static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F); |
| 117 | static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010); | 117 | static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010); |
| 118 | static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811); | 118 | static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811); |
| @@ -222,9 +222,9 @@ public: | |||
| 222 | 222 | ||
| 223 | public: | 223 | public: |
| 224 | constexpr MemoryBlock() = default; | 224 | constexpr MemoryBlock() = default; |
| 225 | constexpr MemoryBlock(VAddr addr, std::size_t num_pages, MemoryState state, | 225 | constexpr MemoryBlock(VAddr addr_, std::size_t num_pages_, MemoryState state_, |
| 226 | MemoryPermission perm, MemoryAttribute attribute) | 226 | MemoryPermission perm_, MemoryAttribute attribute_) |
| 227 | : addr{addr}, num_pages(num_pages), state{state}, perm{perm}, attribute{attribute} {} | 227 | : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {} |
| 228 | 228 | ||
| 229 | constexpr VAddr GetAddress() const { | 229 | constexpr VAddr GetAddress() const { |
| 230 | return addr; | 230 | return addr; |
diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/memory/memory_block_manager.h index 6e1d41075..f57d1bbcc 100644 --- a/src/core/hle/kernel/memory/memory_block_manager.h +++ b/src/core/hle/kernel/memory/memory_block_manager.h | |||
| @@ -57,8 +57,8 @@ public: | |||
| 57 | private: | 57 | private: |
| 58 | void MergeAdjacent(iterator it, iterator& next_it); | 58 | void MergeAdjacent(iterator it, iterator& next_it); |
| 59 | 59 | ||
| 60 | const VAddr start_addr; | 60 | [[maybe_unused]] const VAddr start_addr; |
| 61 | const VAddr end_addr; | 61 | [[maybe_unused]] const VAddr end_addr; |
| 62 | 62 | ||
| 63 | MemoryBlockTree memory_block_tree; | 63 | MemoryBlockTree memory_block_tree; |
| 64 | }; | 64 | }; |
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index a3fadb533..080886554 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp | |||
| @@ -265,7 +265,7 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t | |||
| 265 | physical_memory_usage = 0; | 265 | physical_memory_usage = 0; |
| 266 | memory_pool = pool; | 266 | memory_pool = pool; |
| 267 | 267 | ||
| 268 | page_table_impl.Resize(address_space_width, PageBits, true); | 268 | page_table_impl.Resize(address_space_width, PageBits); |
| 269 | 269 | ||
| 270 | return InitializeMemoryLayout(start, end); | 270 | return InitializeMemoryLayout(start, end); |
| 271 | } | 271 | } |
| @@ -670,6 +670,11 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo | |||
| 670 | return RESULT_SUCCESS; | 670 | return RESULT_SUCCESS; |
| 671 | } | 671 | } |
| 672 | 672 | ||
| 673 | if ((prev_perm & MemoryPermission::Execute) != (perm & MemoryPermission::Execute)) { | ||
| 674 | // Memory execution state is changing, invalidate CPU cache range | ||
| 675 | system.InvalidateCpuInstructionCacheRange(addr, size); | ||
| 676 | } | ||
| 677 | |||
| 673 | const std::size_t num_pages{size / PageSize}; | 678 | const std::size_t num_pages{size / PageSize}; |
| 674 | const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None | 679 | const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None |
| 675 | ? OperationType::ChangePermissionsAndRefresh | 680 | ? OperationType::ChangePermissionsAndRefresh |
| @@ -1002,8 +1007,8 @@ constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const { | |||
| 1002 | case MemoryState::Shared: | 1007 | case MemoryState::Shared: |
| 1003 | case MemoryState::AliasCode: | 1008 | case MemoryState::AliasCode: |
| 1004 | case MemoryState::AliasCodeData: | 1009 | case MemoryState::AliasCodeData: |
| 1005 | case MemoryState::Transfered: | 1010 | case MemoryState::Transferred: |
| 1006 | case MemoryState::SharedTransfered: | 1011 | case MemoryState::SharedTransferred: |
| 1007 | case MemoryState::SharedCode: | 1012 | case MemoryState::SharedCode: |
| 1008 | case MemoryState::GeneratedCode: | 1013 | case MemoryState::GeneratedCode: |
| 1009 | case MemoryState::CodeOut: | 1014 | case MemoryState::CodeOut: |
| @@ -1037,8 +1042,8 @@ constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const { | |||
| 1037 | case MemoryState::Shared: | 1042 | case MemoryState::Shared: |
| 1038 | case MemoryState::AliasCode: | 1043 | case MemoryState::AliasCode: |
| 1039 | case MemoryState::AliasCodeData: | 1044 | case MemoryState::AliasCodeData: |
| 1040 | case MemoryState::Transfered: | 1045 | case MemoryState::Transferred: |
| 1041 | case MemoryState::SharedTransfered: | 1046 | case MemoryState::SharedTransferred: |
| 1042 | case MemoryState::SharedCode: | 1047 | case MemoryState::SharedCode: |
| 1043 | case MemoryState::GeneratedCode: | 1048 | case MemoryState::GeneratedCode: |
| 1044 | case MemoryState::CodeOut: | 1049 | case MemoryState::CodeOut: |
| @@ -1075,8 +1080,8 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s | |||
| 1075 | case MemoryState::AliasCodeData: | 1080 | case MemoryState::AliasCodeData: |
| 1076 | case MemoryState::Stack: | 1081 | case MemoryState::Stack: |
| 1077 | case MemoryState::ThreadLocal: | 1082 | case MemoryState::ThreadLocal: |
| 1078 | case MemoryState::Transfered: | 1083 | case MemoryState::Transferred: |
| 1079 | case MemoryState::SharedTransfered: | 1084 | case MemoryState::SharedTransferred: |
| 1080 | case MemoryState::SharedCode: | 1085 | case MemoryState::SharedCode: |
| 1081 | case MemoryState::GeneratedCode: | 1086 | case MemoryState::GeneratedCode: |
| 1082 | case MemoryState::CodeOut: | 1087 | case MemoryState::CodeOut: |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 8f6c944d1..4f8075e0e 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -11,11 +11,11 @@ | |||
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/hle/kernel/errors.h" | 12 | #include "core/hle/kernel/errors.h" |
| 13 | #include "core/hle/kernel/handle_table.h" | 13 | #include "core/hle/kernel/handle_table.h" |
| 14 | #include "core/hle/kernel/k_scheduler.h" | ||
| 14 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/mutex.h" | 16 | #include "core/hle/kernel/mutex.h" |
| 16 | #include "core/hle/kernel/object.h" | 17 | #include "core/hle/kernel/object.h" |
| 17 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/scheduler.h" | ||
| 19 | #include "core/hle/kernel/thread.h" | 19 | #include "core/hle/kernel/thread.h" |
| 20 | #include "core/hle/result.h" | 20 | #include "core/hle/result.h" |
| 21 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| @@ -73,9 +73,9 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 73 | 73 | ||
| 74 | auto& kernel = system.Kernel(); | 74 | auto& kernel = system.Kernel(); |
| 75 | std::shared_ptr<Thread> current_thread = | 75 | std::shared_ptr<Thread> current_thread = |
| 76 | SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); | 76 | SharedFrom(kernel.CurrentScheduler()->GetCurrentThread()); |
| 77 | { | 77 | { |
| 78 | SchedulerLock lock(kernel); | 78 | KScopedSchedulerLock lock(kernel); |
| 79 | // The mutex address must be 4-byte aligned | 79 | // The mutex address must be 4-byte aligned |
| 80 | if ((address % sizeof(u32)) != 0) { | 80 | if ((address % sizeof(u32)) != 0) { |
| 81 | return ERR_INVALID_ADDRESS; | 81 | return ERR_INVALID_ADDRESS; |
| @@ -114,7 +114,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | { | 116 | { |
| 117 | SchedulerLock lock(kernel); | 117 | KScopedSchedulerLock lock(kernel); |
| 118 | auto* owner = current_thread->GetLockOwner(); | 118 | auto* owner = current_thread->GetLockOwner(); |
| 119 | if (owner != nullptr) { | 119 | if (owner != nullptr) { |
| 120 | owner->RemoveMutexWaiter(current_thread); | 120 | owner->RemoveMutexWaiter(current_thread); |
| @@ -153,10 +153,10 @@ std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thr | |||
| 153 | 153 | ||
| 154 | ResultCode Mutex::Release(VAddr address) { | 154 | ResultCode Mutex::Release(VAddr address) { |
| 155 | auto& kernel = system.Kernel(); | 155 | auto& kernel = system.Kernel(); |
| 156 | SchedulerLock lock(kernel); | 156 | KScopedSchedulerLock lock(kernel); |
| 157 | 157 | ||
| 158 | std::shared_ptr<Thread> current_thread = | 158 | std::shared_ptr<Thread> current_thread = |
| 159 | SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); | 159 | SharedFrom(kernel.CurrentScheduler()->GetCurrentThread()); |
| 160 | 160 | ||
| 161 | auto [result, new_owner] = Unlock(current_thread, address); | 161 | auto [result, new_owner] = Unlock(current_thread, address); |
| 162 | 162 | ||
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index c6bbdb080..7fea45f96 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp | |||
| @@ -2,54 +2,60 @@ | |||
| 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/assert.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/spin_lock.h" | 5 | #include "common/spin_lock.h" |
| 8 | #include "core/arm/arm_interface.h" | 6 | #include "core/arm/cpu_interrupt_handler.h" |
| 9 | #ifdef ARCHITECTURE_x86_64 | ||
| 10 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | 7 | #include "core/arm/dynarmic/arm_dynarmic_32.h" |
| 11 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | 8 | #include "core/arm/dynarmic/arm_dynarmic_64.h" |
| 12 | #endif | ||
| 13 | #include "core/arm/cpu_interrupt_handler.h" | ||
| 14 | #include "core/arm/exclusive_monitor.h" | ||
| 15 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 16 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/k_scheduler.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 17 | #include "core/hle/kernel/physical_core.h" | 12 | #include "core/hle/kernel/physical_core.h" |
| 18 | #include "core/hle/kernel/scheduler.h" | ||
| 19 | #include "core/hle/kernel/thread.h" | ||
| 20 | 13 | ||
| 21 | namespace Kernel { | 14 | namespace Kernel { |
| 22 | 15 | ||
| 23 | PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, | 16 | PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, |
| 24 | Core::CPUInterruptHandler& interrupt_handler) | 17 | Kernel::KScheduler& scheduler, Core::CPUInterrupts& interrupts) |
| 25 | : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { | 18 | : core_index{core_index}, system{system}, scheduler{scheduler}, |
| 26 | 19 | interrupts{interrupts}, guard{std::make_unique<Common::SpinLock>()} {} | |
| 27 | guard = std::make_unique<Common::SpinLock>(); | ||
| 28 | } | ||
| 29 | 20 | ||
| 30 | PhysicalCore::~PhysicalCore() = default; | 21 | PhysicalCore::~PhysicalCore() = default; |
| 31 | 22 | ||
| 32 | void PhysicalCore::Idle() { | 23 | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { |
| 33 | interrupt_handler.AwaitInterrupt(); | 24 | #ifdef ARCHITECTURE_x86_64 |
| 25 | auto& kernel = system.Kernel(); | ||
| 26 | if (is_64_bit) { | ||
| 27 | arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | ||
| 28 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||
| 29 | } else { | ||
| 30 | arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( | ||
| 31 | system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); | ||
| 32 | } | ||
| 33 | #else | ||
| 34 | #error Platform not supported yet. | ||
| 35 | #endif | ||
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | void PhysicalCore::Shutdown() { | 38 | void PhysicalCore::Run() { |
| 37 | scheduler.Shutdown(); | 39 | arm_interface->Run(); |
| 40 | } | ||
| 41 | |||
| 42 | void PhysicalCore::Idle() { | ||
| 43 | interrupts[core_index].AwaitInterrupt(); | ||
| 38 | } | 44 | } |
| 39 | 45 | ||
| 40 | bool PhysicalCore::IsInterrupted() const { | 46 | bool PhysicalCore::IsInterrupted() const { |
| 41 | return interrupt_handler.IsInterrupted(); | 47 | return interrupts[core_index].IsInterrupted(); |
| 42 | } | 48 | } |
| 43 | 49 | ||
| 44 | void PhysicalCore::Interrupt() { | 50 | void PhysicalCore::Interrupt() { |
| 45 | guard->lock(); | 51 | guard->lock(); |
| 46 | interrupt_handler.SetInterrupt(true); | 52 | interrupts[core_index].SetInterrupt(true); |
| 47 | guard->unlock(); | 53 | guard->unlock(); |
| 48 | } | 54 | } |
| 49 | 55 | ||
| 50 | void PhysicalCore::ClearInterrupt() { | 56 | void PhysicalCore::ClearInterrupt() { |
| 51 | guard->lock(); | 57 | guard->lock(); |
| 52 | interrupt_handler.SetInterrupt(false); | 58 | interrupts[core_index].SetInterrupt(false); |
| 53 | guard->unlock(); | 59 | guard->unlock(); |
| 54 | } | 60 | } |
| 55 | 61 | ||
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index d7a7a951c..f2b0911aa 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h | |||
| @@ -4,19 +4,21 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <cstddef> | 8 | #include <cstddef> |
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | 10 | ||
| 11 | #include "core/arm/arm_interface.h" | ||
| 12 | |||
| 10 | namespace Common { | 13 | namespace Common { |
| 11 | class SpinLock; | 14 | class SpinLock; |
| 12 | } | 15 | } |
| 13 | 16 | ||
| 14 | namespace Kernel { | 17 | namespace Kernel { |
| 15 | class Scheduler; | 18 | class KScheduler; |
| 16 | } // namespace Kernel | 19 | } // namespace Kernel |
| 17 | 20 | ||
| 18 | namespace Core { | 21 | namespace Core { |
| 19 | class ARM_Interface; | ||
| 20 | class CPUInterruptHandler; | 22 | class CPUInterruptHandler; |
| 21 | class ExclusiveMonitor; | 23 | class ExclusiveMonitor; |
| 22 | class System; | 24 | class System; |
| @@ -26,17 +28,24 @@ namespace Kernel { | |||
| 26 | 28 | ||
| 27 | class PhysicalCore { | 29 | class PhysicalCore { |
| 28 | public: | 30 | public: |
| 29 | PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, | 31 | PhysicalCore(std::size_t core_index, Core::System& system, Kernel::KScheduler& scheduler, |
| 30 | Core::CPUInterruptHandler& interrupt_handler); | 32 | Core::CPUInterrupts& interrupts); |
| 31 | ~PhysicalCore(); | 33 | ~PhysicalCore(); |
| 32 | 34 | ||
| 33 | PhysicalCore(const PhysicalCore&) = delete; | 35 | PhysicalCore(const PhysicalCore&) = delete; |
| 34 | PhysicalCore& operator=(const PhysicalCore&) = delete; | 36 | PhysicalCore& operator=(const PhysicalCore&) = delete; |
| 35 | 37 | ||
| 36 | PhysicalCore(PhysicalCore&&) = default; | 38 | PhysicalCore(PhysicalCore&&) = default; |
| 37 | PhysicalCore& operator=(PhysicalCore&&) = default; | 39 | PhysicalCore& operator=(PhysicalCore&&) = delete; |
| 40 | |||
| 41 | /// Initialize the core for the specified parameters. | ||
| 42 | void Initialize(bool is_64_bit); | ||
| 43 | |||
| 44 | /// Execute current jit state | ||
| 45 | void Run(); | ||
| 38 | 46 | ||
| 39 | void Idle(); | 47 | void Idle(); |
| 48 | |||
| 40 | /// Interrupt this physical core. | 49 | /// Interrupt this physical core. |
| 41 | void Interrupt(); | 50 | void Interrupt(); |
| 42 | 51 | ||
| @@ -46,8 +55,17 @@ public: | |||
| 46 | /// Check if this core is interrupted | 55 | /// Check if this core is interrupted |
| 47 | bool IsInterrupted() const; | 56 | bool IsInterrupted() const; |
| 48 | 57 | ||
| 49 | // Shutdown this physical core. | 58 | bool IsInitialized() const { |
| 50 | void Shutdown(); | 59 | return arm_interface != nullptr; |
| 60 | } | ||
| 61 | |||
| 62 | Core::ARM_Interface& ArmInterface() { | ||
| 63 | return *arm_interface; | ||
| 64 | } | ||
| 65 | |||
| 66 | const Core::ARM_Interface& ArmInterface() const { | ||
| 67 | return *arm_interface; | ||
| 68 | } | ||
| 51 | 69 | ||
| 52 | bool IsMainCore() const { | 70 | bool IsMainCore() const { |
| 53 | return core_index == 0; | 71 | return core_index == 0; |
| @@ -61,19 +79,21 @@ public: | |||
| 61 | return core_index; | 79 | return core_index; |
| 62 | } | 80 | } |
| 63 | 81 | ||
| 64 | Kernel::Scheduler& Scheduler() { | 82 | Kernel::KScheduler& Scheduler() { |
| 65 | return scheduler; | 83 | return scheduler; |
| 66 | } | 84 | } |
| 67 | 85 | ||
| 68 | const Kernel::Scheduler& Scheduler() const { | 86 | const Kernel::KScheduler& Scheduler() const { |
| 69 | return scheduler; | 87 | return scheduler; |
| 70 | } | 88 | } |
| 71 | 89 | ||
| 72 | private: | 90 | private: |
| 73 | Core::CPUInterruptHandler& interrupt_handler; | 91 | const std::size_t core_index; |
| 74 | std::size_t core_index; | 92 | Core::System& system; |
| 75 | Kernel::Scheduler& scheduler; | 93 | Kernel::KScheduler& scheduler; |
| 94 | Core::CPUInterrupts& interrupts; | ||
| 76 | std::unique_ptr<Common::SpinLock> guard; | 95 | std::unique_ptr<Common::SpinLock> guard; |
| 96 | std::unique_ptr<Core::ARM_Interface> arm_interface; | ||
| 77 | }; | 97 | }; |
| 78 | 98 | ||
| 79 | } // namespace Kernel | 99 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ff9d9248b..b905b486a 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <bitset> | 6 | #include <bitset> |
| 7 | #include <ctime> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <random> | 9 | #include <random> |
| 9 | #include "common/alignment.h" | 10 | #include "common/alignment.h" |
| @@ -14,13 +15,13 @@ | |||
| 14 | #include "core/file_sys/program_metadata.h" | 15 | #include "core/file_sys/program_metadata.h" |
| 15 | #include "core/hle/kernel/code_set.h" | 16 | #include "core/hle/kernel/code_set.h" |
| 16 | #include "core/hle/kernel/errors.h" | 17 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/k_scheduler.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/memory/memory_block_manager.h" | 20 | #include "core/hle/kernel/memory/memory_block_manager.h" |
| 19 | #include "core/hle/kernel/memory/page_table.h" | 21 | #include "core/hle/kernel/memory/page_table.h" |
| 20 | #include "core/hle/kernel/memory/slab_heap.h" | 22 | #include "core/hle/kernel/memory/slab_heap.h" |
| 21 | #include "core/hle/kernel/process.h" | 23 | #include "core/hle/kernel/process.h" |
| 22 | #include "core/hle/kernel/resource_limit.h" | 24 | #include "core/hle/kernel/resource_limit.h" |
| 23 | #include "core/hle/kernel/scheduler.h" | ||
| 24 | #include "core/hle/kernel/thread.h" | 25 | #include "core/hle/kernel/thread.h" |
| 25 | #include "core/hle/lock.h" | 26 | #include "core/hle/lock.h" |
| 26 | #include "core/memory.h" | 27 | #include "core/memory.h" |
| @@ -53,7 +54,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, | |||
| 53 | auto& kernel = system.Kernel(); | 54 | auto& kernel = system.Kernel(); |
| 54 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires | 55 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires |
| 55 | { | 56 | { |
| 56 | SchedulerLock lock{kernel}; | 57 | KScopedSchedulerLock lock{kernel}; |
| 57 | thread->SetStatus(ThreadStatus::Ready); | 58 | thread->SetStatus(ThreadStatus::Ready); |
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| @@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 123 | : kernel.CreateNewUserProcessID(); | 124 | : kernel.CreateNewUserProcessID(); |
| 124 | process->capabilities.InitializeForMetadatalessProcess(); | 125 | process->capabilities.InitializeForMetadatalessProcess(); |
| 125 | 126 | ||
| 126 | std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0)); | 127 | std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); |
| 127 | std::uniform_int_distribution<u64> distribution; | 128 | std::uniform_int_distribution<u64> distribution; |
| 128 | std::generate(process->random_entropy.begin(), process->random_entropy.end(), | 129 | std::generate(process->random_entropy.begin(), process->random_entropy.end(), |
| 129 | [&] { return distribution(rng); }); | 130 | [&] { return distribution(rng); }); |
| @@ -212,7 +213,7 @@ void Process::UnregisterThread(const Thread* thread) { | |||
| 212 | } | 213 | } |
| 213 | 214 | ||
| 214 | ResultCode Process::ClearSignalState() { | 215 | ResultCode Process::ClearSignalState() { |
| 215 | SchedulerLock lock(system.Kernel()); | 216 | KScopedSchedulerLock lock(system.Kernel()); |
| 216 | if (status == ProcessStatus::Exited) { | 217 | if (status == ProcessStatus::Exited) { |
| 217 | LOG_ERROR(Kernel, "called on a terminated process instance."); | 218 | LOG_ERROR(Kernel, "called on a terminated process instance."); |
| 218 | return ERR_INVALID_STATE; | 219 | return ERR_INVALID_STATE; |
| @@ -313,7 +314,7 @@ void Process::PrepareForTermination() { | |||
| 313 | if (thread->GetOwnerProcess() != this) | 314 | if (thread->GetOwnerProcess() != this) |
| 314 | continue; | 315 | continue; |
| 315 | 316 | ||
| 316 | if (thread.get() == system.CurrentScheduler().GetCurrentThread()) | 317 | if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread()) |
| 317 | continue; | 318 | continue; |
| 318 | 319 | ||
| 319 | // TODO(Subv): When are the other running/ready threads terminated? | 320 | // TODO(Subv): When are the other running/ready threads terminated? |
| @@ -324,7 +325,7 @@ void Process::PrepareForTermination() { | |||
| 324 | } | 325 | } |
| 325 | }; | 326 | }; |
| 326 | 327 | ||
| 327 | stop_threads(system.GlobalScheduler().GetThreadList()); | 328 | stop_threads(system.GlobalSchedulerContext().GetThreadList()); |
| 328 | 329 | ||
| 329 | FreeTLSRegion(tls_region_address); | 330 | FreeTLSRegion(tls_region_address); |
| 330 | tls_region_address = 0; | 331 | tls_region_address = 0; |
| @@ -346,7 +347,7 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) { | |||
| 346 | } | 347 | } |
| 347 | 348 | ||
| 348 | VAddr Process::CreateTLSRegion() { | 349 | VAddr Process::CreateTLSRegion() { |
| 349 | SchedulerLock lock(system.Kernel()); | 350 | KScopedSchedulerLock lock(system.Kernel()); |
| 350 | if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; | 351 | if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; |
| 351 | tls_page_iter != tls_pages.cend()) { | 352 | tls_page_iter != tls_pages.cend()) { |
| 352 | return *tls_page_iter->ReserveSlot(); | 353 | return *tls_page_iter->ReserveSlot(); |
| @@ -377,7 +378,7 @@ VAddr Process::CreateTLSRegion() { | |||
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | void Process::FreeTLSRegion(VAddr tls_address) { | 380 | void Process::FreeTLSRegion(VAddr tls_address) { |
| 380 | SchedulerLock lock(system.Kernel()); | 381 | KScopedSchedulerLock lock(system.Kernel()); |
| 381 | const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); | 382 | const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); |
| 382 | auto iter = | 383 | auto iter = |
| 383 | std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { | 384 | std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index f45cb5674..e412e58aa 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -216,6 +216,16 @@ public: | |||
| 216 | total_process_running_time_ticks += ticks; | 216 | total_process_running_time_ticks += ticks; |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /// Gets the process schedule count, used for thread yelding | ||
| 220 | s64 GetScheduledCount() const { | ||
| 221 | return schedule_count; | ||
| 222 | } | ||
| 223 | |||
| 224 | /// Increments the process schedule count, used for thread yielding. | ||
| 225 | void IncrementScheduledCount() { | ||
| 226 | ++schedule_count; | ||
| 227 | } | ||
| 228 | |||
| 219 | /// Gets 8 bytes of random data for svcGetInfo RandomEntropy | 229 | /// Gets 8 bytes of random data for svcGetInfo RandomEntropy |
| 220 | u64 GetRandomEntropy(std::size_t index) const { | 230 | u64 GetRandomEntropy(std::size_t index) const { |
| 221 | return random_entropy.at(index); | 231 | return random_entropy.at(index); |
| @@ -397,6 +407,9 @@ private: | |||
| 397 | /// Name of this process | 407 | /// Name of this process |
| 398 | std::string name; | 408 | std::string name; |
| 399 | 409 | ||
| 410 | /// Schedule count of this process | ||
| 411 | s64 schedule_count{}; | ||
| 412 | |||
| 400 | /// System context | 413 | /// System context |
| 401 | Core::System& system; | 414 | Core::System& system; |
| 402 | }; | 415 | }; |
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 63880f13d..0f128c586 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp | |||
| @@ -199,7 +199,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s | |||
| 199 | break; | 199 | break; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | LOG_ERROR(Kernel, "Invalid capability type! type={}", static_cast<u32>(type)); | 202 | LOG_ERROR(Kernel, "Invalid capability type! type={}", type); |
| 203 | return ERR_INVALID_CAPABILITY_DESCRIPTOR; | 203 | return ERR_INVALID_CAPABILITY_DESCRIPTOR; |
| 204 | } | 204 | } |
| 205 | 205 | ||
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 6e286419e..cea262ce0 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp | |||
| @@ -6,10 +6,10 @@ | |||
| 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/hle/kernel/errors.h" | 8 | #include "core/hle/kernel/errors.h" |
| 9 | #include "core/hle/kernel/k_scheduler.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 11 | #include "core/hle/kernel/readable_event.h" | 12 | #include "core/hle/kernel/readable_event.h" |
| 12 | #include "core/hle/kernel/scheduler.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | 13 | #include "core/hle/kernel/thread.h" |
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| @@ -39,7 +39,7 @@ void ReadableEvent::Clear() { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ResultCode ReadableEvent::Reset() { | 41 | ResultCode ReadableEvent::Reset() { |
| 42 | SchedulerLock lock(kernel); | 42 | KScopedSchedulerLock lock(kernel); |
| 43 | if (!is_signaled) { | 43 | if (!is_signaled) { |
| 44 | LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", | 44 | LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", |
| 45 | GetObjectId(), GetTypeName(), GetName()); | 45 | GetObjectId(), GetTypeName(), GetName()); |
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 212e442f4..7bf50339d 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp | |||
| @@ -65,8 +65,8 @@ ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) { | |||
| 65 | limit[index] = value; | 65 | limit[index] = value; |
| 66 | return RESULT_SUCCESS; | 66 | return RESULT_SUCCESS; |
| 67 | } else { | 67 | } else { |
| 68 | LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", | 68 | LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource, |
| 69 | static_cast<u32>(resource), value, index); | 69 | value, index); |
| 70 | return ERR_INVALID_STATE; | 70 | return ERR_INVALID_STATE; |
| 71 | } | 71 | } |
| 72 | } | 72 | } |
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp deleted file mode 100644 index 5cbd3b912..000000000 --- a/src/core/hle/kernel/scheduler.cpp +++ /dev/null | |||
| @@ -1,849 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | // | ||
| 5 | // SelectThreads, Yield functions originally by TuxSH. | ||
| 6 | // licensed under GPLv2 or later under exception provided by the author. | ||
| 7 | |||
| 8 | #include <algorithm> | ||
| 9 | #include <mutex> | ||
| 10 | #include <set> | ||
| 11 | #include <unordered_set> | ||
| 12 | #include <utility> | ||
| 13 | |||
| 14 | #include "common/assert.h" | ||
| 15 | #include "common/bit_util.h" | ||
| 16 | #include "common/fiber.h" | ||
| 17 | #include "common/logging/log.h" | ||
| 18 | #include "core/arm/arm_interface.h" | ||
| 19 | #include "core/core.h" | ||
| 20 | #include "core/core_timing.h" | ||
| 21 | #include "core/cpu_manager.h" | ||
| 22 | #include "core/hle/kernel/kernel.h" | ||
| 23 | #include "core/hle/kernel/physical_core.h" | ||
| 24 | #include "core/hle/kernel/process.h" | ||
| 25 | #include "core/hle/kernel/scheduler.h" | ||
| 26 | #include "core/hle/kernel/time_manager.h" | ||
| 27 | |||
| 28 | namespace Kernel { | ||
| 29 | |||
| 30 | GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {} | ||
| 31 | |||
| 32 | GlobalScheduler::~GlobalScheduler() = default; | ||
| 33 | |||
| 34 | void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) { | ||
| 35 | std::scoped_lock lock{global_list_guard}; | ||
| 36 | thread_list.push_back(std::move(thread)); | ||
| 37 | } | ||
| 38 | |||
| 39 | void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) { | ||
| 40 | std::scoped_lock lock{global_list_guard}; | ||
| 41 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | ||
| 42 | thread_list.end()); | ||
| 43 | } | ||
| 44 | |||
| 45 | u32 GlobalScheduler::SelectThreads() { | ||
| 46 | ASSERT(is_locked); | ||
| 47 | const auto update_thread = [](Thread* thread, Scheduler& sched) { | ||
| 48 | std::scoped_lock lock{sched.guard}; | ||
| 49 | if (thread != sched.selected_thread_set.get()) { | ||
| 50 | if (thread == nullptr) { | ||
| 51 | ++sched.idle_selection_count; | ||
| 52 | } | ||
| 53 | sched.selected_thread_set = SharedFrom(thread); | ||
| 54 | } | ||
| 55 | const bool reschedule_pending = | ||
| 56 | sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread); | ||
| 57 | sched.is_context_switch_pending = reschedule_pending; | ||
| 58 | std::atomic_thread_fence(std::memory_order_seq_cst); | ||
| 59 | return reschedule_pending; | ||
| 60 | }; | ||
| 61 | if (!is_reselection_pending.load()) { | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | std::array<Thread*, Core::Hardware::NUM_CPU_CORES> top_threads{}; | ||
| 65 | |||
| 66 | u32 idle_cores{}; | ||
| 67 | |||
| 68 | // Step 1: Get top thread in schedule queue. | ||
| 69 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 70 | Thread* top_thread = | ||
| 71 | scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); | ||
| 72 | if (top_thread != nullptr) { | ||
| 73 | // TODO(Blinkhawk): Implement Thread Pinning | ||
| 74 | } else { | ||
| 75 | idle_cores |= (1ul << core); | ||
| 76 | } | ||
| 77 | top_threads[core] = top_thread; | ||
| 78 | } | ||
| 79 | |||
| 80 | while (idle_cores != 0) { | ||
| 81 | u32 core_id = Common::CountTrailingZeroes32(idle_cores); | ||
| 82 | |||
| 83 | if (!suggested_queue[core_id].empty()) { | ||
| 84 | std::array<s32, Core::Hardware::NUM_CPU_CORES> migration_candidates{}; | ||
| 85 | std::size_t num_candidates = 0; | ||
| 86 | auto iter = suggested_queue[core_id].begin(); | ||
| 87 | Thread* suggested = nullptr; | ||
| 88 | // Step 2: Try selecting a suggested thread. | ||
| 89 | while (iter != suggested_queue[core_id].end()) { | ||
| 90 | suggested = *iter; | ||
| 91 | iter++; | ||
| 92 | s32 suggested_core_id = suggested->GetProcessorID(); | ||
| 93 | Thread* top_thread = | ||
| 94 | suggested_core_id >= 0 ? top_threads[suggested_core_id] : nullptr; | ||
| 95 | if (top_thread != suggested) { | ||
| 96 | if (top_thread != nullptr && | ||
| 97 | top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) { | ||
| 98 | suggested = nullptr; | ||
| 99 | break; | ||
| 100 | // There's a too high thread to do core migration, cancel | ||
| 101 | } | ||
| 102 | TransferToCore(suggested->GetPriority(), static_cast<s32>(core_id), suggested); | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | suggested = nullptr; | ||
| 106 | migration_candidates[num_candidates++] = suggested_core_id; | ||
| 107 | } | ||
| 108 | // Step 3: Select a suggested thread from another core | ||
| 109 | if (suggested == nullptr) { | ||
| 110 | for (std::size_t i = 0; i < num_candidates; i++) { | ||
| 111 | s32 candidate_core = migration_candidates[i]; | ||
| 112 | suggested = top_threads[candidate_core]; | ||
| 113 | auto it = scheduled_queue[candidate_core].begin(); | ||
| 114 | it++; | ||
| 115 | Thread* next = it != scheduled_queue[candidate_core].end() ? *it : nullptr; | ||
| 116 | if (next != nullptr) { | ||
| 117 | TransferToCore(suggested->GetPriority(), static_cast<s32>(core_id), | ||
| 118 | suggested); | ||
| 119 | top_threads[candidate_core] = next; | ||
| 120 | break; | ||
| 121 | } else { | ||
| 122 | suggested = nullptr; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | top_threads[core_id] = suggested; | ||
| 127 | } | ||
| 128 | |||
| 129 | idle_cores &= ~(1ul << core_id); | ||
| 130 | } | ||
| 131 | u32 cores_needing_context_switch{}; | ||
| 132 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 133 | Scheduler& sched = kernel.Scheduler(core); | ||
| 134 | ASSERT(top_threads[core] == nullptr || | ||
| 135 | static_cast<u32>(top_threads[core]->GetProcessorID()) == core); | ||
| 136 | if (update_thread(top_threads[core], sched)) { | ||
| 137 | cores_needing_context_switch |= (1ul << core); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | return cores_needing_context_switch; | ||
| 141 | } | ||
| 142 | |||
| 143 | bool GlobalScheduler::YieldThread(Thread* yielding_thread) { | ||
| 144 | ASSERT(is_locked); | ||
| 145 | // Note: caller should use critical section, etc. | ||
| 146 | if (!yielding_thread->IsRunnable()) { | ||
| 147 | // Normally this case shouldn't happen except for SetThreadActivity. | ||
| 148 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 149 | return false; | ||
| 150 | } | ||
| 151 | const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID()); | ||
| 152 | const u32 priority = yielding_thread->GetPriority(); | ||
| 153 | |||
| 154 | // Yield the thread | ||
| 155 | Reschedule(priority, core_id, yielding_thread); | ||
| 156 | const Thread* const winner = scheduled_queue[core_id].front(); | ||
| 157 | if (kernel.GetCurrentHostThreadID() != core_id) { | ||
| 158 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 159 | } | ||
| 160 | |||
| 161 | return AskForReselectionOrMarkRedundant(yielding_thread, winner); | ||
| 162 | } | ||
| 163 | |||
| 164 | bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { | ||
| 165 | ASSERT(is_locked); | ||
| 166 | // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, | ||
| 167 | // etc. | ||
| 168 | if (!yielding_thread->IsRunnable()) { | ||
| 169 | // Normally this case shouldn't happen except for SetThreadActivity. | ||
| 170 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 171 | return false; | ||
| 172 | } | ||
| 173 | const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID()); | ||
| 174 | const u32 priority = yielding_thread->GetPriority(); | ||
| 175 | |||
| 176 | // Yield the thread | ||
| 177 | Reschedule(priority, core_id, yielding_thread); | ||
| 178 | |||
| 179 | std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads; | ||
| 180 | for (std::size_t i = 0; i < current_threads.size(); i++) { | ||
| 181 | current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); | ||
| 182 | } | ||
| 183 | |||
| 184 | Thread* next_thread = scheduled_queue[core_id].front(priority); | ||
| 185 | Thread* winner = nullptr; | ||
| 186 | for (auto& thread : suggested_queue[core_id]) { | ||
| 187 | const s32 source_core = thread->GetProcessorID(); | ||
| 188 | if (source_core >= 0) { | ||
| 189 | if (current_threads[source_core] != nullptr) { | ||
| 190 | if (thread == current_threads[source_core] || | ||
| 191 | current_threads[source_core]->GetPriority() < min_regular_priority) { | ||
| 192 | continue; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | if (next_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks() || | ||
| 197 | next_thread->GetPriority() < thread->GetPriority()) { | ||
| 198 | if (thread->GetPriority() <= priority) { | ||
| 199 | winner = thread; | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | if (winner != nullptr) { | ||
| 206 | if (winner != yielding_thread) { | ||
| 207 | TransferToCore(winner->GetPriority(), s32(core_id), winner); | ||
| 208 | } | ||
| 209 | } else { | ||
| 210 | winner = next_thread; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (kernel.GetCurrentHostThreadID() != core_id) { | ||
| 214 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 215 | } | ||
| 216 | |||
| 217 | return AskForReselectionOrMarkRedundant(yielding_thread, winner); | ||
| 218 | } | ||
| 219 | |||
| 220 | bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { | ||
| 221 | ASSERT(is_locked); | ||
| 222 | // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, | ||
| 223 | // etc. | ||
| 224 | if (!yielding_thread->IsRunnable()) { | ||
| 225 | // Normally this case shouldn't happen except for SetThreadActivity. | ||
| 226 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 227 | return false; | ||
| 228 | } | ||
| 229 | Thread* winner = nullptr; | ||
| 230 | const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID()); | ||
| 231 | |||
| 232 | // Remove the thread from its scheduled mlq, put it on the corresponding "suggested" one instead | ||
| 233 | TransferToCore(yielding_thread->GetPriority(), -1, yielding_thread); | ||
| 234 | |||
| 235 | // If the core is idle, perform load balancing, excluding the threads that have just used this | ||
| 236 | // function... | ||
| 237 | if (scheduled_queue[core_id].empty()) { | ||
| 238 | // Here, "current_threads" is calculated after the ""yield"", unlike yield -1 | ||
| 239 | std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads; | ||
| 240 | for (std::size_t i = 0; i < current_threads.size(); i++) { | ||
| 241 | current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); | ||
| 242 | } | ||
| 243 | for (auto& thread : suggested_queue[core_id]) { | ||
| 244 | const s32 source_core = thread->GetProcessorID(); | ||
| 245 | if (source_core < 0 || thread == current_threads[source_core]) { | ||
| 246 | continue; | ||
| 247 | } | ||
| 248 | if (current_threads[source_core] == nullptr || | ||
| 249 | current_threads[source_core]->GetPriority() >= min_regular_priority) { | ||
| 250 | winner = thread; | ||
| 251 | } | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | if (winner != nullptr) { | ||
| 255 | if (winner != yielding_thread) { | ||
| 256 | TransferToCore(winner->GetPriority(), static_cast<s32>(core_id), winner); | ||
| 257 | } | ||
| 258 | } else { | ||
| 259 | winner = yielding_thread; | ||
| 260 | } | ||
| 261 | } else { | ||
| 262 | winner = scheduled_queue[core_id].front(); | ||
| 263 | } | ||
| 264 | |||
| 265 | if (kernel.GetCurrentHostThreadID() != core_id) { | ||
| 266 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 267 | } | ||
| 268 | |||
| 269 | return AskForReselectionOrMarkRedundant(yielding_thread, winner); | ||
| 270 | } | ||
| 271 | |||
| 272 | void GlobalScheduler::PreemptThreads() { | ||
| 273 | ASSERT(is_locked); | ||
| 274 | for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||
| 275 | const u32 priority = preemption_priorities[core_id]; | ||
| 276 | |||
| 277 | if (scheduled_queue[core_id].size(priority) > 0) { | ||
| 278 | if (scheduled_queue[core_id].size(priority) > 1) { | ||
| 279 | scheduled_queue[core_id].front(priority)->IncrementYieldCount(); | ||
| 280 | } | ||
| 281 | scheduled_queue[core_id].yield(priority); | ||
| 282 | if (scheduled_queue[core_id].size(priority) > 1) { | ||
| 283 | scheduled_queue[core_id].front(priority)->IncrementYieldCount(); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | Thread* current_thread = | ||
| 288 | scheduled_queue[core_id].empty() ? nullptr : scheduled_queue[core_id].front(); | ||
| 289 | Thread* winner = nullptr; | ||
| 290 | for (auto& thread : suggested_queue[core_id]) { | ||
| 291 | const s32 source_core = thread->GetProcessorID(); | ||
| 292 | if (thread->GetPriority() != priority) { | ||
| 293 | continue; | ||
| 294 | } | ||
| 295 | if (source_core >= 0) { | ||
| 296 | Thread* next_thread = scheduled_queue[source_core].empty() | ||
| 297 | ? nullptr | ||
| 298 | : scheduled_queue[source_core].front(); | ||
| 299 | if (next_thread != nullptr && next_thread->GetPriority() < 2) { | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | if (next_thread == thread) { | ||
| 303 | continue; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | if (current_thread != nullptr && | ||
| 307 | current_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks()) { | ||
| 308 | winner = thread; | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | if (winner != nullptr) { | ||
| 314 | TransferToCore(winner->GetPriority(), s32(core_id), winner); | ||
| 315 | current_thread = | ||
| 316 | winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread; | ||
| 317 | } | ||
| 318 | |||
| 319 | if (current_thread != nullptr && current_thread->GetPriority() > priority) { | ||
| 320 | for (auto& thread : suggested_queue[core_id]) { | ||
| 321 | const s32 source_core = thread->GetProcessorID(); | ||
| 322 | if (thread->GetPriority() < priority) { | ||
| 323 | continue; | ||
| 324 | } | ||
| 325 | if (source_core >= 0) { | ||
| 326 | Thread* next_thread = scheduled_queue[source_core].empty() | ||
| 327 | ? nullptr | ||
| 328 | : scheduled_queue[source_core].front(); | ||
| 329 | if (next_thread != nullptr && next_thread->GetPriority() < 2) { | ||
| 330 | break; | ||
| 331 | } | ||
| 332 | if (next_thread == thread) { | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | if (current_thread != nullptr && | ||
| 337 | current_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks()) { | ||
| 338 | winner = thread; | ||
| 339 | break; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | if (winner != nullptr) { | ||
| 344 | TransferToCore(winner->GetPriority(), s32(core_id), winner); | ||
| 345 | current_thread = winner; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, | ||
| 354 | Core::EmuThreadHandle global_thread) { | ||
| 355 | u32 current_core = global_thread.host_handle; | ||
| 356 | bool must_context_switch = global_thread.guest_handle != InvalidHandle && | ||
| 357 | (current_core < Core::Hardware::NUM_CPU_CORES); | ||
| 358 | while (cores_pending_reschedule != 0) { | ||
| 359 | u32 core = Common::CountTrailingZeroes32(cores_pending_reschedule); | ||
| 360 | ASSERT(core < Core::Hardware::NUM_CPU_CORES); | ||
| 361 | if (!must_context_switch || core != current_core) { | ||
| 362 | auto& phys_core = kernel.PhysicalCore(core); | ||
| 363 | phys_core.Interrupt(); | ||
| 364 | } else { | ||
| 365 | must_context_switch = true; | ||
| 366 | } | ||
| 367 | cores_pending_reschedule &= ~(1ul << core); | ||
| 368 | } | ||
| 369 | if (must_context_switch) { | ||
| 370 | auto& core_scheduler = kernel.CurrentScheduler(); | ||
| 371 | kernel.ExitSVCProfile(); | ||
| 372 | core_scheduler.TryDoContextSwitch(); | ||
| 373 | kernel.EnterSVCProfile(); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { | ||
| 378 | ASSERT(is_locked); | ||
| 379 | suggested_queue[core].add(thread, priority); | ||
| 380 | } | ||
| 381 | |||
| 382 | void GlobalScheduler::Unsuggest(u32 priority, std::size_t core, Thread* thread) { | ||
| 383 | ASSERT(is_locked); | ||
| 384 | suggested_queue[core].remove(thread, priority); | ||
| 385 | } | ||
| 386 | |||
| 387 | void GlobalScheduler::Schedule(u32 priority, std::size_t core, Thread* thread) { | ||
| 388 | ASSERT(is_locked); | ||
| 389 | ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); | ||
| 390 | scheduled_queue[core].add(thread, priority); | ||
| 391 | } | ||
| 392 | |||
| 393 | void GlobalScheduler::SchedulePrepend(u32 priority, std::size_t core, Thread* thread) { | ||
| 394 | ASSERT(is_locked); | ||
| 395 | ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); | ||
| 396 | scheduled_queue[core].add(thread, priority, false); | ||
| 397 | } | ||
| 398 | |||
| 399 | void GlobalScheduler::Reschedule(u32 priority, std::size_t core, Thread* thread) { | ||
| 400 | ASSERT(is_locked); | ||
| 401 | scheduled_queue[core].remove(thread, priority); | ||
| 402 | scheduled_queue[core].add(thread, priority); | ||
| 403 | } | ||
| 404 | |||
| 405 | void GlobalScheduler::Unschedule(u32 priority, std::size_t core, Thread* thread) { | ||
| 406 | ASSERT(is_locked); | ||
| 407 | scheduled_queue[core].remove(thread, priority); | ||
| 408 | } | ||
| 409 | |||
| 410 | void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* thread) { | ||
| 411 | ASSERT(is_locked); | ||
| 412 | const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; | ||
| 413 | const s32 source_core = thread->GetProcessorID(); | ||
| 414 | if (source_core == destination_core || !schedulable) { | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | thread->SetProcessorID(destination_core); | ||
| 418 | if (source_core >= 0) { | ||
| 419 | Unschedule(priority, static_cast<u32>(source_core), thread); | ||
| 420 | } | ||
| 421 | if (destination_core >= 0) { | ||
| 422 | Unsuggest(priority, static_cast<u32>(destination_core), thread); | ||
| 423 | Schedule(priority, static_cast<u32>(destination_core), thread); | ||
| 424 | } | ||
| 425 | if (source_core >= 0) { | ||
| 426 | Suggest(priority, static_cast<u32>(source_core), thread); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, | ||
| 431 | const Thread* winner) { | ||
| 432 | if (current_thread == winner) { | ||
| 433 | current_thread->IncrementYieldCount(); | ||
| 434 | return true; | ||
| 435 | } else { | ||
| 436 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 437 | return false; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { | ||
| 442 | if (old_flags == thread->scheduling_state) { | ||
| 443 | return; | ||
| 444 | } | ||
| 445 | ASSERT(is_locked); | ||
| 446 | |||
| 447 | if (old_flags == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 448 | // In this case the thread was running, now it's pausing/exitting | ||
| 449 | if (thread->processor_id >= 0) { | ||
| 450 | Unschedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread); | ||
| 451 | } | ||
| 452 | |||
| 453 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 454 | if (core != static_cast<u32>(thread->processor_id) && | ||
| 455 | ((thread->affinity_mask >> core) & 1) != 0) { | ||
| 456 | Unsuggest(thread->current_priority, core, thread); | ||
| 457 | } | ||
| 458 | } | ||
| 459 | } else if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 460 | // The thread is now set to running from being stopped | ||
| 461 | if (thread->processor_id >= 0) { | ||
| 462 | Schedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread); | ||
| 463 | } | ||
| 464 | |||
| 465 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 466 | if (core != static_cast<u32>(thread->processor_id) && | ||
| 467 | ((thread->affinity_mask >> core) & 1) != 0) { | ||
| 468 | Suggest(thread->current_priority, core, thread); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | SetReselectionPending(); | ||
| 474 | } | ||
| 475 | |||
| 476 | void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { | ||
| 477 | if (thread->scheduling_state != static_cast<u32>(ThreadSchedStatus::Runnable)) { | ||
| 478 | return; | ||
| 479 | } | ||
| 480 | ASSERT(is_locked); | ||
| 481 | if (thread->processor_id >= 0) { | ||
| 482 | Unschedule(old_priority, static_cast<u32>(thread->processor_id), thread); | ||
| 483 | } | ||
| 484 | |||
| 485 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 486 | if (core != static_cast<u32>(thread->processor_id) && | ||
| 487 | ((thread->affinity_mask >> core) & 1) != 0) { | ||
| 488 | Unsuggest(old_priority, core, thread); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | if (thread->processor_id >= 0) { | ||
| 493 | if (thread == kernel.CurrentScheduler().GetCurrentThread()) { | ||
| 494 | SchedulePrepend(thread->current_priority, static_cast<u32>(thread->processor_id), | ||
| 495 | thread); | ||
| 496 | } else { | ||
| 497 | Schedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread); | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 502 | if (core != static_cast<u32>(thread->processor_id) && | ||
| 503 | ((thread->affinity_mask >> core) & 1) != 0) { | ||
| 504 | Suggest(thread->current_priority, core, thread); | ||
| 505 | } | ||
| 506 | } | ||
| 507 | thread->IncrementYieldCount(); | ||
| 508 | SetReselectionPending(); | ||
| 509 | } | ||
| 510 | |||
| 511 | void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, | ||
| 512 | s32 old_core) { | ||
| 513 | if (thread->scheduling_state != static_cast<u32>(ThreadSchedStatus::Runnable) || | ||
| 514 | thread->current_priority >= THREADPRIO_COUNT) { | ||
| 515 | return; | ||
| 516 | } | ||
| 517 | ASSERT(is_locked); | ||
| 518 | |||
| 519 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 520 | if (((old_affinity_mask >> core) & 1) != 0) { | ||
| 521 | if (core == static_cast<u32>(old_core)) { | ||
| 522 | Unschedule(thread->current_priority, core, thread); | ||
| 523 | } else { | ||
| 524 | Unsuggest(thread->current_priority, core, thread); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 530 | if (((thread->affinity_mask >> core) & 1) != 0) { | ||
| 531 | if (core == static_cast<u32>(thread->processor_id)) { | ||
| 532 | Schedule(thread->current_priority, core, thread); | ||
| 533 | } else { | ||
| 534 | Suggest(thread->current_priority, core, thread); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | thread->IncrementYieldCount(); | ||
| 540 | SetReselectionPending(); | ||
| 541 | } | ||
| 542 | |||
| 543 | void GlobalScheduler::Shutdown() { | ||
| 544 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | ||
| 545 | scheduled_queue[core].clear(); | ||
| 546 | suggested_queue[core].clear(); | ||
| 547 | } | ||
| 548 | thread_list.clear(); | ||
| 549 | } | ||
| 550 | |||
| 551 | void GlobalScheduler::Lock() { | ||
| 552 | Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID(); | ||
| 553 | ASSERT(!current_thread.IsInvalid()); | ||
| 554 | if (current_thread == current_owner) { | ||
| 555 | ++scope_lock; | ||
| 556 | } else { | ||
| 557 | inner_lock.lock(); | ||
| 558 | is_locked = true; | ||
| 559 | current_owner = current_thread; | ||
| 560 | ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle()); | ||
| 561 | scope_lock = 1; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | void GlobalScheduler::Unlock() { | ||
| 566 | if (--scope_lock != 0) { | ||
| 567 | ASSERT(scope_lock > 0); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | u32 cores_pending_reschedule = SelectThreads(); | ||
| 571 | Core::EmuThreadHandle leaving_thread = current_owner; | ||
| 572 | current_owner = Core::EmuThreadHandle::InvalidHandle(); | ||
| 573 | scope_lock = 1; | ||
| 574 | is_locked = false; | ||
| 575 | inner_lock.unlock(); | ||
| 576 | EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); | ||
| 577 | } | ||
| 578 | |||
| 579 | Scheduler::Scheduler(Core::System& system, std::size_t core_id) : system(system), core_id(core_id) { | ||
| 580 | switch_fiber = std::make_shared<Common::Fiber>(std::function<void(void*)>(OnSwitch), this); | ||
| 581 | } | ||
| 582 | |||
| 583 | Scheduler::~Scheduler() = default; | ||
| 584 | |||
| 585 | bool Scheduler::HaveReadyThreads() const { | ||
| 586 | return system.GlobalScheduler().HaveReadyThreads(core_id); | ||
| 587 | } | ||
| 588 | |||
| 589 | Thread* Scheduler::GetCurrentThread() const { | ||
| 590 | if (current_thread) { | ||
| 591 | return current_thread.get(); | ||
| 592 | } | ||
| 593 | return idle_thread.get(); | ||
| 594 | } | ||
| 595 | |||
| 596 | Thread* Scheduler::GetSelectedThread() const { | ||
| 597 | return selected_thread.get(); | ||
| 598 | } | ||
| 599 | |||
| 600 | u64 Scheduler::GetLastContextSwitchTicks() const { | ||
| 601 | return last_context_switch_time; | ||
| 602 | } | ||
| 603 | |||
| 604 | void Scheduler::TryDoContextSwitch() { | ||
| 605 | auto& phys_core = system.Kernel().CurrentPhysicalCore(); | ||
| 606 | if (phys_core.IsInterrupted()) { | ||
| 607 | phys_core.ClearInterrupt(); | ||
| 608 | } | ||
| 609 | guard.lock(); | ||
| 610 | if (is_context_switch_pending) { | ||
| 611 | SwitchContext(); | ||
| 612 | } else { | ||
| 613 | guard.unlock(); | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | void Scheduler::OnThreadStart() { | ||
| 618 | SwitchContextStep2(); | ||
| 619 | } | ||
| 620 | |||
| 621 | void Scheduler::Unload() { | ||
| 622 | Thread* thread = current_thread.get(); | ||
| 623 | if (thread) { | ||
| 624 | thread->SetContinuousOnSVC(false); | ||
| 625 | thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 626 | thread->SetIsRunning(false); | ||
| 627 | if (!thread->IsHLEThread() && !thread->HasExited()) { | ||
| 628 | Core::ARM_Interface& cpu_core = thread->ArmInterface(); | ||
| 629 | cpu_core.SaveContext(thread->GetContext32()); | ||
| 630 | cpu_core.SaveContext(thread->GetContext64()); | ||
| 631 | // Save the TPIDR_EL0 system register in case it was modified. | ||
| 632 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); | ||
| 633 | cpu_core.ClearExclusiveState(); | ||
| 634 | } | ||
| 635 | thread->context_guard.unlock(); | ||
| 636 | } | ||
| 637 | } | ||
| 638 | |||
| 639 | void Scheduler::Reload() { | ||
| 640 | Thread* thread = current_thread.get(); | ||
| 641 | if (thread) { | ||
| 642 | ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, | ||
| 643 | "Thread must be runnable."); | ||
| 644 | |||
| 645 | // Cancel any outstanding wakeup events for this thread | ||
| 646 | thread->SetIsRunning(true); | ||
| 647 | thread->SetWasRunning(false); | ||
| 648 | thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 649 | |||
| 650 | auto* const thread_owner_process = thread->GetOwnerProcess(); | ||
| 651 | if (thread_owner_process != nullptr) { | ||
| 652 | system.Kernel().MakeCurrentProcess(thread_owner_process); | ||
| 653 | } | ||
| 654 | if (!thread->IsHLEThread()) { | ||
| 655 | Core::ARM_Interface& cpu_core = thread->ArmInterface(); | ||
| 656 | cpu_core.LoadContext(thread->GetContext32()); | ||
| 657 | cpu_core.LoadContext(thread->GetContext64()); | ||
| 658 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); | ||
| 659 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); | ||
| 660 | cpu_core.ChangeProcessorID(this->core_id); | ||
| 661 | cpu_core.ClearExclusiveState(); | ||
| 662 | } | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | void Scheduler::SwitchContextStep2() { | ||
| 667 | // Load context of new thread | ||
| 668 | if (selected_thread) { | ||
| 669 | ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, | ||
| 670 | "Thread must be runnable."); | ||
| 671 | |||
| 672 | // Cancel any outstanding wakeup events for this thread | ||
| 673 | selected_thread->SetIsRunning(true); | ||
| 674 | selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 675 | selected_thread->SetWasRunning(false); | ||
| 676 | |||
| 677 | auto* const thread_owner_process = current_thread->GetOwnerProcess(); | ||
| 678 | if (thread_owner_process != nullptr) { | ||
| 679 | system.Kernel().MakeCurrentProcess(thread_owner_process); | ||
| 680 | } | ||
| 681 | if (!selected_thread->IsHLEThread()) { | ||
| 682 | Core::ARM_Interface& cpu_core = selected_thread->ArmInterface(); | ||
| 683 | cpu_core.LoadContext(selected_thread->GetContext32()); | ||
| 684 | cpu_core.LoadContext(selected_thread->GetContext64()); | ||
| 685 | cpu_core.SetTlsAddress(selected_thread->GetTLSAddress()); | ||
| 686 | cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0()); | ||
| 687 | cpu_core.ChangeProcessorID(this->core_id); | ||
| 688 | cpu_core.ClearExclusiveState(); | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | TryDoContextSwitch(); | ||
| 693 | } | ||
| 694 | |||
| 695 | void Scheduler::SwitchContext() { | ||
| 696 | current_thread_prev = current_thread; | ||
| 697 | selected_thread = selected_thread_set; | ||
| 698 | Thread* previous_thread = current_thread_prev.get(); | ||
| 699 | Thread* new_thread = selected_thread.get(); | ||
| 700 | current_thread = selected_thread; | ||
| 701 | |||
| 702 | is_context_switch_pending = false; | ||
| 703 | |||
| 704 | if (new_thread == previous_thread) { | ||
| 705 | guard.unlock(); | ||
| 706 | return; | ||
| 707 | } | ||
| 708 | |||
| 709 | Process* const previous_process = system.Kernel().CurrentProcess(); | ||
| 710 | |||
| 711 | UpdateLastContextSwitchTime(previous_thread, previous_process); | ||
| 712 | |||
| 713 | // Save context for previous thread | ||
| 714 | if (previous_thread) { | ||
| 715 | if (new_thread != nullptr && new_thread->IsSuspendThread()) { | ||
| 716 | previous_thread->SetWasRunning(true); | ||
| 717 | } | ||
| 718 | previous_thread->SetContinuousOnSVC(false); | ||
| 719 | previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 720 | previous_thread->SetIsRunning(false); | ||
| 721 | if (!previous_thread->IsHLEThread() && !previous_thread->HasExited()) { | ||
| 722 | Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); | ||
| 723 | cpu_core.SaveContext(previous_thread->GetContext32()); | ||
| 724 | cpu_core.SaveContext(previous_thread->GetContext64()); | ||
| 725 | // Save the TPIDR_EL0 system register in case it was modified. | ||
| 726 | previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); | ||
| 727 | cpu_core.ClearExclusiveState(); | ||
| 728 | } | ||
| 729 | previous_thread->context_guard.unlock(); | ||
| 730 | } | ||
| 731 | |||
| 732 | std::shared_ptr<Common::Fiber>* old_context; | ||
| 733 | if (previous_thread != nullptr) { | ||
| 734 | old_context = &previous_thread->GetHostContext(); | ||
| 735 | } else { | ||
| 736 | old_context = &idle_thread->GetHostContext(); | ||
| 737 | } | ||
| 738 | guard.unlock(); | ||
| 739 | |||
| 740 | Common::Fiber::YieldTo(*old_context, switch_fiber); | ||
| 741 | /// When a thread wakes up, the scheduler may have changed to other in another core. | ||
| 742 | auto& next_scheduler = system.Kernel().CurrentScheduler(); | ||
| 743 | next_scheduler.SwitchContextStep2(); | ||
| 744 | } | ||
| 745 | |||
| 746 | void Scheduler::OnSwitch(void* this_scheduler) { | ||
| 747 | Scheduler* sched = static_cast<Scheduler*>(this_scheduler); | ||
| 748 | sched->SwitchToCurrent(); | ||
| 749 | } | ||
| 750 | |||
| 751 | void Scheduler::SwitchToCurrent() { | ||
| 752 | while (true) { | ||
| 753 | { | ||
| 754 | std::scoped_lock lock{guard}; | ||
| 755 | selected_thread = selected_thread_set; | ||
| 756 | current_thread = selected_thread; | ||
| 757 | is_context_switch_pending = false; | ||
| 758 | } | ||
| 759 | const auto is_switch_pending = [this] { | ||
| 760 | std::scoped_lock lock{guard}; | ||
| 761 | return is_context_switch_pending; | ||
| 762 | }; | ||
| 763 | do { | ||
| 764 | if (current_thread != nullptr && !current_thread->IsHLEThread()) { | ||
| 765 | current_thread->context_guard.lock(); | ||
| 766 | if (!current_thread->IsRunnable()) { | ||
| 767 | current_thread->context_guard.unlock(); | ||
| 768 | break; | ||
| 769 | } | ||
| 770 | if (current_thread->GetProcessorID() != core_id) { | ||
| 771 | current_thread->context_guard.unlock(); | ||
| 772 | break; | ||
| 773 | } | ||
| 774 | } | ||
| 775 | std::shared_ptr<Common::Fiber>* next_context; | ||
| 776 | if (current_thread != nullptr) { | ||
| 777 | next_context = ¤t_thread->GetHostContext(); | ||
| 778 | } else { | ||
| 779 | next_context = &idle_thread->GetHostContext(); | ||
| 780 | } | ||
| 781 | Common::Fiber::YieldTo(switch_fiber, *next_context); | ||
| 782 | } while (!is_switch_pending()); | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | ||
| 787 | const u64 prev_switch_ticks = last_context_switch_time; | ||
| 788 | const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); | ||
| 789 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; | ||
| 790 | |||
| 791 | if (thread != nullptr) { | ||
| 792 | thread->UpdateCPUTimeTicks(update_ticks); | ||
| 793 | } | ||
| 794 | |||
| 795 | if (process != nullptr) { | ||
| 796 | process->UpdateCPUTimeTicks(update_ticks); | ||
| 797 | } | ||
| 798 | |||
| 799 | last_context_switch_time = most_recent_switch_ticks; | ||
| 800 | } | ||
| 801 | |||
| 802 | void Scheduler::Initialize() { | ||
| 803 | std::string name = "Idle Thread Id:" + std::to_string(core_id); | ||
| 804 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); | ||
| 805 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | ||
| 806 | ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); | ||
| 807 | auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, | ||
| 808 | nullptr, std::move(init_func), init_func_parameter); | ||
| 809 | idle_thread = std::move(thread_res).Unwrap(); | ||
| 810 | } | ||
| 811 | |||
| 812 | void Scheduler::Shutdown() { | ||
| 813 | current_thread = nullptr; | ||
| 814 | selected_thread = nullptr; | ||
| 815 | } | ||
| 816 | |||
| 817 | SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} { | ||
| 818 | kernel.GlobalScheduler().Lock(); | ||
| 819 | } | ||
| 820 | |||
| 821 | SchedulerLock::~SchedulerLock() { | ||
| 822 | kernel.GlobalScheduler().Unlock(); | ||
| 823 | } | ||
| 824 | |||
| 825 | SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, | ||
| 826 | Thread* time_task, s64 nanoseconds) | ||
| 827 | : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{ | ||
| 828 | nanoseconds} { | ||
| 829 | event_handle = InvalidHandle; | ||
| 830 | } | ||
| 831 | |||
| 832 | SchedulerLockAndSleep::~SchedulerLockAndSleep() { | ||
| 833 | if (sleep_cancelled) { | ||
| 834 | return; | ||
| 835 | } | ||
| 836 | auto& time_manager = kernel.TimeManager(); | ||
| 837 | time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); | ||
| 838 | } | ||
| 839 | |||
| 840 | void SchedulerLockAndSleep::Release() { | ||
| 841 | if (sleep_cancelled) { | ||
| 842 | return; | ||
| 843 | } | ||
| 844 | auto& time_manager = kernel.TimeManager(); | ||
| 845 | time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); | ||
| 846 | sleep_cancelled = true; | ||
| 847 | } | ||
| 848 | |||
| 849 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h deleted file mode 100644 index b6f04dcea..000000000 --- a/src/core/hle/kernel/scheduler.h +++ /dev/null | |||
| @@ -1,318 +0,0 @@ | |||
| 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 <atomic> | ||
| 8 | #include <memory> | ||
| 9 | #include <mutex> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/multi_level_queue.h" | ||
| 14 | #include "common/spin_lock.h" | ||
| 15 | #include "core/hardware_properties.h" | ||
| 16 | #include "core/hle/kernel/thread.h" | ||
| 17 | |||
| 18 | namespace Common { | ||
| 19 | class Fiber; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Core { | ||
| 23 | class ARM_Interface; | ||
| 24 | class System; | ||
| 25 | } // namespace Core | ||
| 26 | |||
| 27 | namespace Kernel { | ||
| 28 | |||
| 29 | class KernelCore; | ||
| 30 | class Process; | ||
| 31 | class SchedulerLock; | ||
| 32 | |||
| 33 | class GlobalScheduler final { | ||
| 34 | public: | ||
| 35 | explicit GlobalScheduler(KernelCore& kernel); | ||
| 36 | ~GlobalScheduler(); | ||
| 37 | |||
| 38 | /// Adds a new thread to the scheduler | ||
| 39 | void AddThread(std::shared_ptr<Thread> thread); | ||
| 40 | |||
| 41 | /// Removes a thread from the scheduler | ||
| 42 | void RemoveThread(std::shared_ptr<Thread> thread); | ||
| 43 | |||
| 44 | /// Returns a list of all threads managed by the scheduler | ||
| 45 | const std::vector<std::shared_ptr<Thread>>& GetThreadList() const { | ||
| 46 | return thread_list; | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Notify the scheduler a thread's status has changed. | ||
| 50 | void AdjustSchedulingOnStatus(Thread* thread, u32 old_flags); | ||
| 51 | |||
| 52 | /// Notify the scheduler a thread's priority has changed. | ||
| 53 | void AdjustSchedulingOnPriority(Thread* thread, u32 old_priority); | ||
| 54 | |||
| 55 | /// Notify the scheduler a thread's core and/or affinity mask has changed. | ||
| 56 | void AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core); | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Takes care of selecting the new scheduled threads in three steps: | ||
| 60 | * | ||
| 61 | * 1. First a thread is selected from the top of the priority queue. If no thread | ||
| 62 | * is obtained then we move to step two, else we are done. | ||
| 63 | * | ||
| 64 | * 2. Second we try to get a suggested thread that's not assigned to any core or | ||
| 65 | * that is not the top thread in that core. | ||
| 66 | * | ||
| 67 | * 3. Third is no suggested thread is found, we do a second pass and pick a running | ||
| 68 | * thread in another core and swap it with its current thread. | ||
| 69 | * | ||
| 70 | * returns the cores needing scheduling. | ||
| 71 | */ | ||
| 72 | u32 SelectThreads(); | ||
| 73 | |||
| 74 | bool HaveReadyThreads(std::size_t core_id) const { | ||
| 75 | return !scheduled_queue[core_id].empty(); | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Takes a thread and moves it to the back of the it's priority list. | ||
| 80 | * | ||
| 81 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 82 | */ | ||
| 83 | bool YieldThread(Thread* thread); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Takes a thread and moves it to the back of the it's priority list. | ||
| 87 | * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or | ||
| 88 | * a better priority than the next thread in the core. | ||
| 89 | * | ||
| 90 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 91 | */ | ||
| 92 | bool YieldThreadAndBalanceLoad(Thread* thread); | ||
| 93 | |||
| 94 | /** | ||
| 95 | * Takes a thread and moves it out of the scheduling queue. | ||
| 96 | * and into the suggested queue. If no thread can be scheduled afterwards in that core, | ||
| 97 | * a suggested thread is obtained instead. | ||
| 98 | * | ||
| 99 | * @note This operation can be redundant and no scheduling is changed if marked as so. | ||
| 100 | */ | ||
| 101 | bool YieldThreadAndWaitForLoadBalancing(Thread* thread); | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Rotates the scheduling queues of threads at a preemption priority and then does | ||
| 105 | * some core rebalancing. Preemption priorities can be found in the array | ||
| 106 | * 'preemption_priorities'. | ||
| 107 | * | ||
| 108 | * @note This operation happens every 10ms. | ||
| 109 | */ | ||
| 110 | void PreemptThreads(); | ||
| 111 | |||
| 112 | u32 CpuCoresCount() const { | ||
| 113 | return Core::Hardware::NUM_CPU_CORES; | ||
| 114 | } | ||
| 115 | |||
| 116 | void SetReselectionPending() { | ||
| 117 | is_reselection_pending.store(true, std::memory_order_release); | ||
| 118 | } | ||
| 119 | |||
| 120 | bool IsReselectionPending() const { | ||
| 121 | return is_reselection_pending.load(std::memory_order_acquire); | ||
| 122 | } | ||
| 123 | |||
| 124 | void Shutdown(); | ||
| 125 | |||
| 126 | private: | ||
| 127 | friend class SchedulerLock; | ||
| 128 | |||
| 129 | /// Lock the scheduler to the current thread. | ||
| 130 | void Lock(); | ||
| 131 | |||
| 132 | /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling | ||
| 133 | /// and reschedules current core if needed. | ||
| 134 | void Unlock(); | ||
| 135 | |||
| 136 | void EnableInterruptAndSchedule(u32 cores_pending_reschedule, | ||
| 137 | Core::EmuThreadHandle global_thread); | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Add a thread to the suggested queue of a cpu core. Suggested threads may be | ||
| 141 | * picked if no thread is scheduled to run on the core. | ||
| 142 | */ | ||
| 143 | void Suggest(u32 priority, std::size_t core, Thread* thread); | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Remove a thread to the suggested queue of a cpu core. Suggested threads may be | ||
| 147 | * picked if no thread is scheduled to run on the core. | ||
| 148 | */ | ||
| 149 | void Unsuggest(u32 priority, std::size_t core, Thread* thread); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Add a thread to the scheduling queue of a cpu core. The thread is added at the | ||
| 153 | * back the queue in its priority level. | ||
| 154 | */ | ||
| 155 | void Schedule(u32 priority, std::size_t core, Thread* thread); | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Add a thread to the scheduling queue of a cpu core. The thread is added at the | ||
| 159 | * front the queue in its priority level. | ||
| 160 | */ | ||
| 161 | void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); | ||
| 162 | |||
| 163 | /// Reschedule an already scheduled thread based on a new priority | ||
| 164 | void Reschedule(u32 priority, std::size_t core, Thread* thread); | ||
| 165 | |||
| 166 | /// Unschedules a thread. | ||
| 167 | void Unschedule(u32 priority, std::size_t core, Thread* thread); | ||
| 168 | |||
| 169 | /** | ||
| 170 | * Transfers a thread into an specific core. If the destination_core is -1 | ||
| 171 | * it will be unscheduled from its source code and added into its suggested | ||
| 172 | * queue. | ||
| 173 | */ | ||
| 174 | void TransferToCore(u32 priority, s32 destination_core, Thread* thread); | ||
| 175 | |||
| 176 | bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); | ||
| 177 | |||
| 178 | static constexpr u32 min_regular_priority = 2; | ||
| 179 | std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES> | ||
| 180 | scheduled_queue; | ||
| 181 | std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES> | ||
| 182 | suggested_queue; | ||
| 183 | std::atomic<bool> is_reselection_pending{false}; | ||
| 184 | |||
| 185 | // The priority levels at which the global scheduler preempts threads every 10 ms. They are | ||
| 186 | // ordered from Core 0 to Core 3. | ||
| 187 | std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; | ||
| 188 | |||
| 189 | /// Scheduler lock mechanisms. | ||
| 190 | bool is_locked{}; | ||
| 191 | std::mutex inner_lock; | ||
| 192 | std::atomic<s64> scope_lock{}; | ||
| 193 | Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; | ||
| 194 | |||
| 195 | Common::SpinLock global_list_guard{}; | ||
| 196 | |||
| 197 | /// Lists all thread ids that aren't deleted/etc. | ||
| 198 | std::vector<std::shared_ptr<Thread>> thread_list; | ||
| 199 | KernelCore& kernel; | ||
| 200 | }; | ||
| 201 | |||
| 202 | class Scheduler final { | ||
| 203 | public: | ||
| 204 | explicit Scheduler(Core::System& system, std::size_t core_id); | ||
| 205 | ~Scheduler(); | ||
| 206 | |||
| 207 | /// Returns whether there are any threads that are ready to run. | ||
| 208 | bool HaveReadyThreads() const; | ||
| 209 | |||
| 210 | /// Reschedules to the next available thread (call after current thread is suspended) | ||
| 211 | void TryDoContextSwitch(); | ||
| 212 | |||
| 213 | /// The next two are for SingleCore Only. | ||
| 214 | /// Unload current thread before preempting core. | ||
| 215 | void Unload(); | ||
| 216 | /// Reload current thread after core preemption. | ||
| 217 | void Reload(); | ||
| 218 | |||
| 219 | /// Gets the current running thread | ||
| 220 | Thread* GetCurrentThread() const; | ||
| 221 | |||
| 222 | /// Gets the currently selected thread from the top of the multilevel queue | ||
| 223 | Thread* GetSelectedThread() const; | ||
| 224 | |||
| 225 | /// Gets the timestamp for the last context switch in ticks. | ||
| 226 | u64 GetLastContextSwitchTicks() const; | ||
| 227 | |||
| 228 | bool ContextSwitchPending() const { | ||
| 229 | return is_context_switch_pending; | ||
| 230 | } | ||
| 231 | |||
| 232 | void Initialize(); | ||
| 233 | |||
| 234 | /// Shutdowns the scheduler. | ||
| 235 | void Shutdown(); | ||
| 236 | |||
| 237 | void OnThreadStart(); | ||
| 238 | |||
| 239 | std::shared_ptr<Common::Fiber>& ControlContext() { | ||
| 240 | return switch_fiber; | ||
| 241 | } | ||
| 242 | |||
| 243 | const std::shared_ptr<Common::Fiber>& ControlContext() const { | ||
| 244 | return switch_fiber; | ||
| 245 | } | ||
| 246 | |||
| 247 | private: | ||
| 248 | friend class GlobalScheduler; | ||
| 249 | |||
| 250 | /// Switches the CPU's active thread context to that of the specified thread | ||
| 251 | void SwitchContext(); | ||
| 252 | |||
| 253 | /// When a thread wakes up, it must run this through it's new scheduler | ||
| 254 | void SwitchContextStep2(); | ||
| 255 | |||
| 256 | /** | ||
| 257 | * Called on every context switch to update the internal timestamp | ||
| 258 | * This also updates the running time ticks for the given thread and | ||
| 259 | * process using the following difference: | ||
| 260 | * | ||
| 261 | * ticks += most_recent_ticks - last_context_switch_ticks | ||
| 262 | * | ||
| 263 | * The internal tick timestamp for the scheduler is simply the | ||
| 264 | * most recent tick count retrieved. No special arithmetic is | ||
| 265 | * applied to it. | ||
| 266 | */ | ||
| 267 | void UpdateLastContextSwitchTime(Thread* thread, Process* process); | ||
| 268 | |||
| 269 | static void OnSwitch(void* this_scheduler); | ||
| 270 | void SwitchToCurrent(); | ||
| 271 | |||
| 272 | std::shared_ptr<Thread> current_thread = nullptr; | ||
| 273 | std::shared_ptr<Thread> selected_thread = nullptr; | ||
| 274 | std::shared_ptr<Thread> current_thread_prev = nullptr; | ||
| 275 | std::shared_ptr<Thread> selected_thread_set = nullptr; | ||
| 276 | std::shared_ptr<Thread> idle_thread = nullptr; | ||
| 277 | |||
| 278 | std::shared_ptr<Common::Fiber> switch_fiber = nullptr; | ||
| 279 | |||
| 280 | Core::System& system; | ||
| 281 | u64 last_context_switch_time = 0; | ||
| 282 | u64 idle_selection_count = 0; | ||
| 283 | const std::size_t core_id; | ||
| 284 | |||
| 285 | Common::SpinLock guard{}; | ||
| 286 | |||
| 287 | bool is_context_switch_pending = false; | ||
| 288 | }; | ||
| 289 | |||
| 290 | class SchedulerLock { | ||
| 291 | public: | ||
| 292 | [[nodiscard]] explicit SchedulerLock(KernelCore& kernel); | ||
| 293 | ~SchedulerLock(); | ||
| 294 | |||
| 295 | protected: | ||
| 296 | KernelCore& kernel; | ||
| 297 | }; | ||
| 298 | |||
| 299 | class SchedulerLockAndSleep : public SchedulerLock { | ||
| 300 | public: | ||
| 301 | explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, | ||
| 302 | s64 nanoseconds); | ||
| 303 | ~SchedulerLockAndSleep(); | ||
| 304 | |||
| 305 | void CancelSleep() { | ||
| 306 | sleep_cancelled = true; | ||
| 307 | } | ||
| 308 | |||
| 309 | void Release(); | ||
| 310 | |||
| 311 | private: | ||
| 312 | Handle& event_handle; | ||
| 313 | Thread* time_task; | ||
| 314 | s64 nanoseconds; | ||
| 315 | bool sleep_cancelled{}; | ||
| 316 | }; | ||
| 317 | |||
| 318 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 8c19f2534..b40fe3916 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -14,9 +14,9 @@ | |||
| 14 | #include "core/hle/kernel/client_session.h" | 14 | #include "core/hle/kernel/client_session.h" |
| 15 | #include "core/hle/kernel/handle_table.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| 17 | #include "core/hle/kernel/k_scheduler.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/scheduler.h" | ||
| 20 | #include "core/hle/kernel/server_session.h" | 20 | #include "core/hle/kernel/server_session.h" |
| 21 | #include "core/hle/kernel/session.h" | 21 | #include "core/hle/kernel/session.h" |
| 22 | #include "core/hle/kernel/thread.h" | 22 | #include "core/hle/kernel/thread.h" |
| @@ -25,19 +25,19 @@ | |||
| 25 | namespace Kernel { | 25 | namespace Kernel { |
| 26 | 26 | ||
| 27 | ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} | 27 | ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} |
| 28 | ServerSession::~ServerSession() = default; | 28 | |
| 29 | ServerSession::~ServerSession() { | ||
| 30 | kernel.ReleaseServiceThread(service_thread); | ||
| 31 | } | ||
| 29 | 32 | ||
| 30 | ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, | 33 | ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, |
| 31 | std::shared_ptr<Session> parent, | 34 | std::shared_ptr<Session> parent, |
| 32 | std::string name) { | 35 | std::string name) { |
| 33 | std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; | 36 | std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; |
| 34 | 37 | ||
| 35 | session->request_event = | ||
| 36 | Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) { | ||
| 37 | session->CompleteSyncRequest(); | ||
| 38 | }); | ||
| 39 | session->name = std::move(name); | 38 | session->name = std::move(name); |
| 40 | session->parent = std::move(parent); | 39 | session->parent = std::move(parent); |
| 40 | session->service_thread = kernel.CreateServiceThread(session->name); | ||
| 41 | 41 | ||
| 42 | return MakeResult(std::move(session)); | 42 | return MakeResult(std::move(session)); |
| 43 | } | 43 | } |
| @@ -130,8 +130,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | LOG_CRITICAL(IPC, "Unknown domain command={}", | 133 | LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); |
| 134 | static_cast<int>(domain_message_header.command.Value())); | ||
| 135 | ASSERT(false); | 134 | ASSERT(false); |
| 136 | return RESULT_SUCCESS; | 135 | return RESULT_SUCCESS; |
| 137 | } | 136 | } |
| @@ -143,16 +142,16 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, | |||
| 143 | std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); | 142 | std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); |
| 144 | 143 | ||
| 145 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 144 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 146 | request_queue.Push(std::move(context)); | 145 | |
| 146 | if (auto strong_ptr = service_thread.lock()) { | ||
| 147 | strong_ptr->QueueSyncRequest(*this, std::move(context)); | ||
| 148 | return RESULT_SUCCESS; | ||
| 149 | } | ||
| 147 | 150 | ||
| 148 | return RESULT_SUCCESS; | 151 | return RESULT_SUCCESS; |
| 149 | } | 152 | } |
| 150 | 153 | ||
| 151 | ResultCode ServerSession::CompleteSyncRequest() { | 154 | ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { |
| 152 | ASSERT(!request_queue.Empty()); | ||
| 153 | |||
| 154 | auto& context = *request_queue.Front(); | ||
| 155 | |||
| 156 | ResultCode result = RESULT_SUCCESS; | 155 | ResultCode result = RESULT_SUCCESS; |
| 157 | // If the session has been converted to a domain, handle the domain request | 156 | // If the session has been converted to a domain, handle the domain request |
| 158 | if (IsDomain() && context.HasDomainMessageHeader()) { | 157 | if (IsDomain() && context.HasDomainMessageHeader()) { |
| @@ -171,25 +170,20 @@ ResultCode ServerSession::CompleteSyncRequest() { | |||
| 171 | 170 | ||
| 172 | // Some service requests require the thread to block | 171 | // Some service requests require the thread to block |
| 173 | { | 172 | { |
| 174 | SchedulerLock lock(kernel); | 173 | KScopedSchedulerLock lock(kernel); |
| 175 | if (!context.IsThreadWaiting()) { | 174 | if (!context.IsThreadWaiting()) { |
| 176 | context.GetThread().ResumeFromWait(); | 175 | context.GetThread().ResumeFromWait(); |
| 177 | context.GetThread().SetSynchronizationResults(nullptr, result); | 176 | context.GetThread().SetSynchronizationResults(nullptr, result); |
| 178 | } | 177 | } |
| 179 | } | 178 | } |
| 180 | 179 | ||
| 181 | request_queue.Pop(); | ||
| 182 | |||
| 183 | return result; | 180 | return result; |
| 184 | } | 181 | } |
| 185 | 182 | ||
| 186 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | 183 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, |
| 187 | Core::Memory::Memory& memory, | 184 | Core::Memory::Memory& memory, |
| 188 | Core::Timing::CoreTiming& core_timing) { | 185 | Core::Timing::CoreTiming& core_timing) { |
| 189 | const ResultCode result = QueueSyncRequest(std::move(thread), memory); | 186 | return QueueSyncRequest(std::move(thread), memory); |
| 190 | const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000}; | ||
| 191 | core_timing.ScheduleEvent(delay, request_event, {}); | ||
| 192 | return result; | ||
| 193 | } | 187 | } |
| 194 | 188 | ||
| 195 | } // namespace Kernel | 189 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index d23e9ec68..e8d1d99ea 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 13 | #include "core/hle/kernel/service_thread.h" | ||
| 13 | #include "core/hle/kernel/synchronization_object.h" | 14 | #include "core/hle/kernel/synchronization_object.h" |
| 14 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 15 | 16 | ||
| @@ -43,6 +44,8 @@ class Thread; | |||
| 43 | * TLS buffer and control is transferred back to it. | 44 | * TLS buffer and control is transferred back to it. |
| 44 | */ | 45 | */ |
| 45 | class ServerSession final : public SynchronizationObject { | 46 | class ServerSession final : public SynchronizationObject { |
| 47 | friend class ServiceThread; | ||
| 48 | |||
| 46 | public: | 49 | public: |
| 47 | explicit ServerSession(KernelCore& kernel); | 50 | explicit ServerSession(KernelCore& kernel); |
| 48 | ~ServerSession() override; | 51 | ~ServerSession() override; |
| @@ -132,7 +135,7 @@ private: | |||
| 132 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); | 135 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); |
| 133 | 136 | ||
| 134 | /// Completes a sync request from the emulated application. | 137 | /// Completes a sync request from the emulated application. |
| 135 | ResultCode CompleteSyncRequest(); | 138 | ResultCode CompleteSyncRequest(HLERequestContext& context); |
| 136 | 139 | ||
| 137 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | 140 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an |
| 138 | /// object handle. | 141 | /// object handle. |
| @@ -163,11 +166,8 @@ private: | |||
| 163 | /// The name of this session (optional) | 166 | /// The name of this session (optional) |
| 164 | std::string name; | 167 | std::string name; |
| 165 | 168 | ||
| 166 | /// Core timing event used to schedule the service request at some point in the future | 169 | /// Thread to dispatch service requests |
| 167 | std::shared_ptr<Core::Timing::EventType> request_event; | 170 | std::weak_ptr<ServiceThread> service_thread; |
| 168 | |||
| 169 | /// Queue of scheduled service requests | ||
| 170 | Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; | ||
| 171 | }; | 171 | }; |
| 172 | 172 | ||
| 173 | } // namespace Kernel | 173 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp new file mode 100644 index 000000000..ee46f3e21 --- /dev/null +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <condition_variable> | ||
| 6 | #include <functional> | ||
| 7 | #include <mutex> | ||
| 8 | #include <thread> | ||
| 9 | #include <vector> | ||
| 10 | #include <queue> | ||
| 11 | |||
| 12 | #include "common/assert.h" | ||
| 13 | #include "common/scope_exit.h" | ||
| 14 | #include "common/thread.h" | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/hle/kernel/kernel.h" | ||
| 17 | #include "core/hle/kernel/server_session.h" | ||
| 18 | #include "core/hle/kernel/service_thread.h" | ||
| 19 | #include "core/hle/lock.h" | ||
| 20 | #include "video_core/renderer_base.h" | ||
| 21 | |||
| 22 | namespace Kernel { | ||
| 23 | |||
| 24 | class ServiceThread::Impl final { | ||
| 25 | public: | ||
| 26 | explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); | ||
| 27 | ~Impl(); | ||
| 28 | |||
| 29 | void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||
| 30 | |||
| 31 | private: | ||
| 32 | std::vector<std::thread> threads; | ||
| 33 | std::queue<std::function<void()>> requests; | ||
| 34 | std::mutex queue_mutex; | ||
| 35 | std::condition_variable condition; | ||
| 36 | const std::string service_name; | ||
| 37 | bool stop{}; | ||
| 38 | }; | ||
| 39 | |||
| 40 | ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) | ||
| 41 | : service_name{name} { | ||
| 42 | for (std::size_t i = 0; i < num_threads; ++i) | ||
| 43 | threads.emplace_back([this, &kernel] { | ||
| 44 | Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); | ||
| 45 | |||
| 46 | // Wait for first request before trying to acquire a render context | ||
| 47 | { | ||
| 48 | std::unique_lock lock{queue_mutex}; | ||
| 49 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 50 | } | ||
| 51 | |||
| 52 | kernel.RegisterHostThread(); | ||
| 53 | |||
| 54 | while (true) { | ||
| 55 | std::function<void()> task; | ||
| 56 | |||
| 57 | { | ||
| 58 | std::unique_lock lock{queue_mutex}; | ||
| 59 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | ||
| 60 | if (stop || requests.empty()) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | task = std::move(requests.front()); | ||
| 64 | requests.pop(); | ||
| 65 | } | ||
| 66 | |||
| 67 | task(); | ||
| 68 | } | ||
| 69 | }); | ||
| 70 | } | ||
| 71 | |||
| 72 | void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, | ||
| 73 | std::shared_ptr<HLERequestContext>&& context) { | ||
| 74 | { | ||
| 75 | std::unique_lock lock{queue_mutex}; | ||
| 76 | |||
| 77 | // ServerSession owns the service thread, so we cannot caption a strong pointer here in the | ||
| 78 | // event that the ServerSession is terminated. | ||
| 79 | std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)}; | ||
| 80 | requests.emplace([weak_ptr, context{std::move(context)}]() { | ||
| 81 | if (auto strong_ptr = weak_ptr.lock()) { | ||
| 82 | strong_ptr->CompleteSyncRequest(*context); | ||
| 83 | } | ||
| 84 | }); | ||
| 85 | } | ||
| 86 | condition.notify_one(); | ||
| 87 | } | ||
| 88 | |||
| 89 | ServiceThread::Impl::~Impl() { | ||
| 90 | { | ||
| 91 | std::unique_lock lock{queue_mutex}; | ||
| 92 | stop = true; | ||
| 93 | } | ||
| 94 | condition.notify_all(); | ||
| 95 | for (std::thread& thread : threads) { | ||
| 96 | thread.join(); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) | ||
| 101 | : impl{std::make_unique<Impl>(kernel, num_threads, name)} {} | ||
| 102 | |||
| 103 | ServiceThread::~ServiceThread() = default; | ||
| 104 | |||
| 105 | void ServiceThread::QueueSyncRequest(ServerSession& session, | ||
| 106 | std::shared_ptr<HLERequestContext>&& context) { | ||
| 107 | impl->QueueSyncRequest(session, std::move(context)); | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h new file mode 100644 index 000000000..025ab8fb5 --- /dev/null +++ b/src/core/hle/kernel/service_thread.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2020 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 <string> | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class HLERequestContext; | ||
| 13 | class KernelCore; | ||
| 14 | class ServerSession; | ||
| 15 | |||
| 16 | class ServiceThread final { | ||
| 17 | public: | ||
| 18 | explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); | ||
| 19 | ~ServiceThread(); | ||
| 20 | |||
| 21 | void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); | ||
| 22 | |||
| 23 | private: | ||
| 24 | class Impl; | ||
| 25 | std::unique_ptr<Impl> impl; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bafd1ced7..de3ed25da 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | #include "core/hle/kernel/client_session.h" | 24 | #include "core/hle/kernel/client_session.h" |
| 25 | #include "core/hle/kernel/errors.h" | 25 | #include "core/hle/kernel/errors.h" |
| 26 | #include "core/hle/kernel/handle_table.h" | 26 | #include "core/hle/kernel/handle_table.h" |
| 27 | #include "core/hle/kernel/k_scheduler.h" | ||
| 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 27 | #include "core/hle/kernel/kernel.h" | 29 | #include "core/hle/kernel/kernel.h" |
| 28 | #include "core/hle/kernel/memory/memory_block.h" | 30 | #include "core/hle/kernel/memory/memory_block.h" |
| 29 | #include "core/hle/kernel/memory/page_table.h" | 31 | #include "core/hle/kernel/memory/page_table.h" |
| @@ -32,7 +34,6 @@ | |||
| 32 | #include "core/hle/kernel/process.h" | 34 | #include "core/hle/kernel/process.h" |
| 33 | #include "core/hle/kernel/readable_event.h" | 35 | #include "core/hle/kernel/readable_event.h" |
| 34 | #include "core/hle/kernel/resource_limit.h" | 36 | #include "core/hle/kernel/resource_limit.h" |
| 35 | #include "core/hle/kernel/scheduler.h" | ||
| 36 | #include "core/hle/kernel/shared_memory.h" | 37 | #include "core/hle/kernel/shared_memory.h" |
| 37 | #include "core/hle/kernel/svc.h" | 38 | #include "core/hle/kernel/svc.h" |
| 38 | #include "core/hle/kernel/svc_types.h" | 39 | #include "core/hle/kernel/svc_types.h" |
| @@ -234,8 +235,7 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si | |||
| 234 | 235 | ||
| 235 | static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, | 236 | static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, |
| 236 | u32 attribute) { | 237 | u32 attribute) { |
| 237 | return SetMemoryAttribute(system, static_cast<VAddr>(address), static_cast<std::size_t>(size), | 238 | return SetMemoryAttribute(system, address, size, mask, attribute); |
| 238 | mask, attribute); | ||
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | /// Maps a memory range into a different range. | 241 | /// Maps a memory range into a different range. |
| @@ -255,8 +255,7 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr | |||
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { | 257 | static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { |
| 258 | return MapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr), | 258 | return MapMemory(system, dst_addr, src_addr, size); |
| 259 | static_cast<std::size_t>(size)); | ||
| 260 | } | 259 | } |
| 261 | 260 | ||
| 262 | /// Unmaps a region that was previously mapped with svcMapMemory | 261 | /// Unmaps a region that was previously mapped with svcMapMemory |
| @@ -276,8 +275,7 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad | |||
| 276 | } | 275 | } |
| 277 | 276 | ||
| 278 | static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { | 277 | static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { |
| 279 | return UnmapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr), | 278 | return UnmapMemory(system, dst_addr, src_addr, size); |
| 280 | static_cast<std::size_t>(size)); | ||
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | /// Connect to an OS service given the port name, returns the handle to the port to out | 281 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| @@ -332,7 +330,8 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, | |||
| 332 | 330 | ||
| 333 | /// Makes a blocking IPC call to an OS service. | 331 | /// Makes a blocking IPC call to an OS service. |
| 334 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | 332 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { |
| 335 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 333 | auto& kernel = system.Kernel(); |
| 334 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||
| 336 | std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); | 335 | std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); |
| 337 | if (!session) { | 336 | if (!session) { |
| 338 | LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); | 337 | LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); |
| @@ -341,9 +340,9 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 341 | 340 | ||
| 342 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | 341 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); |
| 343 | 342 | ||
| 344 | auto thread = system.CurrentScheduler().GetCurrentThread(); | 343 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 345 | { | 344 | { |
| 346 | SchedulerLock lock(system.Kernel()); | 345 | KScopedSchedulerLock lock(kernel); |
| 347 | thread->InvalidateHLECallback(); | 346 | thread->InvalidateHLECallback(); |
| 348 | thread->SetStatus(ThreadStatus::WaitIPC); | 347 | thread->SetStatus(ThreadStatus::WaitIPC); |
| 349 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 348 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); |
| @@ -352,12 +351,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 352 | if (thread->HasHLECallback()) { | 351 | if (thread->HasHLECallback()) { |
| 353 | Handle event_handle = thread->GetHLETimeEvent(); | 352 | Handle event_handle = thread->GetHLETimeEvent(); |
| 354 | if (event_handle != InvalidHandle) { | 353 | if (event_handle != InvalidHandle) { |
| 355 | auto& time_manager = system.Kernel().TimeManager(); | 354 | auto& time_manager = kernel.TimeManager(); |
| 356 | time_manager.UnscheduleTimeEvent(event_handle); | 355 | time_manager.UnscheduleTimeEvent(event_handle); |
| 357 | } | 356 | } |
| 358 | 357 | ||
| 359 | { | 358 | { |
| 360 | SchedulerLock lock(system.Kernel()); | 359 | KScopedSchedulerLock lock(kernel); |
| 361 | auto* sync_object = thread->GetHLESyncObject(); | 360 | auto* sync_object = thread->GetHLESyncObject(); |
| 362 | sync_object->RemoveWaitingThread(SharedFrom(thread)); | 361 | sync_object->RemoveWaitingThread(SharedFrom(thread)); |
| 363 | } | 362 | } |
| @@ -531,8 +530,7 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand | |||
| 531 | 530 | ||
| 532 | static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, | 531 | static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, |
| 533 | u32 mutex_addr, Handle requesting_thread_handle) { | 532 | u32 mutex_addr, Handle requesting_thread_handle) { |
| 534 | return ArbitrateLock(system, holding_thread_handle, static_cast<VAddr>(mutex_addr), | 533 | return ArbitrateLock(system, holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 535 | requesting_thread_handle); | ||
| 536 | } | 534 | } |
| 537 | 535 | ||
| 538 | /// Unlock a mutex | 536 | /// Unlock a mutex |
| @@ -555,7 +553,7 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { | |||
| 555 | } | 553 | } |
| 556 | 554 | ||
| 557 | static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { | 555 | static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { |
| 558 | return ArbitrateUnlock(system, static_cast<VAddr>(mutex_addr)); | 556 | return ArbitrateUnlock(system, mutex_addr); |
| 559 | } | 557 | } |
| 560 | 558 | ||
| 561 | enum class BreakType : u32 { | 559 | enum class BreakType : u32 { |
| @@ -658,7 +656,6 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 658 | info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); | 656 | info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); |
| 659 | 657 | ||
| 660 | if (!break_reason.signal_debugger) { | 658 | if (!break_reason.signal_debugger) { |
| 661 | SchedulerLock lock(system.Kernel()); | ||
| 662 | LOG_CRITICAL( | 659 | LOG_CRITICAL( |
| 663 | Debug_Emulated, | 660 | Debug_Emulated, |
| 664 | "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", | 661 | "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", |
| @@ -666,22 +663,18 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { | |||
| 666 | 663 | ||
| 667 | handle_debug_buffer(info1, info2); | 664 | handle_debug_buffer(info1, info2); |
| 668 | 665 | ||
| 669 | auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); | 666 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 670 | const auto thread_processor_id = current_thread->GetProcessorID(); | 667 | const auto thread_processor_id = current_thread->GetProcessorID(); |
| 671 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); | 668 | system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); |
| 672 | |||
| 673 | // Kill the current thread | ||
| 674 | system.Kernel().ExceptionalExit(); | ||
| 675 | current_thread->Stop(); | ||
| 676 | } | 669 | } |
| 677 | } | 670 | } |
| 678 | 671 | ||
| 679 | static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { | 672 | static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { |
| 680 | Break(system, reason, static_cast<u64>(info1), static_cast<u64>(info2)); | 673 | Break(system, reason, info1, info2); |
| 681 | } | 674 | } |
| 682 | 675 | ||
| 683 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 676 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| 684 | static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { | 677 | static void OutputDebugString(Core::System& system, VAddr address, u64 len) { |
| 685 | if (len == 0) { | 678 | if (len == 0) { |
| 686 | return; | 679 | return; |
| 687 | } | 680 | } |
| @@ -922,7 +915,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 922 | } | 915 | } |
| 923 | 916 | ||
| 924 | const auto& core_timing = system.CoreTiming(); | 917 | const auto& core_timing = system.CoreTiming(); |
| 925 | const auto& scheduler = system.CurrentScheduler(); | 918 | const auto& scheduler = *system.Kernel().CurrentScheduler(); |
| 926 | const auto* const current_thread = scheduler.GetCurrentThread(); | 919 | const auto* const current_thread = scheduler.GetCurrentThread(); |
| 927 | const bool same_thread = current_thread == thread.get(); | 920 | const bool same_thread = current_thread == thread.get(); |
| 928 | 921 | ||
| @@ -948,7 +941,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha | |||
| 948 | 941 | ||
| 949 | static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low, | 942 | static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low, |
| 950 | u32 info_id, u32 handle, u32 sub_id_high) { | 943 | u32 info_id, u32 handle, u32 sub_id_high) { |
| 951 | const u64 sub_id{static_cast<u64>(sub_id_low | (static_cast<u64>(sub_id_high) << 32))}; | 944 | const u64 sub_id{u64{sub_id_low} | (u64{sub_id_high} << 32)}; |
| 952 | u64 res_value{}; | 945 | u64 res_value{}; |
| 953 | 946 | ||
| 954 | const ResultCode result{GetInfo(system, &res_value, info_id, handle, sub_id)}; | 947 | const ResultCode result{GetInfo(system, &res_value, info_id, handle, sub_id)}; |
| @@ -1009,7 +1002,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) | |||
| 1009 | } | 1002 | } |
| 1010 | 1003 | ||
| 1011 | static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { | 1004 | static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { |
| 1012 | return MapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size)); | 1005 | return MapPhysicalMemory(system, addr, size); |
| 1013 | } | 1006 | } |
| 1014 | 1007 | ||
| 1015 | /// Unmaps memory previously mapped via MapPhysicalMemory | 1008 | /// Unmaps memory previously mapped via MapPhysicalMemory |
| @@ -1063,7 +1056,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size | |||
| 1063 | } | 1056 | } |
| 1064 | 1057 | ||
| 1065 | static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { | 1058 | static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { |
| 1066 | return UnmapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size)); | 1059 | return UnmapPhysicalMemory(system, addr, size); |
| 1067 | } | 1060 | } |
| 1068 | 1061 | ||
| 1069 | /// Sets the thread activity | 1062 | /// Sets the thread activity |
| @@ -1090,7 +1083,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act | |||
| 1090 | return ERR_INVALID_HANDLE; | 1083 | return ERR_INVALID_HANDLE; |
| 1091 | } | 1084 | } |
| 1092 | 1085 | ||
| 1093 | if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { | 1086 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { |
| 1094 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1087 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); |
| 1095 | return ERR_BUSY; | 1088 | return ERR_BUSY; |
| 1096 | } | 1089 | } |
| @@ -1123,7 +1116,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H | |||
| 1123 | return ERR_INVALID_HANDLE; | 1116 | return ERR_INVALID_HANDLE; |
| 1124 | } | 1117 | } |
| 1125 | 1118 | ||
| 1126 | if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { | 1119 | if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { |
| 1127 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | 1120 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); |
| 1128 | return ERR_BUSY; | 1121 | return ERR_BUSY; |
| 1129 | } | 1122 | } |
| @@ -1144,7 +1137,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H | |||
| 1144 | } | 1137 | } |
| 1145 | 1138 | ||
| 1146 | static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { | 1139 | static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { |
| 1147 | return GetThreadContext(system, static_cast<VAddr>(thread_context), handle); | 1140 | return GetThreadContext(system, thread_context, handle); |
| 1148 | } | 1141 | } |
| 1149 | 1142 | ||
| 1150 | /// Gets the priority for the specified thread | 1143 | /// Gets the priority for the specified thread |
| @@ -1281,8 +1274,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han | |||
| 1281 | 1274 | ||
| 1282 | static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, | 1275 | static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, |
| 1283 | u32 size, u32 permissions) { | 1276 | u32 size, u32 permissions) { |
| 1284 | return MapSharedMemory(system, shared_memory_handle, static_cast<VAddr>(addr), | 1277 | return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); |
| 1285 | static_cast<std::size_t>(size), permissions); | ||
| 1286 | } | 1278 | } |
| 1287 | 1279 | ||
| 1288 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1280 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, |
| @@ -1480,7 +1472,7 @@ static void ExitProcess(Core::System& system) { | |||
| 1480 | current_process->PrepareForTermination(); | 1472 | current_process->PrepareForTermination(); |
| 1481 | 1473 | ||
| 1482 | // Kill the current thread | 1474 | // Kill the current thread |
| 1483 | system.CurrentScheduler().GetCurrentThread()->Stop(); | 1475 | system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); |
| 1484 | } | 1476 | } |
| 1485 | 1477 | ||
| 1486 | static void ExitProcess32(Core::System& system) { | 1478 | static void ExitProcess32(Core::System& system) { |
| @@ -1552,8 +1544,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1552 | 1544 | ||
| 1553 | static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, | 1545 | static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, |
| 1554 | u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { | 1546 | u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { |
| 1555 | return CreateThread(system, out_handle, static_cast<VAddr>(entry_point), static_cast<u64>(arg), | 1547 | return CreateThread(system, out_handle, entry_point, arg, stack_top, priority, processor_id); |
| 1556 | static_cast<VAddr>(stack_top), priority, processor_id); | ||
| 1557 | } | 1548 | } |
| 1558 | 1549 | ||
| 1559 | /// Starts the thread for the provided handle | 1550 | /// Starts the thread for the provided handle |
| @@ -1581,8 +1572,8 @@ static ResultCode StartThread32(Core::System& system, Handle thread_handle) { | |||
| 1581 | static void ExitThread(Core::System& system) { | 1572 | static void ExitThread(Core::System& system) { |
| 1582 | LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); | 1573 | LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); |
| 1583 | 1574 | ||
| 1584 | auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); | 1575 | auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 1585 | system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); | 1576 | system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); |
| 1586 | current_thread->Stop(); | 1577 | current_thread->Stop(); |
| 1587 | } | 1578 | } |
| 1588 | 1579 | ||
| @@ -1592,53 +1583,39 @@ static void ExitThread32(Core::System& system) { | |||
| 1592 | 1583 | ||
| 1593 | /// Sleep the current thread | 1584 | /// Sleep the current thread |
| 1594 | static void SleepThread(Core::System& system, s64 nanoseconds) { | 1585 | static void SleepThread(Core::System& system, s64 nanoseconds) { |
| 1595 | LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); | 1586 | LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); |
| 1596 | 1587 | ||
| 1597 | enum class SleepType : s64 { | 1588 | enum class SleepType : s64 { |
| 1598 | YieldWithoutLoadBalancing = 0, | 1589 | YieldWithoutCoreMigration = 0, |
| 1599 | YieldWithLoadBalancing = -1, | 1590 | YieldWithCoreMigration = -1, |
| 1600 | YieldAndWaitForLoadBalancing = -2, | 1591 | YieldAndWaitForLoadBalancing = -2, |
| 1601 | }; | 1592 | }; |
| 1602 | 1593 | ||
| 1603 | auto& scheduler = system.CurrentScheduler(); | 1594 | auto& scheduler = *system.Kernel().CurrentScheduler(); |
| 1604 | auto* const current_thread = scheduler.GetCurrentThread(); | ||
| 1605 | bool is_redundant = false; | ||
| 1606 | |||
| 1607 | if (nanoseconds <= 0) { | 1595 | if (nanoseconds <= 0) { |
| 1608 | switch (static_cast<SleepType>(nanoseconds)) { | 1596 | switch (static_cast<SleepType>(nanoseconds)) { |
| 1609 | case SleepType::YieldWithoutLoadBalancing: { | 1597 | case SleepType::YieldWithoutCoreMigration: { |
| 1610 | auto pair = current_thread->YieldSimple(); | 1598 | scheduler.YieldWithoutCoreMigration(); |
| 1611 | is_redundant = pair.second; | ||
| 1612 | break; | 1599 | break; |
| 1613 | } | 1600 | } |
| 1614 | case SleepType::YieldWithLoadBalancing: { | 1601 | case SleepType::YieldWithCoreMigration: { |
| 1615 | auto pair = current_thread->YieldAndBalanceLoad(); | 1602 | scheduler.YieldWithCoreMigration(); |
| 1616 | is_redundant = pair.second; | ||
| 1617 | break; | 1603 | break; |
| 1618 | } | 1604 | } |
| 1619 | case SleepType::YieldAndWaitForLoadBalancing: { | 1605 | case SleepType::YieldAndWaitForLoadBalancing: { |
| 1620 | auto pair = current_thread->YieldAndWaitForLoadBalancing(); | 1606 | scheduler.YieldToAnyThread(); |
| 1621 | is_redundant = pair.second; | ||
| 1622 | break; | 1607 | break; |
| 1623 | } | 1608 | } |
| 1624 | default: | 1609 | default: |
| 1625 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); | 1610 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); |
| 1626 | } | 1611 | } |
| 1627 | } else { | 1612 | } else { |
| 1628 | current_thread->Sleep(nanoseconds); | 1613 | scheduler.GetCurrentThread()->Sleep(nanoseconds); |
| 1629 | } | ||
| 1630 | |||
| 1631 | if (is_redundant && !system.Kernel().IsMulticore()) { | ||
| 1632 | system.Kernel().ExitSVCProfile(); | ||
| 1633 | system.CoreTiming().AddTicks(1000U); | ||
| 1634 | system.GetCpuManager().PreemptSingleCore(); | ||
| 1635 | system.Kernel().EnterSVCProfile(); | ||
| 1636 | } | 1614 | } |
| 1637 | } | 1615 | } |
| 1638 | 1616 | ||
| 1639 | static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { | 1617 | static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { |
| 1640 | const s64 nanoseconds = static_cast<s64>(static_cast<u64>(nanoseconds_low) | | 1618 | const auto nanoseconds = static_cast<s64>(u64{nanoseconds_low} | (u64{nanoseconds_high} << 32)); |
| 1641 | (static_cast<u64>(nanoseconds_high) << 32)); | ||
| 1642 | SleepThread(system, nanoseconds); | 1619 | SleepThread(system, nanoseconds); |
| 1643 | } | 1620 | } |
| 1644 | 1621 | ||
| @@ -1668,10 +1645,10 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1668 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); | 1645 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); |
| 1669 | auto& kernel = system.Kernel(); | 1646 | auto& kernel = system.Kernel(); |
| 1670 | Handle event_handle; | 1647 | Handle event_handle; |
| 1671 | Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); | 1648 | Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 1672 | auto* const current_process = system.Kernel().CurrentProcess(); | 1649 | auto* const current_process = kernel.CurrentProcess(); |
| 1673 | { | 1650 | { |
| 1674 | SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); | 1651 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); |
| 1675 | const auto& handle_table = current_process->GetHandleTable(); | 1652 | const auto& handle_table = current_process->GetHandleTable(); |
| 1676 | std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1653 | std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 1677 | ASSERT(thread); | 1654 | ASSERT(thread); |
| @@ -1707,7 +1684,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1707 | } | 1684 | } |
| 1708 | 1685 | ||
| 1709 | { | 1686 | { |
| 1710 | SchedulerLock lock(kernel); | 1687 | KScopedSchedulerLock lock(kernel); |
| 1711 | 1688 | ||
| 1712 | auto* owner = current_thread->GetLockOwner(); | 1689 | auto* owner = current_thread->GetLockOwner(); |
| 1713 | if (owner != nullptr) { | 1690 | if (owner != nullptr) { |
| @@ -1724,10 +1701,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1724 | static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, | 1701 | static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, |
| 1725 | u32 condition_variable_addr, Handle thread_handle, | 1702 | u32 condition_variable_addr, Handle thread_handle, |
| 1726 | u32 nanoseconds_low, u32 nanoseconds_high) { | 1703 | u32 nanoseconds_low, u32 nanoseconds_high) { |
| 1727 | const s64 nanoseconds = | 1704 | const auto nanoseconds = static_cast<s64>(nanoseconds_low | (u64{nanoseconds_high} << 32)); |
| 1728 | static_cast<s64>(nanoseconds_low | (static_cast<u64>(nanoseconds_high) << 32)); | 1705 | return WaitProcessWideKeyAtomic(system, mutex_addr, condition_variable_addr, thread_handle, |
| 1729 | return WaitProcessWideKeyAtomic(system, static_cast<VAddr>(mutex_addr), | ||
| 1730 | static_cast<VAddr>(condition_variable_addr), thread_handle, | ||
| 1731 | nanoseconds); | 1706 | nanoseconds); |
| 1732 | } | 1707 | } |
| 1733 | 1708 | ||
| @@ -1740,7 +1715,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ | |||
| 1740 | 1715 | ||
| 1741 | // Retrieve a list of all threads that are waiting for this condition variable. | 1716 | // Retrieve a list of all threads that are waiting for this condition variable. |
| 1742 | auto& kernel = system.Kernel(); | 1717 | auto& kernel = system.Kernel(); |
| 1743 | SchedulerLock lock(kernel); | 1718 | KScopedSchedulerLock lock(kernel); |
| 1744 | auto* const current_process = kernel.CurrentProcess(); | 1719 | auto* const current_process = kernel.CurrentProcess(); |
| 1745 | std::vector<std::shared_ptr<Thread>> waiting_threads = | 1720 | std::vector<std::shared_ptr<Thread>> waiting_threads = |
| 1746 | current_process->GetConditionVariableThreads(condition_variable_addr); | 1721 | current_process->GetConditionVariableThreads(condition_variable_addr); |
| @@ -1833,8 +1808,8 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, | |||
| 1833 | 1808 | ||
| 1834 | static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, | 1809 | static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, |
| 1835 | u32 timeout_low, u32 timeout_high) { | 1810 | u32 timeout_low, u32 timeout_high) { |
| 1836 | s64 timeout = static_cast<s64>(timeout_low | (static_cast<u64>(timeout_high) << 32)); | 1811 | const auto timeout = static_cast<s64>(timeout_low | (u64{timeout_high} << 32)); |
| 1837 | return WaitForAddress(system, static_cast<VAddr>(address), type, value, timeout); | 1812 | return WaitForAddress(system, address, type, value, timeout); |
| 1838 | } | 1813 | } |
| 1839 | 1814 | ||
| 1840 | // Signals to an address (via Address Arbiter) | 1815 | // Signals to an address (via Address Arbiter) |
| @@ -1862,7 +1837,7 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, | |||
| 1862 | 1837 | ||
| 1863 | static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, | 1838 | static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, |
| 1864 | s32 num_to_wake) { | 1839 | s32 num_to_wake) { |
| 1865 | return SignalToAddress(system, static_cast<VAddr>(address), type, value, num_to_wake); | 1840 | return SignalToAddress(system, address, type, value, num_to_wake); |
| 1866 | } | 1841 | } |
| 1867 | 1842 | ||
| 1868 | static void KernelDebug([[maybe_unused]] Core::System& system, | 1843 | static void KernelDebug([[maybe_unused]] Core::System& system, |
| @@ -1893,7 +1868,7 @@ static u64 GetSystemTick(Core::System& system) { | |||
| 1893 | } | 1868 | } |
| 1894 | 1869 | ||
| 1895 | static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { | 1870 | static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { |
| 1896 | u64 time = GetSystemTick(system); | 1871 | const auto time = GetSystemTick(system); |
| 1897 | *time_low = static_cast<u32>(time); | 1872 | *time_low = static_cast<u32>(time); |
| 1898 | *time_high = static_cast<u32>(time >> 32); | 1873 | *time_high = static_cast<u32>(time >> 32); |
| 1899 | } | 1874 | } |
| @@ -1984,8 +1959,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | |||
| 1984 | 1959 | ||
| 1985 | static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, | 1960 | static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, |
| 1986 | u32 permissions) { | 1961 | u32 permissions) { |
| 1987 | return CreateTransferMemory(system, handle, static_cast<VAddr>(addr), | 1962 | return CreateTransferMemory(system, handle, addr, size, permissions); |
| 1988 | static_cast<std::size_t>(size), permissions); | ||
| 1989 | } | 1963 | } |
| 1990 | 1964 | ||
| 1991 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, | 1965 | static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, |
| @@ -2003,7 +1977,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 2003 | } | 1977 | } |
| 2004 | 1978 | ||
| 2005 | *core = thread->GetIdealCore(); | 1979 | *core = thread->GetIdealCore(); |
| 2006 | *mask = thread->GetAffinityMask(); | 1980 | *mask = thread->GetAffinityMask().GetAffinityMask(); |
| 2007 | 1981 | ||
| 2008 | return RESULT_SUCCESS; | 1982 | return RESULT_SUCCESS; |
| 2009 | } | 1983 | } |
| @@ -2075,8 +2049,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, | |||
| 2075 | 2049 | ||
| 2076 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, | 2050 | static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, |
| 2077 | u32 affinity_mask_low, u32 affinity_mask_high) { | 2051 | u32 affinity_mask_low, u32 affinity_mask_high) { |
| 2078 | const u64 affinity_mask = | 2052 | const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32); |
| 2079 | static_cast<u64>(affinity_mask_low) | (static_cast<u64>(affinity_mask_high) << 32); | ||
| 2080 | return SetThreadCoreMask(system, thread_handle, core, affinity_mask); | 2053 | return SetThreadCoreMask(system, thread_handle, core, affinity_mask); |
| 2081 | } | 2054 | } |
| 2082 | 2055 | ||
| @@ -2341,9 +2314,10 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd | |||
| 2341 | return RESULT_SUCCESS; | 2314 | return RESULT_SUCCESS; |
| 2342 | } | 2315 | } |
| 2343 | 2316 | ||
| 2344 | static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address, | 2317 | static ResultCode FlushProcessDataCache32([[maybe_unused]] Core::System& system, |
| 2345 | u32 size) { | 2318 | [[maybe_unused]] Handle handle, |
| 2346 | // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope | 2319 | [[maybe_unused]] u32 address, [[maybe_unused]] u32 size) { |
| 2320 | // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, | ||
| 2347 | // as all emulation is done in the same cache level in host architecture, thus data cache | 2321 | // as all emulation is done in the same cache level in host architecture, thus data cache |
| 2348 | // does not need flushing. | 2322 | // does not need flushing. |
| 2349 | LOG_DEBUG(Kernel_SVC, "called"); | 2323 | LOG_DEBUG(Kernel_SVC, "called"); |
| @@ -2639,6 +2613,9 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2639 | auto& kernel = system.Kernel(); | 2613 | auto& kernel = system.Kernel(); |
| 2640 | kernel.EnterSVCProfile(); | 2614 | kernel.EnterSVCProfile(); |
| 2641 | 2615 | ||
| 2616 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); | ||
| 2617 | thread->SetContinuousOnSVC(true); | ||
| 2618 | |||
| 2642 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) | 2619 | const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) |
| 2643 | : GetSVCInfo32(immediate); | 2620 | : GetSVCInfo32(immediate); |
| 2644 | if (info) { | 2621 | if (info) { |
| @@ -2652,6 +2629,12 @@ void Call(Core::System& system, u32 immediate) { | |||
| 2652 | } | 2629 | } |
| 2653 | 2630 | ||
| 2654 | kernel.ExitSVCProfile(); | 2631 | kernel.ExitSVCProfile(); |
| 2632 | |||
| 2633 | if (!thread->IsContinuousOnSVC()) { | ||
| 2634 | auto* host_context = thread->GetHostContext().get(); | ||
| 2635 | host_context->Rewind(); | ||
| 2636 | } | ||
| 2637 | |||
| 2655 | system.EnterDynarmicProfile(); | 2638 | system.EnterDynarmicProfile(); |
| 2656 | } | 2639 | } |
| 2657 | 2640 | ||
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 986724beb..11e1d8e2d 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -23,8 +23,8 @@ enum class MemoryState : u32 { | |||
| 23 | Ipc = 0x0A, | 23 | Ipc = 0x0A, |
| 24 | Stack = 0x0B, | 24 | Stack = 0x0B, |
| 25 | ThreadLocal = 0x0C, | 25 | ThreadLocal = 0x0C, |
| 26 | Transfered = 0x0D, | 26 | Transferred = 0x0D, |
| 27 | SharedTransfered = 0x0E, | 27 | SharedTransferred = 0x0E, |
| 28 | SharedCode = 0x0F, | 28 | SharedCode = 0x0F, |
| 29 | Inaccessible = 0x10, | 29 | Inaccessible = 0x10, |
| 30 | NonSecureIpc = 0x11, | 30 | NonSecureIpc = 0x11, |
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 8b875d853..d3f520ea2 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp | |||
| @@ -5,8 +5,9 @@ | |||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/errors.h" | 6 | #include "core/hle/kernel/errors.h" |
| 7 | #include "core/hle/kernel/handle_table.h" | 7 | #include "core/hle/kernel/handle_table.h" |
| 8 | #include "core/hle/kernel/k_scheduler.h" | ||
| 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 9 | #include "core/hle/kernel/scheduler.h" | ||
| 10 | #include "core/hle/kernel/synchronization.h" | 11 | #include "core/hle/kernel/synchronization.h" |
| 11 | #include "core/hle/kernel/synchronization_object.h" | 12 | #include "core/hle/kernel/synchronization_object.h" |
| 12 | #include "core/hle/kernel/thread.h" | 13 | #include "core/hle/kernel/thread.h" |
| @@ -18,7 +19,7 @@ Synchronization::Synchronization(Core::System& system) : system{system} {} | |||
| 18 | 19 | ||
| 19 | void Synchronization::SignalObject(SynchronizationObject& obj) const { | 20 | void Synchronization::SignalObject(SynchronizationObject& obj) const { |
| 20 | auto& kernel = system.Kernel(); | 21 | auto& kernel = system.Kernel(); |
| 21 | SchedulerLock lock(kernel); | 22 | KScopedSchedulerLock lock(kernel); |
| 22 | if (obj.IsSignaled()) { | 23 | if (obj.IsSignaled()) { |
| 23 | for (auto thread : obj.GetWaitingThreads()) { | 24 | for (auto thread : obj.GetWaitingThreads()) { |
| 24 | if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { | 25 | if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { |
| @@ -37,10 +38,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { | |||
| 37 | std::pair<ResultCode, Handle> Synchronization::WaitFor( | 38 | std::pair<ResultCode, Handle> Synchronization::WaitFor( |
| 38 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { | 39 | std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { |
| 39 | auto& kernel = system.Kernel(); | 40 | auto& kernel = system.Kernel(); |
| 40 | auto* const thread = system.CurrentScheduler().GetCurrentThread(); | 41 | auto* const thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 41 | Handle event_handle = InvalidHandle; | 42 | Handle event_handle = InvalidHandle; |
| 42 | { | 43 | { |
| 43 | SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); | 44 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); |
| 44 | const auto itr = | 45 | const auto itr = |
| 45 | std::find_if(sync_objects.begin(), sync_objects.end(), | 46 | std::find_if(sync_objects.begin(), sync_objects.end(), |
| 46 | [thread](const std::shared_ptr<SynchronizationObject>& object) { | 47 | [thread](const std::shared_ptr<SynchronizationObject>& object) { |
| @@ -89,7 +90,7 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor( | |||
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | { | 92 | { |
| 92 | SchedulerLock lock(kernel); | 93 | KScopedSchedulerLock lock(kernel); |
| 93 | ResultCode signaling_result = thread->GetSignalingResult(); | 94 | ResultCode signaling_result = thread->GetSignalingResult(); |
| 94 | SynchronizationObject* signaling_object = thread->GetSignalingObject(); | 95 | SynchronizationObject* signaling_object = thread->GetSignalingObject(); |
| 95 | thread->SetSynchronizationObjects(nullptr); | 96 | thread->SetSynchronizationObjects(nullptr); |
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index f89b24204..7408ed51f 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| @@ -56,7 +57,7 @@ public: | |||
| 56 | void ClearWaitingThreads(); | 57 | void ClearWaitingThreads(); |
| 57 | 58 | ||
| 58 | protected: | 59 | protected: |
| 59 | bool is_signaled{}; // Tells if this sync object is signalled; | 60 | std::atomic_bool is_signaled{}; // Tells if this sync object is signaled |
| 60 | 61 | ||
| 61 | private: | 62 | private: |
| 62 | /// Threads waiting for this object to become available | 63 | /// Threads waiting for this object to become available |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d132aba34..a4f9e0d97 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -12,17 +12,16 @@ | |||
| 12 | #include "common/fiber.h" | 12 | #include "common/fiber.h" |
| 13 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 14 | #include "common/thread_queue_list.h" | 14 | #include "common/thread_queue_list.h" |
| 15 | #include "core/arm/arm_interface.h" | ||
| 16 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 17 | #include "core/core.h" | 15 | #include "core/core.h" |
| 18 | #include "core/cpu_manager.h" | 16 | #include "core/cpu_manager.h" |
| 19 | #include "core/hardware_properties.h" | 17 | #include "core/hardware_properties.h" |
| 20 | #include "core/hle/kernel/errors.h" | 18 | #include "core/hle/kernel/errors.h" |
| 21 | #include "core/hle/kernel/handle_table.h" | 19 | #include "core/hle/kernel/handle_table.h" |
| 20 | #include "core/hle/kernel/k_scheduler.h" | ||
| 21 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 22 | #include "core/hle/kernel/kernel.h" | 22 | #include "core/hle/kernel/kernel.h" |
| 23 | #include "core/hle/kernel/object.h" | 23 | #include "core/hle/kernel/object.h" |
| 24 | #include "core/hle/kernel/process.h" | 24 | #include "core/hle/kernel/process.h" |
| 25 | #include "core/hle/kernel/scheduler.h" | ||
| 26 | #include "core/hle/kernel/thread.h" | 25 | #include "core/hle/kernel/thread.h" |
| 27 | #include "core/hle/kernel/time_manager.h" | 26 | #include "core/hle/kernel/time_manager.h" |
| 28 | #include "core/hle/result.h" | 27 | #include "core/hle/result.h" |
| @@ -52,7 +51,7 @@ Thread::~Thread() = default; | |||
| 52 | 51 | ||
| 53 | void Thread::Stop() { | 52 | void Thread::Stop() { |
| 54 | { | 53 | { |
| 55 | SchedulerLock lock(kernel); | 54 | KScopedSchedulerLock lock(kernel); |
| 56 | SetStatus(ThreadStatus::Dead); | 55 | SetStatus(ThreadStatus::Dead); |
| 57 | Signal(); | 56 | Signal(); |
| 58 | kernel.GlobalHandleTable().Close(global_handle); | 57 | kernel.GlobalHandleTable().Close(global_handle); |
| @@ -63,14 +62,13 @@ void Thread::Stop() { | |||
| 63 | // Mark the TLS slot in the thread's page as free. | 62 | // Mark the TLS slot in the thread's page as free. |
| 64 | owner_process->FreeTLSRegion(tls_address); | 63 | owner_process->FreeTLSRegion(tls_address); |
| 65 | } | 64 | } |
| 66 | arm_interface.reset(); | ||
| 67 | has_exited = true; | 65 | has_exited = true; |
| 68 | } | 66 | } |
| 69 | global_handle = 0; | 67 | global_handle = 0; |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | void Thread::ResumeFromWait() { | 70 | void Thread::ResumeFromWait() { |
| 73 | SchedulerLock lock(kernel); | 71 | KScopedSchedulerLock lock(kernel); |
| 74 | switch (status) { | 72 | switch (status) { |
| 75 | case ThreadStatus::Paused: | 73 | case ThreadStatus::Paused: |
| 76 | case ThreadStatus::WaitSynch: | 74 | case ThreadStatus::WaitSynch: |
| @@ -91,10 +89,6 @@ void Thread::ResumeFromWait() { | |||
| 91 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | 89 | // before actually resuming. We can ignore subsequent wakeups if the thread status has |
| 92 | // already been set to ThreadStatus::Ready. | 90 | // already been set to ThreadStatus::Ready. |
| 93 | return; | 91 | return; |
| 94 | |||
| 95 | case ThreadStatus::Running: | ||
| 96 | DEBUG_ASSERT_MSG(false, "Thread with object id {} has already resumed.", GetObjectId()); | ||
| 97 | return; | ||
| 98 | case ThreadStatus::Dead: | 92 | case ThreadStatus::Dead: |
| 99 | // This should never happen, as threads must complete before being stopped. | 93 | // This should never happen, as threads must complete before being stopped. |
| 100 | DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", | 94 | DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", |
| @@ -106,19 +100,18 @@ void Thread::ResumeFromWait() { | |||
| 106 | } | 100 | } |
| 107 | 101 | ||
| 108 | void Thread::OnWakeUp() { | 102 | void Thread::OnWakeUp() { |
| 109 | SchedulerLock lock(kernel); | 103 | KScopedSchedulerLock lock(kernel); |
| 110 | |||
| 111 | SetStatus(ThreadStatus::Ready); | 104 | SetStatus(ThreadStatus::Ready); |
| 112 | } | 105 | } |
| 113 | 106 | ||
| 114 | ResultCode Thread::Start() { | 107 | ResultCode Thread::Start() { |
| 115 | SchedulerLock lock(kernel); | 108 | KScopedSchedulerLock lock(kernel); |
| 116 | SetStatus(ThreadStatus::Ready); | 109 | SetStatus(ThreadStatus::Ready); |
| 117 | return RESULT_SUCCESS; | 110 | return RESULT_SUCCESS; |
| 118 | } | 111 | } |
| 119 | 112 | ||
| 120 | void Thread::CancelWait() { | 113 | void Thread::CancelWait() { |
| 121 | SchedulerLock lock(kernel); | 114 | KScopedSchedulerLock lock(kernel); |
| 122 | if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { | 115 | if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { |
| 123 | is_sync_cancelled = true; | 116 | is_sync_cancelled = true; |
| 124 | return; | 117 | return; |
| @@ -193,12 +186,14 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 193 | thread->status = ThreadStatus::Dormant; | 186 | thread->status = ThreadStatus::Dormant; |
| 194 | thread->entry_point = entry_point; | 187 | thread->entry_point = entry_point; |
| 195 | thread->stack_top = stack_top; | 188 | thread->stack_top = stack_top; |
| 189 | thread->disable_count = 1; | ||
| 196 | thread->tpidr_el0 = 0; | 190 | thread->tpidr_el0 = 0; |
| 197 | thread->nominal_priority = thread->current_priority = priority; | 191 | thread->nominal_priority = thread->current_priority = priority; |
| 198 | thread->last_running_ticks = 0; | 192 | thread->schedule_count = -1; |
| 193 | thread->last_scheduled_tick = 0; | ||
| 199 | thread->processor_id = processor_id; | 194 | thread->processor_id = processor_id; |
| 200 | thread->ideal_core = processor_id; | 195 | thread->ideal_core = processor_id; |
| 201 | thread->affinity_mask = 1ULL << processor_id; | 196 | thread->affinity_mask.SetAffinity(processor_id, true); |
| 202 | thread->wait_objects = nullptr; | 197 | thread->wait_objects = nullptr; |
| 203 | thread->mutex_wait_address = 0; | 198 | thread->mutex_wait_address = 0; |
| 204 | thread->condvar_wait_address = 0; | 199 | thread->condvar_wait_address = 0; |
| @@ -208,7 +203,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 208 | thread->owner_process = owner_process; | 203 | thread->owner_process = owner_process; |
| 209 | thread->type = type_flags; | 204 | thread->type = type_flags; |
| 210 | if ((type_flags & THREADTYPE_IDLE) == 0) { | 205 | if ((type_flags & THREADTYPE_IDLE) == 0) { |
| 211 | auto& scheduler = kernel.GlobalScheduler(); | 206 | auto& scheduler = kernel.GlobalSchedulerContext(); |
| 212 | scheduler.AddThread(thread); | 207 | scheduler.AddThread(thread); |
| 213 | } | 208 | } |
| 214 | if (owner_process) { | 209 | if (owner_process) { |
| @@ -217,33 +212,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 217 | } else { | 212 | } else { |
| 218 | thread->tls_address = 0; | 213 | thread->tls_address = 0; |
| 219 | } | 214 | } |
| 215 | |||
| 220 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | 216 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used |
| 221 | // to initialize the context | 217 | // to initialize the context |
| 222 | thread->arm_interface.reset(); | ||
| 223 | if ((type_flags & THREADTYPE_HLE) == 0) { | 218 | if ((type_flags & THREADTYPE_HLE) == 0) { |
| 224 | #ifdef ARCHITECTURE_x86_64 | ||
| 225 | if (owner_process && !owner_process->Is64BitProcess()) { | ||
| 226 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( | ||
| 227 | system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), | ||
| 228 | processor_id); | ||
| 229 | } else { | ||
| 230 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | ||
| 231 | system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), | ||
| 232 | processor_id); | ||
| 233 | } | ||
| 234 | |||
| 235 | #else | ||
| 236 | if (owner_process && !owner_process->Is64BitProcess()) { | ||
| 237 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( | ||
| 238 | system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32, | ||
| 239 | processor_id); | ||
| 240 | } else { | ||
| 241 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( | ||
| 242 | system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64, | ||
| 243 | processor_id); | ||
| 244 | } | ||
| 245 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | ||
| 246 | #endif | ||
| 247 | ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), | 219 | ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), |
| 248 | static_cast<u32>(entry_point), static_cast<u32>(arg)); | 220 | static_cast<u32>(entry_point), static_cast<u32>(arg)); |
| 249 | ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); | 221 | ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); |
| @@ -255,7 +227,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 255 | } | 227 | } |
| 256 | 228 | ||
| 257 | void Thread::SetPriority(u32 priority) { | 229 | void Thread::SetPriority(u32 priority) { |
| 258 | SchedulerLock lock(kernel); | 230 | KScopedSchedulerLock lock(kernel); |
| 259 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, | 231 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, |
| 260 | "Invalid priority value."); | 232 | "Invalid priority value."); |
| 261 | nominal_priority = priority; | 233 | nominal_priority = priority; |
| @@ -279,14 +251,6 @@ VAddr Thread::GetCommandBufferAddress() const { | |||
| 279 | return GetTLSAddress() + command_header_offset; | 251 | return GetTLSAddress() + command_header_offset; |
| 280 | } | 252 | } |
| 281 | 253 | ||
| 282 | Core::ARM_Interface& Thread::ArmInterface() { | ||
| 283 | return *arm_interface; | ||
| 284 | } | ||
| 285 | |||
| 286 | const Core::ARM_Interface& Thread::ArmInterface() const { | ||
| 287 | return *arm_interface; | ||
| 288 | } | ||
| 289 | |||
| 290 | void Thread::SetStatus(ThreadStatus new_status) { | 254 | void Thread::SetStatus(ThreadStatus new_status) { |
| 291 | if (new_status == status) { | 255 | if (new_status == status) { |
| 292 | return; | 256 | return; |
| @@ -294,7 +258,6 @@ void Thread::SetStatus(ThreadStatus new_status) { | |||
| 294 | 258 | ||
| 295 | switch (new_status) { | 259 | switch (new_status) { |
| 296 | case ThreadStatus::Ready: | 260 | case ThreadStatus::Ready: |
| 297 | case ThreadStatus::Running: | ||
| 298 | SetSchedulingStatus(ThreadSchedStatus::Runnable); | 261 | SetSchedulingStatus(ThreadSchedStatus::Runnable); |
| 299 | break; | 262 | break; |
| 300 | case ThreadStatus::Dormant: | 263 | case ThreadStatus::Dormant: |
| @@ -401,7 +364,7 @@ bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) { | |||
| 401 | } | 364 | } |
| 402 | 365 | ||
| 403 | ResultCode Thread::SetActivity(ThreadActivity value) { | 366 | ResultCode Thread::SetActivity(ThreadActivity value) { |
| 404 | SchedulerLock lock(kernel); | 367 | KScopedSchedulerLock lock(kernel); |
| 405 | 368 | ||
| 406 | auto sched_status = GetSchedulingStatus(); | 369 | auto sched_status = GetSchedulingStatus(); |
| 407 | 370 | ||
| @@ -430,7 +393,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) { | |||
| 430 | ResultCode Thread::Sleep(s64 nanoseconds) { | 393 | ResultCode Thread::Sleep(s64 nanoseconds) { |
| 431 | Handle event_handle{}; | 394 | Handle event_handle{}; |
| 432 | { | 395 | { |
| 433 | SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); | 396 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); |
| 434 | SetStatus(ThreadStatus::WaitSleep); | 397 | SetStatus(ThreadStatus::WaitSleep); |
| 435 | } | 398 | } |
| 436 | 399 | ||
| @@ -441,39 +404,12 @@ ResultCode Thread::Sleep(s64 nanoseconds) { | |||
| 441 | return RESULT_SUCCESS; | 404 | return RESULT_SUCCESS; |
| 442 | } | 405 | } |
| 443 | 406 | ||
| 444 | std::pair<ResultCode, bool> Thread::YieldSimple() { | ||
| 445 | bool is_redundant = false; | ||
| 446 | { | ||
| 447 | SchedulerLock lock(kernel); | ||
| 448 | is_redundant = kernel.GlobalScheduler().YieldThread(this); | ||
| 449 | } | ||
| 450 | return {RESULT_SUCCESS, is_redundant}; | ||
| 451 | } | ||
| 452 | |||
| 453 | std::pair<ResultCode, bool> Thread::YieldAndBalanceLoad() { | ||
| 454 | bool is_redundant = false; | ||
| 455 | { | ||
| 456 | SchedulerLock lock(kernel); | ||
| 457 | is_redundant = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); | ||
| 458 | } | ||
| 459 | return {RESULT_SUCCESS, is_redundant}; | ||
| 460 | } | ||
| 461 | |||
| 462 | std::pair<ResultCode, bool> Thread::YieldAndWaitForLoadBalancing() { | ||
| 463 | bool is_redundant = false; | ||
| 464 | { | ||
| 465 | SchedulerLock lock(kernel); | ||
| 466 | is_redundant = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); | ||
| 467 | } | ||
| 468 | return {RESULT_SUCCESS, is_redundant}; | ||
| 469 | } | ||
| 470 | |||
| 471 | void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { | 407 | void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { |
| 472 | const u32 old_state = scheduling_state; | 408 | const u32 old_state = scheduling_state; |
| 473 | pausing_state |= static_cast<u32>(flag); | 409 | pausing_state |= static_cast<u32>(flag); |
| 474 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); | 410 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); |
| 475 | scheduling_state = base_scheduling | pausing_state; | 411 | scheduling_state = base_scheduling | pausing_state; |
| 476 | kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); | 412 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 477 | } | 413 | } |
| 478 | 414 | ||
| 479 | void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { | 415 | void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { |
| @@ -481,23 +417,24 @@ void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { | |||
| 481 | pausing_state &= ~static_cast<u32>(flag); | 417 | pausing_state &= ~static_cast<u32>(flag); |
| 482 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); | 418 | const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); |
| 483 | scheduling_state = base_scheduling | pausing_state; | 419 | scheduling_state = base_scheduling | pausing_state; |
| 484 | kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); | 420 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 485 | } | 421 | } |
| 486 | 422 | ||
| 487 | void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { | 423 | void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { |
| 488 | const u32 old_state = scheduling_state; | 424 | const u32 old_state = scheduling_state; |
| 489 | scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) | | 425 | scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) | |
| 490 | static_cast<u32>(new_status); | 426 | static_cast<u32>(new_status); |
| 491 | kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); | 427 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 492 | } | 428 | } |
| 493 | 429 | ||
| 494 | void Thread::SetCurrentPriority(u32 new_priority) { | 430 | void Thread::SetCurrentPriority(u32 new_priority) { |
| 495 | const u32 old_priority = std::exchange(current_priority, new_priority); | 431 | const u32 old_priority = std::exchange(current_priority, new_priority); |
| 496 | kernel.GlobalScheduler().AdjustSchedulingOnPriority(this, old_priority); | 432 | KScheduler::OnThreadPriorityChanged(kernel, this, kernel.CurrentScheduler()->GetCurrentThread(), |
| 433 | old_priority); | ||
| 497 | } | 434 | } |
| 498 | 435 | ||
| 499 | ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { | 436 | ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { |
| 500 | SchedulerLock lock(kernel); | 437 | KScopedSchedulerLock lock(kernel); |
| 501 | const auto HighestSetCore = [](u64 mask, u32 max_cores) { | 438 | const auto HighestSetCore = [](u64 mask, u32 max_cores) { |
| 502 | for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) { | 439 | for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) { |
| 503 | if (((mask >> core) & 1) != 0) { | 440 | if (((mask >> core) & 1) != 0) { |
| @@ -518,20 +455,21 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { | |||
| 518 | } | 455 | } |
| 519 | if (use_override) { | 456 | if (use_override) { |
| 520 | ideal_core_override = new_core; | 457 | ideal_core_override = new_core; |
| 521 | affinity_mask_override = new_affinity_mask; | ||
| 522 | } else { | 458 | } else { |
| 523 | const u64 old_affinity_mask = std::exchange(affinity_mask, new_affinity_mask); | 459 | const auto old_affinity_mask = affinity_mask; |
| 460 | affinity_mask.SetAffinityMask(new_affinity_mask); | ||
| 524 | ideal_core = new_core; | 461 | ideal_core = new_core; |
| 525 | if (old_affinity_mask != new_affinity_mask) { | 462 | if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) { |
| 526 | const s32 old_core = processor_id; | 463 | const s32 old_core = processor_id; |
| 527 | if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { | 464 | if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) { |
| 528 | if (static_cast<s32>(ideal_core) < 0) { | 465 | if (static_cast<s32>(ideal_core) < 0) { |
| 529 | processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES); | 466 | processor_id = HighestSetCore(affinity_mask.GetAffinityMask(), |
| 467 | Core::Hardware::NUM_CPU_CORES); | ||
| 530 | } else { | 468 | } else { |
| 531 | processor_id = ideal_core; | 469 | processor_id = ideal_core; |
| 532 | } | 470 | } |
| 533 | } | 471 | } |
| 534 | kernel.GlobalScheduler().AdjustSchedulingOnAffinity(this, old_affinity_mask, old_core); | 472 | KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core); |
| 535 | } | 473 | } |
| 536 | } | 474 | } |
| 537 | return RESULT_SUCCESS; | 475 | return RESULT_SUCCESS; |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 8daf79fac..11ef29888 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <functional> | 8 | #include <functional> |
| 8 | #include <string> | 9 | #include <string> |
| 9 | #include <utility> | 10 | #include <utility> |
| @@ -12,6 +13,7 @@ | |||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "common/spin_lock.h" | 14 | #include "common/spin_lock.h" |
| 14 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/hle/kernel/k_affinity_mask.h" | ||
| 15 | #include "core/hle/kernel/object.h" | 17 | #include "core/hle/kernel/object.h" |
| 16 | #include "core/hle/kernel/synchronization_object.h" | 18 | #include "core/hle/kernel/synchronization_object.h" |
| 17 | #include "core/hle/result.h" | 19 | #include "core/hle/result.h" |
| @@ -27,10 +29,10 @@ class System; | |||
| 27 | 29 | ||
| 28 | namespace Kernel { | 30 | namespace Kernel { |
| 29 | 31 | ||
| 30 | class GlobalScheduler; | 32 | class GlobalSchedulerContext; |
| 31 | class KernelCore; | 33 | class KernelCore; |
| 32 | class Process; | 34 | class Process; |
| 33 | class Scheduler; | 35 | class KScheduler; |
| 34 | 36 | ||
| 35 | enum ThreadPriority : u32 { | 37 | enum ThreadPriority : u32 { |
| 36 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority | 38 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority |
| @@ -72,7 +74,6 @@ enum ThreadProcessorId : s32 { | |||
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| 74 | enum class ThreadStatus { | 76 | enum class ThreadStatus { |
| 75 | Running, ///< Currently running | ||
| 76 | Ready, ///< Ready to run | 77 | Ready, ///< Ready to run |
| 77 | Paused, ///< Paused by SetThreadActivity or debug | 78 | Paused, ///< Paused by SetThreadActivity or debug |
| 78 | WaitHLEEvent, ///< Waiting for hle event to finish | 79 | WaitHLEEvent, ///< Waiting for hle event to finish |
| @@ -248,10 +249,6 @@ public: | |||
| 248 | 249 | ||
| 249 | void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); | 250 | void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); |
| 250 | 251 | ||
| 251 | Core::ARM_Interface& ArmInterface(); | ||
| 252 | |||
| 253 | const Core::ARM_Interface& ArmInterface() const; | ||
| 254 | |||
| 255 | SynchronizationObject* GetSignalingObject() const { | 252 | SynchronizationObject* GetSignalingObject() const { |
| 256 | return signaling_object; | 253 | return signaling_object; |
| 257 | } | 254 | } |
| @@ -350,8 +347,12 @@ public: | |||
| 350 | 347 | ||
| 351 | void SetStatus(ThreadStatus new_status); | 348 | void SetStatus(ThreadStatus new_status); |
| 352 | 349 | ||
| 353 | u64 GetLastRunningTicks() const { | 350 | s64 GetLastScheduledTick() const { |
| 354 | return last_running_ticks; | 351 | return this->last_scheduled_tick; |
| 352 | } | ||
| 353 | |||
| 354 | void SetLastScheduledTick(s64 tick) { | ||
| 355 | this->last_scheduled_tick = tick; | ||
| 355 | } | 356 | } |
| 356 | 357 | ||
| 357 | u64 GetTotalCPUTimeTicks() const { | 358 | u64 GetTotalCPUTimeTicks() const { |
| @@ -366,10 +367,18 @@ public: | |||
| 366 | return processor_id; | 367 | return processor_id; |
| 367 | } | 368 | } |
| 368 | 369 | ||
| 370 | s32 GetActiveCore() const { | ||
| 371 | return GetProcessorID(); | ||
| 372 | } | ||
| 373 | |||
| 369 | void SetProcessorID(s32 new_core) { | 374 | void SetProcessorID(s32 new_core) { |
| 370 | processor_id = new_core; | 375 | processor_id = new_core; |
| 371 | } | 376 | } |
| 372 | 377 | ||
| 378 | void SetActiveCore(s32 new_core) { | ||
| 379 | processor_id = new_core; | ||
| 380 | } | ||
| 381 | |||
| 373 | Process* GetOwnerProcess() { | 382 | Process* GetOwnerProcess() { |
| 374 | return owner_process; | 383 | return owner_process; |
| 375 | } | 384 | } |
| @@ -474,7 +483,7 @@ public: | |||
| 474 | return ideal_core; | 483 | return ideal_core; |
| 475 | } | 484 | } |
| 476 | 485 | ||
| 477 | u64 GetAffinityMask() const { | 486 | const KAffinityMask& GetAffinityMask() const { |
| 478 | return affinity_mask; | 487 | return affinity_mask; |
| 479 | } | 488 | } |
| 480 | 489 | ||
| @@ -483,21 +492,12 @@ public: | |||
| 483 | /// Sleeps this thread for the given amount of nanoseconds. | 492 | /// Sleeps this thread for the given amount of nanoseconds. |
| 484 | ResultCode Sleep(s64 nanoseconds); | 493 | ResultCode Sleep(s64 nanoseconds); |
| 485 | 494 | ||
| 486 | /// Yields this thread without rebalancing loads. | 495 | s64 GetYieldScheduleCount() const { |
| 487 | std::pair<ResultCode, bool> YieldSimple(); | 496 | return this->schedule_count; |
| 488 | |||
| 489 | /// Yields this thread and does a load rebalancing. | ||
| 490 | std::pair<ResultCode, bool> YieldAndBalanceLoad(); | ||
| 491 | |||
| 492 | /// Yields this thread and if the core is left idle, loads are rebalanced | ||
| 493 | std::pair<ResultCode, bool> YieldAndWaitForLoadBalancing(); | ||
| 494 | |||
| 495 | void IncrementYieldCount() { | ||
| 496 | yield_count++; | ||
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | u64 GetYieldCount() const { | 499 | void SetYieldScheduleCount(s64 count) { |
| 500 | return yield_count; | 500 | this->schedule_count = count; |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | ThreadSchedStatus GetSchedulingStatus() const { | 503 | ThreadSchedStatus GetSchedulingStatus() const { |
| @@ -573,9 +573,59 @@ public: | |||
| 573 | return has_exited; | 573 | return has_exited; |
| 574 | } | 574 | } |
| 575 | 575 | ||
| 576 | class QueueEntry { | ||
| 577 | public: | ||
| 578 | constexpr QueueEntry() = default; | ||
| 579 | |||
| 580 | constexpr void Initialize() { | ||
| 581 | this->prev = nullptr; | ||
| 582 | this->next = nullptr; | ||
| 583 | } | ||
| 584 | |||
| 585 | constexpr Thread* GetPrev() const { | ||
| 586 | return this->prev; | ||
| 587 | } | ||
| 588 | constexpr Thread* GetNext() const { | ||
| 589 | return this->next; | ||
| 590 | } | ||
| 591 | constexpr void SetPrev(Thread* thread) { | ||
| 592 | this->prev = thread; | ||
| 593 | } | ||
| 594 | constexpr void SetNext(Thread* thread) { | ||
| 595 | this->next = thread; | ||
| 596 | } | ||
| 597 | |||
| 598 | private: | ||
| 599 | Thread* prev{}; | ||
| 600 | Thread* next{}; | ||
| 601 | }; | ||
| 602 | |||
| 603 | QueueEntry& GetPriorityQueueEntry(s32 core) { | ||
| 604 | return this->per_core_priority_queue_entry[core]; | ||
| 605 | } | ||
| 606 | |||
| 607 | const QueueEntry& GetPriorityQueueEntry(s32 core) const { | ||
| 608 | return this->per_core_priority_queue_entry[core]; | ||
| 609 | } | ||
| 610 | |||
| 611 | s32 GetDisableDispatchCount() const { | ||
| 612 | return disable_count; | ||
| 613 | } | ||
| 614 | |||
| 615 | void DisableDispatch() { | ||
| 616 | ASSERT(GetDisableDispatchCount() >= 0); | ||
| 617 | disable_count++; | ||
| 618 | } | ||
| 619 | |||
| 620 | void EnableDispatch() { | ||
| 621 | ASSERT(GetDisableDispatchCount() > 0); | ||
| 622 | disable_count--; | ||
| 623 | } | ||
| 624 | |||
| 576 | private: | 625 | private: |
| 577 | friend class GlobalScheduler; | 626 | friend class GlobalSchedulerContext; |
| 578 | friend class Scheduler; | 627 | friend class KScheduler; |
| 628 | friend class Process; | ||
| 579 | 629 | ||
| 580 | void SetSchedulingStatus(ThreadSchedStatus new_status); | 630 | void SetSchedulingStatus(ThreadSchedStatus new_status); |
| 581 | void AddSchedulingFlag(ThreadSchedFlags flag); | 631 | void AddSchedulingFlag(ThreadSchedFlags flag); |
| @@ -586,15 +636,16 @@ private: | |||
| 586 | Common::SpinLock context_guard{}; | 636 | Common::SpinLock context_guard{}; |
| 587 | ThreadContext32 context_32{}; | 637 | ThreadContext32 context_32{}; |
| 588 | ThreadContext64 context_64{}; | 638 | ThreadContext64 context_64{}; |
| 589 | std::unique_ptr<Core::ARM_Interface> arm_interface{}; | ||
| 590 | std::shared_ptr<Common::Fiber> host_context{}; | 639 | std::shared_ptr<Common::Fiber> host_context{}; |
| 591 | 640 | ||
| 592 | u64 thread_id = 0; | ||
| 593 | |||
| 594 | ThreadStatus status = ThreadStatus::Dormant; | 641 | ThreadStatus status = ThreadStatus::Dormant; |
| 642 | u32 scheduling_state = 0; | ||
| 643 | |||
| 644 | u64 thread_id = 0; | ||
| 595 | 645 | ||
| 596 | VAddr entry_point = 0; | 646 | VAddr entry_point = 0; |
| 597 | VAddr stack_top = 0; | 647 | VAddr stack_top = 0; |
| 648 | std::atomic_int disable_count = 0; | ||
| 598 | 649 | ||
| 599 | ThreadType type; | 650 | ThreadType type; |
| 600 | 651 | ||
| @@ -608,9 +659,8 @@ private: | |||
| 608 | u32 current_priority = 0; | 659 | u32 current_priority = 0; |
| 609 | 660 | ||
| 610 | u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. | 661 | u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. |
| 611 | u64 last_running_ticks = 0; ///< CPU tick when thread was last running | 662 | s64 schedule_count{}; |
| 612 | u64 yield_count = 0; ///< Number of redundant yields carried by this thread. | 663 | s64 last_scheduled_tick{}; |
| 613 | ///< a redundant yield is one where no scheduling is changed | ||
| 614 | 664 | ||
| 615 | s32 processor_id = 0; | 665 | s32 processor_id = 0; |
| 616 | 666 | ||
| @@ -652,16 +702,16 @@ private: | |||
| 652 | Handle hle_time_event; | 702 | Handle hle_time_event; |
| 653 | SynchronizationObject* hle_object; | 703 | SynchronizationObject* hle_object; |
| 654 | 704 | ||
| 655 | Scheduler* scheduler = nullptr; | 705 | KScheduler* scheduler = nullptr; |
| 706 | |||
| 707 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | ||
| 656 | 708 | ||
| 657 | u32 ideal_core{0xFFFFFFFF}; | 709 | u32 ideal_core{0xFFFFFFFF}; |
| 658 | u64 affinity_mask{0x1}; | 710 | KAffinityMask affinity_mask{}; |
| 659 | 711 | ||
| 660 | s32 ideal_core_override = -1; | 712 | s32 ideal_core_override = -1; |
| 661 | u64 affinity_mask_override = 0x1; | ||
| 662 | u32 affinity_override_count = 0; | 713 | u32 affinity_override_count = 0; |
| 663 | 714 | ||
| 664 | u32 scheduling_state = 0; | ||
| 665 | u32 pausing_state = 0; | 715 | u32 pausing_state = 0; |
| 666 | bool is_running = false; | 716 | bool is_running = false; |
| 667 | bool is_waiting_on_sync = false; | 717 | bool is_waiting_on_sync = false; |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 95f2446c9..79628e2b4 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/core_timing_util.h" | 8 | #include "core/core_timing_util.h" |
| 9 | #include "core/hle/kernel/handle_table.h" | 9 | #include "core/hle/kernel/handle_table.h" |
| 10 | #include "core/hle/kernel/k_scheduler.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/scheduler.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | 13 | #include "core/hle/kernel/time_manager.h" |
| 14 | 14 | ||
| @@ -18,17 +18,27 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { | |||
| 18 | time_manager_event_type = Core::Timing::CreateEvent( | 18 | time_manager_event_type = Core::Timing::CreateEvent( |
| 19 | "Kernel::TimeManagerCallback", | 19 | "Kernel::TimeManagerCallback", |
| 20 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | 20 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { |
| 21 | const SchedulerLock lock(system.Kernel()); | 21 | const KScopedSchedulerLock lock(system.Kernel()); |
| 22 | const auto proper_handle = static_cast<Handle>(thread_handle); | 22 | const auto proper_handle = static_cast<Handle>(thread_handle); |
| 23 | if (cancelled_events[proper_handle]) { | 23 | |
| 24 | return; | 24 | std::shared_ptr<Thread> thread; |
| 25 | { | ||
| 26 | std::lock_guard lock{mutex}; | ||
| 27 | if (cancelled_events[proper_handle]) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | thread = system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); | ||
| 31 | } | ||
| 32 | |||
| 33 | if (thread) { | ||
| 34 | // Thread can be null if process has exited | ||
| 35 | thread->OnWakeUp(); | ||
| 25 | } | 36 | } |
| 26 | auto thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); | ||
| 27 | thread->OnWakeUp(); | ||
| 28 | }); | 37 | }); |
| 29 | } | 38 | } |
| 30 | 39 | ||
| 31 | void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { | 40 | void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { |
| 41 | std::lock_guard lock{mutex}; | ||
| 32 | event_handle = timetask->GetGlobalHandle(); | 42 | event_handle = timetask->GetGlobalHandle(); |
| 33 | if (nanoseconds > 0) { | 43 | if (nanoseconds > 0) { |
| 34 | ASSERT(timetask); | 44 | ASSERT(timetask); |
| @@ -43,6 +53,7 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 | |||
| 43 | } | 53 | } |
| 44 | 54 | ||
| 45 | void TimeManager::UnscheduleTimeEvent(Handle event_handle) { | 55 | void TimeManager::UnscheduleTimeEvent(Handle event_handle) { |
| 56 | std::lock_guard lock{mutex}; | ||
| 46 | if (event_handle == InvalidHandle) { | 57 | if (event_handle == InvalidHandle) { |
| 47 | return; | 58 | return; |
| 48 | } | 59 | } |
| @@ -51,7 +62,8 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) { | |||
| 51 | } | 62 | } |
| 52 | 63 | ||
| 53 | void TimeManager::CancelTimeEvent(Thread* time_task) { | 64 | void TimeManager::CancelTimeEvent(Thread* time_task) { |
| 54 | Handle event_handle = time_task->GetGlobalHandle(); | 65 | std::lock_guard lock{mutex}; |
| 66 | const Handle event_handle = time_task->GetGlobalHandle(); | ||
| 55 | UnscheduleTimeEvent(event_handle); | 67 | UnscheduleTimeEvent(event_handle); |
| 56 | } | 68 | } |
| 57 | 69 | ||
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 307a18765..f39df39a0 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <mutex> | ||
| 8 | #include <unordered_map> | 9 | #include <unordered_map> |
| 9 | 10 | ||
| 10 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| @@ -42,6 +43,7 @@ private: | |||
| 42 | Core::System& system; | 43 | Core::System& system; |
| 43 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; | 44 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; |
| 44 | std::unordered_map<Handle, bool> cancelled_events; | 45 | std::unordered_map<Handle, bool> cancelled_events; |
| 46 | std::mutex mutex; | ||
| 45 | }; | 47 | }; |
| 46 | 48 | ||
| 47 | } // namespace Kernel | 49 | } // namespace Kernel |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index b6bdbd988..8feda7ad7 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -119,7 +119,7 @@ union ResultCode { | |||
| 119 | BitField<0, 9, ErrorModule> module; | 119 | BitField<0, 9, ErrorModule> module; |
| 120 | BitField<9, 13, u32> description; | 120 | BitField<9, 13, u32> description; |
| 121 | 121 | ||
| 122 | constexpr explicit ResultCode(u32 raw) : raw(raw) {} | 122 | constexpr explicit ResultCode(u32 raw_) : raw(raw_) {} |
| 123 | 123 | ||
| 124 | constexpr ResultCode(ErrorModule module_, u32 description_) | 124 | constexpr ResultCode(ErrorModule module_, u32 description_) |
| 125 | : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} | 125 | : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6b1613510..6981f8ee7 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 12 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 13 | #include "core/constants.h" | 13 | #include "core/constants.h" |
| 14 | #include "core/core.h" | ||
| 14 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 15 | #include "core/file_sys/control_metadata.h" | 16 | #include "core/file_sys/control_metadata.h" |
| 16 | #include "core/file_sys/patch_manager.h" | 17 | #include "core/file_sys/patch_manager.h" |
| @@ -46,8 +47,8 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) { | |||
| 46 | 47 | ||
| 47 | class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { | 48 | class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { |
| 48 | public: | 49 | public: |
| 49 | explicit IManagerForSystemService(Common::UUID user_id) | 50 | explicit IManagerForSystemService(Core::System& system_, Common::UUID) |
| 50 | : ServiceFramework("IManagerForSystemService") { | 51 | : ServiceFramework{system_, "IManagerForSystemService"} { |
| 51 | // clang-format off | 52 | // clang-format off |
| 52 | static const FunctionInfo functions[] = { | 53 | static const FunctionInfo functions[] = { |
| 53 | {0, nullptr, "CheckAvailability"}, | 54 | {0, nullptr, "CheckAvailability"}, |
| @@ -82,8 +83,8 @@ public: | |||
| 82 | // 3.0.0+ | 83 | // 3.0.0+ |
| 83 | class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> { | 84 | class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> { |
| 84 | public: | 85 | public: |
| 85 | explicit IFloatingRegistrationRequest(Common::UUID user_id) | 86 | explicit IFloatingRegistrationRequest(Core::System& system_, Common::UUID) |
| 86 | : ServiceFramework("IFloatingRegistrationRequest") { | 87 | : ServiceFramework{system_, "IFloatingRegistrationRequest"} { |
| 87 | // clang-format off | 88 | // clang-format off |
| 88 | static const FunctionInfo functions[] = { | 89 | static const FunctionInfo functions[] = { |
| 89 | {0, nullptr, "GetSessionId"}, | 90 | {0, nullptr, "GetSessionId"}, |
| @@ -107,7 +108,8 @@ public: | |||
| 107 | 108 | ||
| 108 | class IAdministrator final : public ServiceFramework<IAdministrator> { | 109 | class IAdministrator final : public ServiceFramework<IAdministrator> { |
| 109 | public: | 110 | public: |
| 110 | explicit IAdministrator(Common::UUID user_id) : ServiceFramework("IAdministrator") { | 111 | explicit IAdministrator(Core::System& system_, Common::UUID) |
| 112 | : ServiceFramework{system_, "IAdministrator"} { | ||
| 111 | // clang-format off | 113 | // clang-format off |
| 112 | static const FunctionInfo functions[] = { | 114 | static const FunctionInfo functions[] = { |
| 113 | {0, nullptr, "CheckAvailability"}, | 115 | {0, nullptr, "CheckAvailability"}, |
| @@ -164,8 +166,8 @@ public: | |||
| 164 | 166 | ||
| 165 | class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> { | 167 | class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> { |
| 166 | public: | 168 | public: |
| 167 | explicit IAuthorizationRequest(Common::UUID user_id) | 169 | explicit IAuthorizationRequest(Core::System& system_, Common::UUID) |
| 168 | : ServiceFramework("IAuthorizationRequest") { | 170 | : ServiceFramework{system_, "IAuthorizationRequest"} { |
| 169 | // clang-format off | 171 | // clang-format off |
| 170 | static const FunctionInfo functions[] = { | 172 | static const FunctionInfo functions[] = { |
| 171 | {0, nullptr, "GetSessionId"}, | 173 | {0, nullptr, "GetSessionId"}, |
| @@ -183,7 +185,8 @@ public: | |||
| 183 | 185 | ||
| 184 | class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> { | 186 | class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> { |
| 185 | public: | 187 | public: |
| 186 | explicit IOAuthProcedure(Common::UUID user_id) : ServiceFramework("IOAuthProcedure") { | 188 | explicit IOAuthProcedure(Core::System& system_, Common::UUID) |
| 189 | : ServiceFramework{system_, "IOAuthProcedure"} { | ||
| 187 | // clang-format off | 190 | // clang-format off |
| 188 | static const FunctionInfo functions[] = { | 191 | static const FunctionInfo functions[] = { |
| 189 | {0, nullptr, "PrepareAsync"}, | 192 | {0, nullptr, "PrepareAsync"}, |
| @@ -201,8 +204,8 @@ public: | |||
| 201 | // 3.0.0+ | 204 | // 3.0.0+ |
| 202 | class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> { | 205 | class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> { |
| 203 | public: | 206 | public: |
| 204 | explicit IOAuthProcedureForExternalNsa(Common::UUID user_id) | 207 | explicit IOAuthProcedureForExternalNsa(Core::System& system_, Common::UUID) |
| 205 | : ServiceFramework("IOAuthProcedureForExternalNsa") { | 208 | : ServiceFramework{system_, "IOAuthProcedureForExternalNsa"} { |
| 206 | // clang-format off | 209 | // clang-format off |
| 207 | static const FunctionInfo functions[] = { | 210 | static const FunctionInfo functions[] = { |
| 208 | {0, nullptr, "PrepareAsync"}, | 211 | {0, nullptr, "PrepareAsync"}, |
| @@ -224,8 +227,8 @@ public: | |||
| 224 | class IOAuthProcedureForNintendoAccountLinkage final | 227 | class IOAuthProcedureForNintendoAccountLinkage final |
| 225 | : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> { | 228 | : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> { |
| 226 | public: | 229 | public: |
| 227 | explicit IOAuthProcedureForNintendoAccountLinkage(Common::UUID user_id) | 230 | explicit IOAuthProcedureForNintendoAccountLinkage(Core::System& system_, Common::UUID) |
| 228 | : ServiceFramework("IOAuthProcedureForNintendoAccountLinkage") { | 231 | : ServiceFramework{system_, "IOAuthProcedureForNintendoAccountLinkage"} { |
| 229 | // clang-format off | 232 | // clang-format off |
| 230 | static const FunctionInfo functions[] = { | 233 | static const FunctionInfo functions[] = { |
| 231 | {0, nullptr, "PrepareAsync"}, | 234 | {0, nullptr, "PrepareAsync"}, |
| @@ -245,7 +248,8 @@ public: | |||
| 245 | 248 | ||
| 246 | class INotifier final : public ServiceFramework<INotifier> { | 249 | class INotifier final : public ServiceFramework<INotifier> { |
| 247 | public: | 250 | public: |
| 248 | explicit INotifier(Common::UUID user_id) : ServiceFramework("INotifier") { | 251 | explicit INotifier(Core::System& system_, Common::UUID) |
| 252 | : ServiceFramework{system_, "INotifier"} { | ||
| 249 | // clang-format off | 253 | // clang-format off |
| 250 | static const FunctionInfo functions[] = { | 254 | static const FunctionInfo functions[] = { |
| 251 | {0, nullptr, "GetSystemEvent"}, | 255 | {0, nullptr, "GetSystemEvent"}, |
| @@ -258,9 +262,9 @@ public: | |||
| 258 | 262 | ||
| 259 | class IProfileCommon : public ServiceFramework<IProfileCommon> { | 263 | class IProfileCommon : public ServiceFramework<IProfileCommon> { |
| 260 | public: | 264 | public: |
| 261 | explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id, | 265 | explicit IProfileCommon(Core::System& system_, const char* name, bool editor_commands, |
| 262 | ProfileManager& profile_manager) | 266 | Common::UUID user_id_, ProfileManager& profile_manager_) |
| 263 | : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) { | 267 | : ServiceFramework{system_, name}, profile_manager{profile_manager_}, user_id{user_id_} { |
| 264 | static const FunctionInfo functions[] = { | 268 | static const FunctionInfo functions[] = { |
| 265 | {0, &IProfileCommon::Get, "Get"}, | 269 | {0, &IProfileCommon::Get, "Get"}, |
| 266 | {1, &IProfileCommon::GetBase, "GetBase"}, | 270 | {1, &IProfileCommon::GetBase, "GetBase"}, |
| @@ -426,19 +430,21 @@ protected: | |||
| 426 | 430 | ||
| 427 | class IProfile final : public IProfileCommon { | 431 | class IProfile final : public IProfileCommon { |
| 428 | public: | 432 | public: |
| 429 | IProfile(Common::UUID user_id, ProfileManager& profile_manager) | 433 | explicit IProfile(Core::System& system_, Common::UUID user_id_, |
| 430 | : IProfileCommon("IProfile", false, user_id, profile_manager) {} | 434 | ProfileManager& profile_manager_) |
| 435 | : IProfileCommon{system_, "IProfile", false, user_id_, profile_manager_} {} | ||
| 431 | }; | 436 | }; |
| 432 | 437 | ||
| 433 | class IProfileEditor final : public IProfileCommon { | 438 | class IProfileEditor final : public IProfileCommon { |
| 434 | public: | 439 | public: |
| 435 | IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager) | 440 | explicit IProfileEditor(Core::System& system_, Common::UUID user_id_, |
| 436 | : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {} | 441 | ProfileManager& profile_manager_) |
| 442 | : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {} | ||
| 437 | }; | 443 | }; |
| 438 | 444 | ||
| 439 | class IAsyncContext final : public ServiceFramework<IAsyncContext> { | 445 | class IAsyncContext final : public ServiceFramework<IAsyncContext> { |
| 440 | public: | 446 | public: |
| 441 | explicit IAsyncContext(Common::UUID user_id) : ServiceFramework("IAsyncContext") { | 447 | explicit IAsyncContext(Core::System& system_) : ServiceFramework{system_, "IAsyncContext"} { |
| 442 | // clang-format off | 448 | // clang-format off |
| 443 | static const FunctionInfo functions[] = { | 449 | static const FunctionInfo functions[] = { |
| 444 | {0, nullptr, "GetSystemEvent"}, | 450 | {0, nullptr, "GetSystemEvent"}, |
| @@ -454,7 +460,8 @@ public: | |||
| 454 | 460 | ||
| 455 | class ISessionObject final : public ServiceFramework<ISessionObject> { | 461 | class ISessionObject final : public ServiceFramework<ISessionObject> { |
| 456 | public: | 462 | public: |
| 457 | explicit ISessionObject(Common::UUID user_id) : ServiceFramework("ISessionObject") { | 463 | explicit ISessionObject(Core::System& system_, Common::UUID) |
| 464 | : ServiceFramework{system_, "ISessionObject"} { | ||
| 458 | // clang-format off | 465 | // clang-format off |
| 459 | static const FunctionInfo functions[] = { | 466 | static const FunctionInfo functions[] = { |
| 460 | {999, nullptr, "Dummy"}, | 467 | {999, nullptr, "Dummy"}, |
| @@ -467,7 +474,8 @@ public: | |||
| 467 | 474 | ||
| 468 | class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> { | 475 | class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> { |
| 469 | public: | 476 | public: |
| 470 | explicit IGuestLoginRequest(Common::UUID) : ServiceFramework("IGuestLoginRequest") { | 477 | explicit IGuestLoginRequest(Core::System& system_, Common::UUID) |
| 478 | : ServiceFramework{system_, "IGuestLoginRequest"} { | ||
| 471 | // clang-format off | 479 | // clang-format off |
| 472 | static const FunctionInfo functions[] = { | 480 | static const FunctionInfo functions[] = { |
| 473 | {0, nullptr, "GetSessionId"}, | 481 | {0, nullptr, "GetSessionId"}, |
| @@ -486,8 +494,8 @@ public: | |||
| 486 | 494 | ||
| 487 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { | 495 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { |
| 488 | public: | 496 | public: |
| 489 | explicit IManagerForApplication(Common::UUID user_id) | 497 | explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_) |
| 490 | : ServiceFramework("IManagerForApplication"), user_id(user_id) { | 498 | : ServiceFramework{system_, "IManagerForApplication"}, user_id{user_id_} { |
| 491 | // clang-format off | 499 | // clang-format off |
| 492 | static const FunctionInfo functions[] = { | 500 | static const FunctionInfo functions[] = { |
| 493 | {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, | 501 | {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, |
| @@ -496,7 +504,7 @@ public: | |||
| 496 | {3, nullptr, "LoadIdTokenCache"}, | 504 | {3, nullptr, "LoadIdTokenCache"}, |
| 497 | {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, | 505 | {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, |
| 498 | {150, nullptr, "CreateAuthorizationRequest"}, | 506 | {150, nullptr, "CreateAuthorizationRequest"}, |
| 499 | {160, nullptr, "StoreOpenContext"}, | 507 | {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"}, |
| 500 | {170, nullptr, "LoadNetworkServiceLicenseKindAsync"}, | 508 | {170, nullptr, "LoadNetworkServiceLicenseKindAsync"}, |
| 501 | }; | 509 | }; |
| 502 | // clang-format on | 510 | // clang-format on |
| @@ -520,6 +528,12 @@ private: | |||
| 520 | rb.PushRaw<u64>(user_id.GetNintendoID()); | 528 | rb.PushRaw<u64>(user_id.GetNintendoID()); |
| 521 | } | 529 | } |
| 522 | 530 | ||
| 531 | void StoreOpenContext(Kernel::HLERequestContext& ctx) { | ||
| 532 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 533 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 534 | rb.Push(RESULT_SUCCESS); | ||
| 535 | } | ||
| 536 | |||
| 523 | Common::UUID user_id; | 537 | Common::UUID user_id; |
| 524 | }; | 538 | }; |
| 525 | 539 | ||
| @@ -527,8 +541,8 @@ private: | |||
| 527 | class IAsyncNetworkServiceLicenseKindContext final | 541 | class IAsyncNetworkServiceLicenseKindContext final |
| 528 | : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> { | 542 | : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> { |
| 529 | public: | 543 | public: |
| 530 | explicit IAsyncNetworkServiceLicenseKindContext(Common::UUID user_id) | 544 | explicit IAsyncNetworkServiceLicenseKindContext(Core::System& system_, Common::UUID) |
| 531 | : ServiceFramework("IAsyncNetworkServiceLicenseKindContext") { | 545 | : ServiceFramework{system_, "IAsyncNetworkServiceLicenseKindContext"} { |
| 532 | // clang-format off | 546 | // clang-format off |
| 533 | static const FunctionInfo functions[] = { | 547 | static const FunctionInfo functions[] = { |
| 534 | {0, nullptr, "GetSystemEvent"}, | 548 | {0, nullptr, "GetSystemEvent"}, |
| @@ -547,8 +561,8 @@ public: | |||
| 547 | class IOAuthProcedureForUserRegistration final | 561 | class IOAuthProcedureForUserRegistration final |
| 548 | : public ServiceFramework<IOAuthProcedureForUserRegistration> { | 562 | : public ServiceFramework<IOAuthProcedureForUserRegistration> { |
| 549 | public: | 563 | public: |
| 550 | explicit IOAuthProcedureForUserRegistration(Common::UUID user_id) | 564 | explicit IOAuthProcedureForUserRegistration(Core::System& system_, Common::UUID) |
| 551 | : ServiceFramework("IOAuthProcedureForUserRegistration") { | 565 | : ServiceFramework{system_, "IOAuthProcedureForUserRegistration"} { |
| 552 | // clang-format off | 566 | // clang-format off |
| 553 | static const FunctionInfo functions[] = { | 567 | static const FunctionInfo functions[] = { |
| 554 | {0, nullptr, "PrepareAsync"}, | 568 | {0, nullptr, "PrepareAsync"}, |
| @@ -571,7 +585,7 @@ public: | |||
| 571 | 585 | ||
| 572 | class DAUTH_O final : public ServiceFramework<DAUTH_O> { | 586 | class DAUTH_O final : public ServiceFramework<DAUTH_O> { |
| 573 | public: | 587 | public: |
| 574 | explicit DAUTH_O(Common::UUID) : ServiceFramework("dauth:o") { | 588 | explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} { |
| 575 | // clang-format off | 589 | // clang-format off |
| 576 | static const FunctionInfo functions[] = { | 590 | static const FunctionInfo functions[] = { |
| 577 | {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData | 591 | {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData |
| @@ -590,7 +604,8 @@ public: | |||
| 590 | // 6.0.0+ | 604 | // 6.0.0+ |
| 591 | class IAsyncResult final : public ServiceFramework<IAsyncResult> { | 605 | class IAsyncResult final : public ServiceFramework<IAsyncResult> { |
| 592 | public: | 606 | public: |
| 593 | explicit IAsyncResult(Common::UUID user_id) : ServiceFramework("IAsyncResult") { | 607 | explicit IAsyncResult(Core::System& system_, Common::UUID) |
| 608 | : ServiceFramework{system_, "IAsyncResult"} { | ||
| 594 | // clang-format off | 609 | // clang-format off |
| 595 | static const FunctionInfo functions[] = { | 610 | static const FunctionInfo functions[] = { |
| 596 | {0, nullptr, "GetResult"}, | 611 | {0, nullptr, "GetResult"}, |
| @@ -649,7 +664,7 @@ void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { | |||
| 649 | 664 | ||
| 650 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 665 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 651 | rb.Push(RESULT_SUCCESS); | 666 | rb.Push(RESULT_SUCCESS); |
| 652 | rb.PushIpcInterface<IProfile>(user_id, *profile_manager); | 667 | rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager); |
| 653 | } | 668 | } |
| 654 | 669 | ||
| 655 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { | 670 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { |
| @@ -724,7 +739,7 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo | |||
| 724 | LOG_DEBUG(Service_ACC, "called"); | 739 | LOG_DEBUG(Service_ACC, "called"); |
| 725 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 740 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 726 | rb.Push(RESULT_SUCCESS); | 741 | rb.Push(RESULT_SUCCESS); |
| 727 | rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser()); | 742 | rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); |
| 728 | } | 743 | } |
| 729 | 744 | ||
| 730 | void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) { | 745 | void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) { |
| @@ -735,8 +750,10 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx | |||
| 735 | bool is_locked = false; | 750 | bool is_locked = false; |
| 736 | 751 | ||
| 737 | if (res != Loader::ResultStatus::Success) { | 752 | if (res != Loader::ResultStatus::Success) { |
| 738 | FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; | 753 | const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), |
| 739 | auto nacp_unique = pm.GetControlMetadata().first; | 754 | system.GetFileSystemController(), |
| 755 | system.GetContentProvider()}; | ||
| 756 | const auto nacp_unique = pm.GetControlMetadata().first; | ||
| 740 | 757 | ||
| 741 | if (nacp_unique != nullptr) { | 758 | if (nacp_unique != nullptr) { |
| 742 | is_locked = nacp_unique->GetUserAccountSwitchLock(); | 759 | is_locked = nacp_unique->GetUserAccountSwitchLock(); |
| @@ -760,7 +777,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) { | |||
| 760 | 777 | ||
| 761 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 778 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 762 | rb.Push(RESULT_SUCCESS); | 779 | rb.Push(RESULT_SUCCESS); |
| 763 | rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager); | 780 | rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager); |
| 764 | } | 781 | } |
| 765 | 782 | ||
| 766 | void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { | 783 | void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { |
| @@ -782,7 +799,7 @@ void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) { | |||
| 782 | // TODO: Find the differences between this and GetBaasAccountManagerForApplication | 799 | // TODO: Find the differences between this and GetBaasAccountManagerForApplication |
| 783 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 800 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 784 | rb.Push(RESULT_SUCCESS); | 801 | rb.Push(RESULT_SUCCESS); |
| 785 | rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser()); | 802 | rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); |
| 786 | } | 803 | } |
| 787 | 804 | ||
| 788 | void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { | 805 | void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { |
| @@ -818,11 +835,11 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex | |||
| 818 | rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid); | 835 | rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid); |
| 819 | } | 836 | } |
| 820 | 837 | ||
| 821 | Module::Interface::Interface(std::shared_ptr<Module> module, | 838 | Module::Interface::Interface(std::shared_ptr<Module> module_, |
| 822 | std::shared_ptr<ProfileManager> profile_manager, Core::System& system, | 839 | std::shared_ptr<ProfileManager> profile_manager_, |
| 823 | const char* name) | 840 | Core::System& system_, const char* name) |
| 824 | : ServiceFramework(name), module(std::move(module)), | 841 | : ServiceFramework{system_, name}, module{std::move(module_)}, profile_manager{std::move( |
| 825 | profile_manager(std::move(profile_manager)), system(system) {} | 842 | profile_manager_)} {} |
| 826 | 843 | ||
| 827 | Module::Interface::~Interface() = default; | 844 | Module::Interface::~Interface() = default; |
| 828 | 845 | ||
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index c611efd89..ab8edc049 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -15,8 +15,8 @@ class Module final { | |||
| 15 | public: | 15 | public: |
| 16 | class Interface : public ServiceFramework<Interface> { | 16 | class Interface : public ServiceFramework<Interface> { |
| 17 | public: | 17 | public: |
| 18 | explicit Interface(std::shared_ptr<Module> module, | 18 | explicit Interface(std::shared_ptr<Module> module_, |
| 19 | std::shared_ptr<ProfileManager> profile_manager, Core::System& system, | 19 | std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_, |
| 20 | const char* name); | 20 | const char* name); |
| 21 | ~Interface() override; | 21 | ~Interface() override; |
| 22 | 22 | ||
| @@ -60,7 +60,6 @@ public: | |||
| 60 | protected: | 60 | protected: |
| 61 | std::shared_ptr<Module> module; | 61 | std::shared_ptr<Module> module; |
| 62 | std::shared_ptr<ProfileManager> profile_manager; | 62 | std::shared_ptr<ProfileManager> profile_manager; |
| 63 | Core::System& system; | ||
| 64 | }; | 63 | }; |
| 65 | }; | 64 | }; |
| 66 | 65 | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d7a81f64a..c9808060a 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -64,7 +64,7 @@ struct LaunchParameterAccountPreselectedUser { | |||
| 64 | static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); | 64 | static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |
| 65 | 65 | ||
| 66 | IWindowController::IWindowController(Core::System& system_) | 66 | IWindowController::IWindowController(Core::System& system_) |
| 67 | : ServiceFramework("IWindowController"), system{system_} { | 67 | : ServiceFramework{system_, "IWindowController"} { |
| 68 | // clang-format off | 68 | // clang-format off |
| 69 | static const FunctionInfo functions[] = { | 69 | static const FunctionInfo functions[] = { |
| 70 | {0, nullptr, "CreateWindow"}, | 70 | {0, nullptr, "CreateWindow"}, |
| @@ -99,7 +99,8 @@ void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) | |||
| 99 | rb.Push(RESULT_SUCCESS); | 99 | rb.Push(RESULT_SUCCESS); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | IAudioController::IAudioController() : ServiceFramework("IAudioController") { | 102 | IAudioController::IAudioController(Core::System& system_) |
| 103 | : ServiceFramework{system_, "IAudioController"} { | ||
| 103 | // clang-format off | 104 | // clang-format off |
| 104 | static const FunctionInfo functions[] = { | 105 | static const FunctionInfo functions[] = { |
| 105 | {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, | 106 | {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, |
| @@ -180,7 +181,8 @@ void IAudioController::SetTransparentAudioRate(Kernel::HLERequestContext& ctx) { | |||
| 180 | rb.Push(RESULT_SUCCESS); | 181 | rb.Push(RESULT_SUCCESS); |
| 181 | } | 182 | } |
| 182 | 183 | ||
| 183 | IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") { | 184 | IDisplayController::IDisplayController(Core::System& system_) |
| 185 | : ServiceFramework{system_, "IDisplayController"} { | ||
| 184 | // clang-format off | 186 | // clang-format off |
| 185 | static const FunctionInfo functions[] = { | 187 | static const FunctionInfo functions[] = { |
| 186 | {0, nullptr, "GetLastForegroundCaptureImage"}, | 188 | {0, nullptr, "GetLastForegroundCaptureImage"}, |
| @@ -219,7 +221,8 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" | |||
| 219 | 221 | ||
| 220 | IDisplayController::~IDisplayController() = default; | 222 | IDisplayController::~IDisplayController() = default; |
| 221 | 223 | ||
| 222 | IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { | 224 | IDebugFunctions::IDebugFunctions(Core::System& system_) |
| 225 | : ServiceFramework{system_, "IDebugFunctions"} { | ||
| 223 | // clang-format off | 226 | // clang-format off |
| 224 | static const FunctionInfo functions[] = { | 227 | static const FunctionInfo functions[] = { |
| 225 | {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, | 228 | {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, |
| @@ -246,9 +249,8 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { | |||
| 246 | 249 | ||
| 247 | IDebugFunctions::~IDebugFunctions() = default; | 250 | IDebugFunctions::~IDebugFunctions() = default; |
| 248 | 251 | ||
| 249 | ISelfController::ISelfController(Core::System& system, | 252 | ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_) |
| 250 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger) | 253 | : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_} { |
| 251 | : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) { | ||
| 252 | // clang-format off | 254 | // clang-format off |
| 253 | static const FunctionInfo functions[] = { | 255 | static const FunctionInfo functions[] = { |
| 254 | {0, &ISelfController::Exit, "Exit"}, | 256 | {0, &ISelfController::Exit, "Exit"}, |
| @@ -458,8 +460,8 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) | |||
| 458 | 460 | ||
| 459 | // TODO(Subv): Find out how AM determines the display to use, for now just | 461 | // TODO(Subv): Find out how AM determines the display to use, for now just |
| 460 | // create the layer in the Default display. | 462 | // create the layer in the Default display. |
| 461 | const auto display_id = nvflinger->OpenDisplay("Default"); | 463 | const auto display_id = nvflinger.OpenDisplay("Default"); |
| 462 | const auto layer_id = nvflinger->CreateLayer(*display_id); | 464 | const auto layer_id = nvflinger.CreateLayer(*display_id); |
| 463 | 465 | ||
| 464 | IPC::ResponseBuilder rb{ctx, 4}; | 466 | IPC::ResponseBuilder rb{ctx, 4}; |
| 465 | rb.Push(RESULT_SUCCESS); | 467 | rb.Push(RESULT_SUCCESS); |
| @@ -476,8 +478,8 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte | |||
| 476 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse | 478 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse |
| 477 | // side effects. | 479 | // side effects. |
| 478 | // TODO: Support multiple layers | 480 | // TODO: Support multiple layers |
| 479 | const auto display_id = nvflinger->OpenDisplay("Default"); | 481 | const auto display_id = nvflinger.OpenDisplay("Default"); |
| 480 | const auto layer_id = nvflinger->CreateLayer(*display_id); | 482 | const auto layer_id = nvflinger.CreateLayer(*display_id); |
| 481 | 483 | ||
| 482 | IPC::ResponseBuilder rb{ctx, 4}; | 484 | IPC::ResponseBuilder rb{ctx, 4}; |
| 483 | rb.Push(RESULT_SUCCESS); | 485 | rb.Push(RESULT_SUCCESS); |
| @@ -558,14 +560,14 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest | |||
| 558 | 560 | ||
| 559 | AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { | 561 | AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { |
| 560 | on_new_message = | 562 | on_new_message = |
| 561 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageRecieved"); | 563 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageReceived"); |
| 562 | on_operation_mode_changed = | 564 | on_operation_mode_changed = |
| 563 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged"); | 565 | Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged"); |
| 564 | } | 566 | } |
| 565 | 567 | ||
| 566 | AppletMessageQueue::~AppletMessageQueue() = default; | 568 | AppletMessageQueue::~AppletMessageQueue() = default; |
| 567 | 569 | ||
| 568 | const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() const { | 570 | const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { |
| 569 | return on_new_message.readable; | 571 | return on_new_message.readable; |
| 570 | } | 572 | } |
| 571 | 573 | ||
| @@ -606,9 +608,9 @@ void AppletMessageQueue::RequestExit() { | |||
| 606 | PushMessage(AppletMessage::ExitRequested); | 608 | PushMessage(AppletMessage::ExitRequested); |
| 607 | } | 609 | } |
| 608 | 610 | ||
| 609 | ICommonStateGetter::ICommonStateGetter(Core::System& system, | 611 | ICommonStateGetter::ICommonStateGetter(Core::System& system_, |
| 610 | std::shared_ptr<AppletMessageQueue> msg_queue) | 612 | std::shared_ptr<AppletMessageQueue> msg_queue_) |
| 611 | : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { | 613 | : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} { |
| 612 | // clang-format off | 614 | // clang-format off |
| 613 | static const FunctionInfo functions[] = { | 615 | static const FunctionInfo functions[] = { |
| 614 | {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, | 616 | {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, |
| @@ -673,7 +675,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { | |||
| 673 | 675 | ||
| 674 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 676 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 675 | rb.Push(RESULT_SUCCESS); | 677 | rb.Push(RESULT_SUCCESS); |
| 676 | rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); | 678 | rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); |
| 677 | } | 679 | } |
| 678 | 680 | ||
| 679 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { | 681 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { |
| @@ -751,7 +753,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& | |||
| 751 | IPC::ResponseBuilder rb{ctx, 4}; | 753 | IPC::ResponseBuilder rb{ctx, 4}; |
| 752 | rb.Push(RESULT_SUCCESS); | 754 | rb.Push(RESULT_SUCCESS); |
| 753 | 755 | ||
| 754 | if (Settings::values.use_docked_mode) { | 756 | if (Settings::values.use_docked_mode.GetValue()) { |
| 755 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * | 757 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 756 | static_cast<u32>(Settings::values.resolution_factor.GetValue())); | 758 | static_cast<u32>(Settings::values.resolution_factor.GetValue())); |
| 757 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | 759 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * |
| @@ -796,8 +798,9 @@ private: | |||
| 796 | std::vector<u8> buffer; | 798 | std::vector<u8> buffer; |
| 797 | }; | 799 | }; |
| 798 | 800 | ||
| 799 | IStorage::IStorage(std::vector<u8>&& buffer) | 801 | IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer) |
| 800 | : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { | 802 | : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>( |
| 803 | std::move(buffer))} { | ||
| 801 | Register(); | 804 | Register(); |
| 802 | } | 805 | } |
| 803 | 806 | ||
| @@ -820,11 +823,11 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) { | |||
| 820 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 823 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 821 | 824 | ||
| 822 | rb.Push(RESULT_SUCCESS); | 825 | rb.Push(RESULT_SUCCESS); |
| 823 | rb.PushIpcInterface<IStorageAccessor>(*this); | 826 | rb.PushIpcInterface<IStorageAccessor>(system, *this); |
| 824 | } | 827 | } |
| 825 | 828 | ||
| 826 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | 829 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { |
| 827 | const bool use_docked_mode{Settings::values.use_docked_mode}; | 830 | const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()}; |
| 828 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); | 831 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); |
| 829 | 832 | ||
| 830 | IPC::ResponseBuilder rb{ctx, 3}; | 833 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -842,8 +845,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | |||
| 842 | 845 | ||
| 843 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 846 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
| 844 | public: | 847 | public: |
| 845 | explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) | 848 | explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> applet_) |
| 846 | : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { | 849 | : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { |
| 847 | // clang-format off | 850 | // clang-format off |
| 848 | static const FunctionInfo functions[] = { | 851 | static const FunctionInfo functions[] = { |
| 849 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | 852 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
| @@ -998,8 +1001,8 @@ private: | |||
| 998 | std::shared_ptr<Applets::Applet> applet; | 1001 | std::shared_ptr<Applets::Applet> applet; |
| 999 | }; | 1002 | }; |
| 1000 | 1003 | ||
| 1001 | IStorageAccessor::IStorageAccessor(IStorage& storage) | 1004 | IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) |
| 1002 | : ServiceFramework("IStorageAccessor"), backing(storage) { | 1005 | : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { |
| 1003 | // clang-format off | 1006 | // clang-format off |
| 1004 | static const FunctionInfo functions[] = { | 1007 | static const FunctionInfo functions[] = { |
| 1005 | {0, &IStorageAccessor::GetSize, "GetSize"}, | 1008 | {0, &IStorageAccessor::GetSize, "GetSize"}, |
| @@ -1070,7 +1073,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | |||
| 1070 | } | 1073 | } |
| 1071 | 1074 | ||
| 1072 | ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) | 1075 | ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) |
| 1073 | : ServiceFramework("ILibraryAppletCreator"), system{system_} { | 1076 | : ServiceFramework{system_, "ILibraryAppletCreator"} { |
| 1074 | static const FunctionInfo functions[] = { | 1077 | static const FunctionInfo functions[] = { |
| 1075 | {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, | 1078 | {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, |
| 1076 | {1, nullptr, "TerminateAllLibraryApplets"}, | 1079 | {1, nullptr, "TerminateAllLibraryApplets"}, |
| @@ -1089,14 +1092,14 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 1089 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); | 1092 | const auto applet_id = rp.PopRaw<Applets::AppletId>(); |
| 1090 | const auto applet_mode = rp.PopRaw<u32>(); | 1093 | const auto applet_mode = rp.PopRaw<u32>(); |
| 1091 | 1094 | ||
| 1092 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", | 1095 | LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, |
| 1093 | static_cast<u32>(applet_id), applet_mode); | 1096 | applet_mode); |
| 1094 | 1097 | ||
| 1095 | const auto& applet_manager{system.GetAppletManager()}; | 1098 | const auto& applet_manager{system.GetAppletManager()}; |
| 1096 | const auto applet = applet_manager.GetApplet(applet_id); | 1099 | const auto applet = applet_manager.GetApplet(applet_id); |
| 1097 | 1100 | ||
| 1098 | if (applet == nullptr) { | 1101 | if (applet == nullptr) { |
| 1099 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); | 1102 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |
| 1100 | 1103 | ||
| 1101 | IPC::ResponseBuilder rb{ctx, 2}; | 1104 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1102 | rb.Push(RESULT_UNKNOWN); | 1105 | rb.Push(RESULT_UNKNOWN); |
| @@ -1106,7 +1109,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 1106 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1109 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1107 | 1110 | ||
| 1108 | rb.Push(RESULT_SUCCESS); | 1111 | rb.Push(RESULT_SUCCESS); |
| 1109 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet); | 1112 | rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); |
| 1110 | } | 1113 | } |
| 1111 | 1114 | ||
| 1112 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 1115 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| @@ -1118,7 +1121,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | |||
| 1118 | 1121 | ||
| 1119 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1120 | rb.Push(RESULT_SUCCESS); | 1123 | rb.Push(RESULT_SUCCESS); |
| 1121 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); | 1124 | rb.PushIpcInterface<IStorage>(system, std::move(buffer)); |
| 1122 | } | 1125 | } |
| 1123 | 1126 | ||
| 1124 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { | 1127 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { |
| @@ -1145,11 +1148,11 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | |||
| 1145 | 1148 | ||
| 1146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1149 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1147 | rb.Push(RESULT_SUCCESS); | 1150 | rb.Push(RESULT_SUCCESS); |
| 1148 | rb.PushIpcInterface<IStorage>(std::move(memory)); | 1151 | rb.PushIpcInterface<IStorage>(system, std::move(memory)); |
| 1149 | } | 1152 | } |
| 1150 | 1153 | ||
| 1151 | IApplicationFunctions::IApplicationFunctions(Core::System& system_) | 1154 | IApplicationFunctions::IApplicationFunctions(Core::System& system_) |
| 1152 | : ServiceFramework("IApplicationFunctions"), system{system_} { | 1155 | : ServiceFramework{system_, "IApplicationFunctions"} { |
| 1153 | // clang-format off | 1156 | // clang-format off |
| 1154 | static const FunctionInfo functions[] = { | 1157 | static const FunctionInfo functions[] = { |
| 1155 | {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, | 1158 | {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, |
| @@ -1189,9 +1192,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1189 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, | 1192 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, |
| 1190 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, | 1193 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, |
| 1191 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, | 1194 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, |
| 1192 | {120, nullptr, "ExecuteProgram"}, | 1195 | {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, |
| 1193 | {121, nullptr, "ClearUserChannel"}, | 1196 | {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, |
| 1194 | {122, nullptr, "UnpopToUserChannel"}, | 1197 | {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, |
| 1195 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, | 1198 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, |
| 1196 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | 1199 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, |
| 1197 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, | 1200 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, |
| @@ -1201,6 +1204,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1201 | {151, nullptr, "TryPopFromNotificationStorageChannel"}, | 1204 | {151, nullptr, "TryPopFromNotificationStorageChannel"}, |
| 1202 | {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, | 1205 | {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, |
| 1203 | {170, nullptr, "SetHdcpAuthenticationActivated"}, | 1206 | {170, nullptr, "SetHdcpAuthenticationActivated"}, |
| 1207 | {180, nullptr, "GetLaunchRequiredVersion"}, | ||
| 1208 | {181, nullptr, "UpgradeLaunchRequiredVersion"}, | ||
| 1204 | {500, nullptr, "StartContinuousRecordingFlushForDebug"}, | 1209 | {500, nullptr, "StartContinuousRecordingFlushForDebug"}, |
| 1205 | {1000, nullptr, "CreateMovieMaker"}, | 1210 | {1000, nullptr, "CreateMovieMaker"}, |
| 1206 | {1001, nullptr, "PrepareForJit"}, | 1211 | {1001, nullptr, "PrepareForJit"}, |
| @@ -1285,7 +1290,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 1285 | IPC::RequestParser rp{ctx}; | 1290 | IPC::RequestParser rp{ctx}; |
| 1286 | const auto kind = rp.PopEnum<LaunchParameterKind>(); | 1291 | const auto kind = rp.PopEnum<LaunchParameterKind>(); |
| 1287 | 1292 | ||
| 1288 | LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); | 1293 | LOG_DEBUG(Service_AM, "called, kind={:08X}", kind); |
| 1289 | 1294 | ||
| 1290 | if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { | 1295 | if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { |
| 1291 | const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) { | 1296 | const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) { |
| @@ -1299,7 +1304,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 1299 | if (data.has_value()) { | 1304 | if (data.has_value()) { |
| 1300 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1305 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1301 | rb.Push(RESULT_SUCCESS); | 1306 | rb.Push(RESULT_SUCCESS); |
| 1302 | rb.PushIpcInterface<IStorage>(std::move(*data)); | 1307 | rb.PushIpcInterface<IStorage>(system, std::move(*data)); |
| 1303 | launch_popped_application_specific = true; | 1308 | launch_popped_application_specific = true; |
| 1304 | return; | 1309 | return; |
| 1305 | } | 1310 | } |
| @@ -1322,7 +1327,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 1322 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | 1327 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |
| 1323 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 1328 | std::memcpy(buffer.data(), ¶ms, buffer.size()); |
| 1324 | 1329 | ||
| 1325 | rb.PushIpcInterface<IStorage>(std::move(buffer)); | 1330 | rb.PushIpcInterface<IStorage>(system, std::move(buffer)); |
| 1326 | launch_popped_account_preselect = true; | 1331 | launch_popped_account_preselect = true; |
| 1327 | return; | 1332 | return; |
| 1328 | } | 1333 | } |
| @@ -1379,13 +1384,16 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | |||
| 1379 | const auto res = [this] { | 1384 | const auto res = [this] { |
| 1380 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 1385 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 1381 | 1386 | ||
| 1382 | FileSys::PatchManager pm{title_id}; | 1387 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 1388 | system.GetContentProvider()}; | ||
| 1383 | auto res = pm.GetControlMetadata(); | 1389 | auto res = pm.GetControlMetadata(); |
| 1384 | if (res.first != nullptr) { | 1390 | if (res.first != nullptr) { |
| 1385 | return res; | 1391 | return res; |
| 1386 | } | 1392 | } |
| 1387 | 1393 | ||
| 1388 | FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; | 1394 | const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
| 1395 | system.GetFileSystemController(), | ||
| 1396 | system.GetContentProvider()}; | ||
| 1389 | return pm_update.GetControlMetadata(); | 1397 | return pm_update.GetControlMetadata(); |
| 1390 | }(); | 1398 | }(); |
| 1391 | 1399 | ||
| @@ -1413,13 +1421,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | |||
| 1413 | const auto res = [this] { | 1421 | const auto res = [this] { |
| 1414 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 1422 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 1415 | 1423 | ||
| 1416 | FileSys::PatchManager pm{title_id}; | 1424 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 1425 | system.GetContentProvider()}; | ||
| 1417 | auto res = pm.GetControlMetadata(); | 1426 | auto res = pm.GetControlMetadata(); |
| 1418 | if (res.first != nullptr) { | 1427 | if (res.first != nullptr) { |
| 1419 | return res; | 1428 | return res; |
| 1420 | } | 1429 | } |
| 1421 | 1430 | ||
| 1422 | FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; | 1431 | const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
| 1432 | system.GetFileSystemController(), | ||
| 1433 | system.GetContentProvider()}; | ||
| 1423 | return pm_update.GetControlMetadata(); | 1434 | return pm_update.GetControlMetadata(); |
| 1424 | }(); | 1435 | }(); |
| 1425 | 1436 | ||
| @@ -1526,8 +1537,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { | |||
| 1526 | IPC::RequestParser rp{ctx}; | 1537 | IPC::RequestParser rp{ctx}; |
| 1527 | const auto [type, user_id] = rp.PopRaw<Parameters>(); | 1538 | const auto [type, user_id] = rp.PopRaw<Parameters>(); |
| 1528 | 1539 | ||
| 1529 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), | 1540 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], |
| 1530 | user_id[1], user_id[0]); | 1541 | user_id[0]); |
| 1531 | 1542 | ||
| 1532 | const auto size = system.GetFileSystemController().ReadSaveDataSize( | 1543 | const auto size = system.GetFileSystemController().ReadSaveDataSize( |
| 1533 | type, system.CurrentProcess()->GetTitleID(), user_id); | 1544 | type, system.CurrentProcess()->GetTitleID(), user_id); |
| @@ -1554,6 +1565,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque | |||
| 1554 | rb.Push<u32>(0); | 1565 | rb.Push<u32>(0); |
| 1555 | } | 1566 | } |
| 1556 | 1567 | ||
| 1568 | void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) { | ||
| 1569 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1570 | |||
| 1571 | IPC::RequestParser rp{ctx}; | ||
| 1572 | [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); | ||
| 1573 | [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); | ||
| 1574 | const auto program_index = rp.Pop<u64>(); | ||
| 1575 | |||
| 1576 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1577 | rb.Push(RESULT_SUCCESS); | ||
| 1578 | |||
| 1579 | system.ExecuteProgram(program_index); | ||
| 1580 | } | ||
| 1581 | |||
| 1582 | void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1583 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1584 | |||
| 1585 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1586 | rb.Push(RESULT_SUCCESS); | ||
| 1587 | } | ||
| 1588 | |||
| 1589 | void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1590 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1591 | |||
| 1592 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1593 | rb.Push(RESULT_SUCCESS); | ||
| 1594 | } | ||
| 1595 | |||
| 1557 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { | 1596 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { |
| 1558 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1597 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 1559 | 1598 | ||
| @@ -1578,22 +1617,22 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe | |||
| 1578 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); | 1617 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); |
| 1579 | } | 1618 | } |
| 1580 | 1619 | ||
| 1581 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1620 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 1582 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { | 1621 | Core::System& system) { |
| 1583 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); | 1622 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); |
| 1584 | // Needed on game boot | 1623 | // Needed on game boot |
| 1585 | message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); | 1624 | message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |
| 1586 | 1625 | ||
| 1587 | std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); | 1626 | std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); |
| 1588 | std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager); | 1627 | std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager); |
| 1589 | std::make_shared<IdleSys>()->InstallAsService(service_manager); | 1628 | std::make_shared<IdleSys>(system)->InstallAsService(service_manager); |
| 1590 | std::make_shared<OMM>()->InstallAsService(service_manager); | 1629 | std::make_shared<OMM>(system)->InstallAsService(service_manager); |
| 1591 | std::make_shared<SPSM>()->InstallAsService(service_manager); | 1630 | std::make_shared<SPSM>(system)->InstallAsService(service_manager); |
| 1592 | std::make_shared<TCAP>()->InstallAsService(service_manager); | 1631 | std::make_shared<TCAP>(system)->InstallAsService(service_manager); |
| 1593 | } | 1632 | } |
| 1594 | 1633 | ||
| 1595 | IHomeMenuFunctions::IHomeMenuFunctions(Kernel::KernelCore& kernel) | 1634 | IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) |
| 1596 | : ServiceFramework("IHomeMenuFunctions"), kernel(kernel) { | 1635 | : ServiceFramework{system_, "IHomeMenuFunctions"} { |
| 1597 | // clang-format off | 1636 | // clang-format off |
| 1598 | static const FunctionInfo functions[] = { | 1637 | static const FunctionInfo functions[] = { |
| 1599 | {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, | 1638 | {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, |
| @@ -1612,7 +1651,7 @@ IHomeMenuFunctions::IHomeMenuFunctions(Kernel::KernelCore& kernel) | |||
| 1612 | RegisterHandlers(functions); | 1651 | RegisterHandlers(functions); |
| 1613 | 1652 | ||
| 1614 | pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair( | 1653 | pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair( |
| 1615 | kernel, "IHomeMenuFunctions:PopFromGeneralChannelEvent"); | 1654 | system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent"); |
| 1616 | } | 1655 | } |
| 1617 | 1656 | ||
| 1618 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; | 1657 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; |
| @@ -1632,7 +1671,8 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext | |||
| 1632 | rb.PushCopyObjects(pop_from_general_channel_event.readable); | 1671 | rb.PushCopyObjects(pop_from_general_channel_event.readable); |
| 1633 | } | 1672 | } |
| 1634 | 1673 | ||
| 1635 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { | 1674 | IGlobalStateController::IGlobalStateController(Core::System& system_) |
| 1675 | : ServiceFramework{system_, "IGlobalStateController"} { | ||
| 1636 | // clang-format off | 1676 | // clang-format off |
| 1637 | static const FunctionInfo functions[] = { | 1677 | static const FunctionInfo functions[] = { |
| 1638 | {0, nullptr, "RequestToEnterSleep"}, | 1678 | {0, nullptr, "RequestToEnterSleep"}, |
| @@ -1655,7 +1695,8 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat | |||
| 1655 | 1695 | ||
| 1656 | IGlobalStateController::~IGlobalStateController() = default; | 1696 | IGlobalStateController::~IGlobalStateController() = default; |
| 1657 | 1697 | ||
| 1658 | IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { | 1698 | IApplicationCreator::IApplicationCreator(Core::System& system_) |
| 1699 | : ServiceFramework{system_, "IApplicationCreator"} { | ||
| 1659 | // clang-format off | 1700 | // clang-format off |
| 1660 | static const FunctionInfo functions[] = { | 1701 | static const FunctionInfo functions[] = { |
| 1661 | {0, nullptr, "CreateApplication"}, | 1702 | {0, nullptr, "CreateApplication"}, |
| @@ -1670,8 +1711,8 @@ IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreat | |||
| 1670 | 1711 | ||
| 1671 | IApplicationCreator::~IApplicationCreator() = default; | 1712 | IApplicationCreator::~IApplicationCreator() = default; |
| 1672 | 1713 | ||
| 1673 | IProcessWindingController::IProcessWindingController() | 1714 | IProcessWindingController::IProcessWindingController(Core::System& system_) |
| 1674 | : ServiceFramework("IProcessWindingController") { | 1715 | : ServiceFramework{system_, "IProcessWindingController"} { |
| 1675 | // clang-format off | 1716 | // clang-format off |
| 1676 | static const FunctionInfo functions[] = { | 1717 | static const FunctionInfo functions[] = { |
| 1677 | {0, nullptr, "GetLaunchReason"}, | 1718 | {0, nullptr, "GetLaunchReason"}, |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index bcc06affe..f51aca1af 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -55,7 +55,7 @@ public: | |||
| 55 | explicit AppletMessageQueue(Kernel::KernelCore& kernel); | 55 | explicit AppletMessageQueue(Kernel::KernelCore& kernel); |
| 56 | ~AppletMessageQueue(); | 56 | ~AppletMessageQueue(); |
| 57 | 57 | ||
| 58 | const std::shared_ptr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; | 58 | const std::shared_ptr<Kernel::ReadableEvent>& GetMessageReceiveEvent() const; |
| 59 | const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; | 59 | const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; |
| 60 | void PushMessage(AppletMessage msg); | 60 | void PushMessage(AppletMessage msg); |
| 61 | AppletMessage PopMessage(); | 61 | AppletMessage PopMessage(); |
| @@ -77,13 +77,11 @@ public: | |||
| 77 | private: | 77 | private: |
| 78 | void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); | 78 | void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); |
| 79 | void AcquireForegroundRights(Kernel::HLERequestContext& ctx); | 79 | void AcquireForegroundRights(Kernel::HLERequestContext& ctx); |
| 80 | |||
| 81 | Core::System& system; | ||
| 82 | }; | 80 | }; |
| 83 | 81 | ||
| 84 | class IAudioController final : public ServiceFramework<IAudioController> { | 82 | class IAudioController final : public ServiceFramework<IAudioController> { |
| 85 | public: | 83 | public: |
| 86 | IAudioController(); | 84 | explicit IAudioController(Core::System& system_); |
| 87 | ~IAudioController() override; | 85 | ~IAudioController() override; |
| 88 | 86 | ||
| 89 | private: | 87 | private: |
| @@ -109,20 +107,19 @@ private: | |||
| 109 | 107 | ||
| 110 | class IDisplayController final : public ServiceFramework<IDisplayController> { | 108 | class IDisplayController final : public ServiceFramework<IDisplayController> { |
| 111 | public: | 109 | public: |
| 112 | IDisplayController(); | 110 | explicit IDisplayController(Core::System& system_); |
| 113 | ~IDisplayController() override; | 111 | ~IDisplayController() override; |
| 114 | }; | 112 | }; |
| 115 | 113 | ||
| 116 | class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { | 114 | class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { |
| 117 | public: | 115 | public: |
| 118 | IDebugFunctions(); | 116 | explicit IDebugFunctions(Core::System& system_); |
| 119 | ~IDebugFunctions() override; | 117 | ~IDebugFunctions() override; |
| 120 | }; | 118 | }; |
| 121 | 119 | ||
| 122 | class ISelfController final : public ServiceFramework<ISelfController> { | 120 | class ISelfController final : public ServiceFramework<ISelfController> { |
| 123 | public: | 121 | public: |
| 124 | explicit ISelfController(Core::System& system_, | 122 | explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_); |
| 125 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger_); | ||
| 126 | ~ISelfController() override; | 123 | ~ISelfController() override; |
| 127 | 124 | ||
| 128 | private: | 125 | private: |
| @@ -155,8 +152,7 @@ private: | |||
| 155 | Disable = 2, | 152 | Disable = 2, |
| 156 | }; | 153 | }; |
| 157 | 154 | ||
| 158 | Core::System& system; | 155 | NVFlinger::NVFlinger& nvflinger; |
| 159 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | ||
| 160 | Kernel::EventPair launchable_event; | 156 | Kernel::EventPair launchable_event; |
| 161 | Kernel::EventPair accumulated_suspended_tick_changed_event; | 157 | Kernel::EventPair accumulated_suspended_tick_changed_event; |
| 162 | 158 | ||
| @@ -168,8 +164,8 @@ private: | |||
| 168 | 164 | ||
| 169 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | 165 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
| 170 | public: | 166 | public: |
| 171 | explicit ICommonStateGetter(Core::System& system, | 167 | explicit ICommonStateGetter(Core::System& system_, |
| 172 | std::shared_ptr<AppletMessageQueue> msg_queue); | 168 | std::shared_ptr<AppletMessageQueue> msg_queue_); |
| 173 | ~ICommonStateGetter() override; | 169 | ~ICommonStateGetter() override; |
| 174 | 170 | ||
| 175 | private: | 171 | private: |
| @@ -197,7 +193,6 @@ private: | |||
| 197 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); | 193 | void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); |
| 198 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); | 194 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); |
| 199 | 195 | ||
| 200 | Core::System& system; | ||
| 201 | std::shared_ptr<AppletMessageQueue> msg_queue; | 196 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 202 | bool vr_mode_state{}; | 197 | bool vr_mode_state{}; |
| 203 | }; | 198 | }; |
| @@ -212,7 +207,7 @@ public: | |||
| 212 | 207 | ||
| 213 | class IStorage final : public ServiceFramework<IStorage> { | 208 | class IStorage final : public ServiceFramework<IStorage> { |
| 214 | public: | 209 | public: |
| 215 | explicit IStorage(std::vector<u8>&& buffer); | 210 | explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); |
| 216 | ~IStorage() override; | 211 | ~IStorage() override; |
| 217 | 212 | ||
| 218 | std::vector<u8>& GetData() { | 213 | std::vector<u8>& GetData() { |
| @@ -236,7 +231,7 @@ private: | |||
| 236 | 231 | ||
| 237 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | 232 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { |
| 238 | public: | 233 | public: |
| 239 | explicit IStorageAccessor(IStorage& backing); | 234 | explicit IStorageAccessor(Core::System& system_, IStorage& backing_); |
| 240 | ~IStorageAccessor() override; | 235 | ~IStorageAccessor() override; |
| 241 | 236 | ||
| 242 | private: | 237 | private: |
| @@ -256,8 +251,6 @@ private: | |||
| 256 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); | 251 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); |
| 257 | void CreateStorage(Kernel::HLERequestContext& ctx); | 252 | void CreateStorage(Kernel::HLERequestContext& ctx); |
| 258 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); | 253 | void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); |
| 259 | |||
| 260 | Core::System& system; | ||
| 261 | }; | 254 | }; |
| 262 | 255 | ||
| 263 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | 256 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { |
| @@ -288,6 +281,9 @@ private: | |||
| 288 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); | 281 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); |
| 289 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); | 282 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); |
| 290 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); | 283 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); |
| 284 | void ExecuteProgram(Kernel::HLERequestContext& ctx); | ||
| 285 | void ClearUserChannel(Kernel::HLERequestContext& ctx); | ||
| 286 | void UnpopToUserChannel(Kernel::HLERequestContext& ctx); | ||
| 291 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); | 287 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); |
| 292 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 288 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 293 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); | 289 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); |
| @@ -297,12 +293,11 @@ private: | |||
| 297 | s32 previous_program_index{-1}; | 293 | s32 previous_program_index{-1}; |
| 298 | Kernel::EventPair gpu_error_detected_event; | 294 | Kernel::EventPair gpu_error_detected_event; |
| 299 | Kernel::EventPair friend_invitation_storage_channel_event; | 295 | Kernel::EventPair friend_invitation_storage_channel_event; |
| 300 | Core::System& system; | ||
| 301 | }; | 296 | }; |
| 302 | 297 | ||
| 303 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { | 298 | class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { |
| 304 | public: | 299 | public: |
| 305 | explicit IHomeMenuFunctions(Kernel::KernelCore& kernel); | 300 | explicit IHomeMenuFunctions(Core::System& system_); |
| 306 | ~IHomeMenuFunctions() override; | 301 | ~IHomeMenuFunctions() override; |
| 307 | 302 | ||
| 308 | private: | 303 | private: |
| @@ -310,29 +305,28 @@ private: | |||
| 310 | void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); | 305 | void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); |
| 311 | 306 | ||
| 312 | Kernel::EventPair pop_from_general_channel_event; | 307 | Kernel::EventPair pop_from_general_channel_event; |
| 313 | Kernel::KernelCore& kernel; | ||
| 314 | }; | 308 | }; |
| 315 | 309 | ||
| 316 | class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { | 310 | class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { |
| 317 | public: | 311 | public: |
| 318 | IGlobalStateController(); | 312 | explicit IGlobalStateController(Core::System& system_); |
| 319 | ~IGlobalStateController() override; | 313 | ~IGlobalStateController() override; |
| 320 | }; | 314 | }; |
| 321 | 315 | ||
| 322 | class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { | 316 | class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { |
| 323 | public: | 317 | public: |
| 324 | IApplicationCreator(); | 318 | explicit IApplicationCreator(Core::System& system_); |
| 325 | ~IApplicationCreator() override; | 319 | ~IApplicationCreator() override; |
| 326 | }; | 320 | }; |
| 327 | 321 | ||
| 328 | class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { | 322 | class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { |
| 329 | public: | 323 | public: |
| 330 | IProcessWindingController(); | 324 | explicit IProcessWindingController(Core::System& system_); |
| 331 | ~IProcessWindingController() override; | 325 | ~IProcessWindingController() override; |
| 332 | }; | 326 | }; |
| 333 | 327 | ||
| 334 | /// Registers all AM services with the specified service manager. | 328 | /// Registers all AM services with the specified service manager. |
| 335 | void InstallInterfaces(SM::ServiceManager& service_manager, | 329 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 336 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); | 330 | Core::System& system); |
| 337 | 331 | ||
| 338 | } // namespace Service::AM | 332 | } // namespace Service::AM |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 9df286d17..5421e0da0 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/process.h" | ||
| 8 | #include "core/hle/service/am/am.h" | 8 | #include "core/hle/service/am/am.h" |
| 9 | #include "core/hle/service/am/applet_ae.h" | 9 | #include "core/hle/service/am/applet_ae.h" |
| 10 | #include "core/hle/service/nvflinger/nvflinger.h" | 10 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -13,11 +13,11 @@ namespace Service::AM { | |||
| 13 | 13 | ||
| 14 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { | 14 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { |
| 15 | public: | 15 | public: |
| 16 | explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 16 | explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger_, |
| 17 | std::shared_ptr<AppletMessageQueue> msg_queue, | 17 | std::shared_ptr<AppletMessageQueue> msg_queue_, |
| 18 | Core::System& system) | 18 | Core::System& system_) |
| 19 | : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), | 19 | : ServiceFramework{system_, "ILibraryAppletProxy"}, nvflinger{nvflinger_}, |
| 20 | msg_queue(std::move(msg_queue)), system(system) { | 20 | msg_queue{std::move(msg_queue_)} { |
| 21 | // clang-format off | 21 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 23 | {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | 23 | {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
| @@ -66,7 +66,7 @@ private: | |||
| 66 | 66 | ||
| 67 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 67 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 68 | rb.Push(RESULT_SUCCESS); | 68 | rb.Push(RESULT_SUCCESS); |
| 69 | rb.PushIpcInterface<IAudioController>(); | 69 | rb.PushIpcInterface<IAudioController>(system); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 72 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| @@ -74,7 +74,7 @@ private: | |||
| 74 | 74 | ||
| 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 76 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 77 | rb.PushIpcInterface<IDisplayController>(); | 77 | rb.PushIpcInterface<IDisplayController>(system); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { | 80 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { |
| @@ -82,7 +82,7 @@ private: | |||
| 82 | 82 | ||
| 83 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 83 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 84 | rb.Push(RESULT_SUCCESS); | 84 | rb.Push(RESULT_SUCCESS); |
| 85 | rb.PushIpcInterface<IProcessWindingController>(); | 85 | rb.PushIpcInterface<IProcessWindingController>(system); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 88 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| @@ -90,7 +90,7 @@ private: | |||
| 90 | 90 | ||
| 91 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 91 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 92 | rb.Push(RESULT_SUCCESS); | 92 | rb.Push(RESULT_SUCCESS); |
| 93 | rb.PushIpcInterface<IDebugFunctions>(); | 93 | rb.PushIpcInterface<IDebugFunctions>(system); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 96 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| @@ -109,17 +109,17 @@ private: | |||
| 109 | rb.PushIpcInterface<IApplicationFunctions>(system); | 109 | rb.PushIpcInterface<IApplicationFunctions>(system); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 112 | NVFlinger::NVFlinger& nvflinger; |
| 113 | std::shared_ptr<AppletMessageQueue> msg_queue; | 113 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 114 | Core::System& system; | ||
| 115 | }; | 114 | }; |
| 116 | 115 | ||
| 117 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { | 116 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { |
| 118 | public: | 117 | public: |
| 119 | explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 118 | explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger_, |
| 120 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 119 | std::shared_ptr<AppletMessageQueue> msg_queue_, |
| 121 | : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), | 120 | Core::System& system_) |
| 122 | msg_queue(std::move(msg_queue)), system(system) { | 121 | : ServiceFramework{system_, "ISystemAppletProxy"}, nvflinger{nvflinger_}, |
| 122 | msg_queue{std::move(msg_queue_)} { | ||
| 123 | // clang-format off | 123 | // clang-format off |
| 124 | static const FunctionInfo functions[] = { | 124 | static const FunctionInfo functions[] = { |
| 125 | {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | 125 | {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
| @@ -170,7 +170,7 @@ private: | |||
| 170 | 170 | ||
| 171 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 171 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 172 | rb.Push(RESULT_SUCCESS); | 172 | rb.Push(RESULT_SUCCESS); |
| 173 | rb.PushIpcInterface<IAudioController>(); | 173 | rb.PushIpcInterface<IAudioController>(system); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 176 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| @@ -178,7 +178,7 @@ private: | |||
| 178 | 178 | ||
| 179 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 179 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 180 | rb.Push(RESULT_SUCCESS); | 180 | rb.Push(RESULT_SUCCESS); |
| 181 | rb.PushIpcInterface<IDisplayController>(); | 181 | rb.PushIpcInterface<IDisplayController>(system); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 184 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| @@ -186,7 +186,7 @@ private: | |||
| 186 | 186 | ||
| 187 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 187 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 188 | rb.Push(RESULT_SUCCESS); | 188 | rb.Push(RESULT_SUCCESS); |
| 189 | rb.PushIpcInterface<IDebugFunctions>(); | 189 | rb.PushIpcInterface<IDebugFunctions>(system); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 192 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| @@ -202,7 +202,7 @@ private: | |||
| 202 | 202 | ||
| 203 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 203 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 204 | rb.Push(RESULT_SUCCESS); | 204 | rb.Push(RESULT_SUCCESS); |
| 205 | rb.PushIpcInterface<IHomeMenuFunctions>(system.Kernel()); | 205 | rb.PushIpcInterface<IHomeMenuFunctions>(system); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { | 208 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { |
| @@ -210,7 +210,7 @@ private: | |||
| 210 | 210 | ||
| 211 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 211 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 212 | rb.Push(RESULT_SUCCESS); | 212 | rb.Push(RESULT_SUCCESS); |
| 213 | rb.PushIpcInterface<IGlobalStateController>(); | 213 | rb.PushIpcInterface<IGlobalStateController>(system); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { | 216 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { |
| @@ -218,11 +218,11 @@ private: | |||
| 218 | 218 | ||
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<IApplicationCreator>(); | 221 | rb.PushIpcInterface<IApplicationCreator>(system); |
| 222 | } | 222 | } |
| 223 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 223 | |
| 224 | NVFlinger::NVFlinger& nvflinger; | ||
| 224 | std::shared_ptr<AppletMessageQueue> msg_queue; | 225 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 225 | Core::System& system; | ||
| 226 | }; | 226 | }; |
| 227 | 227 | ||
| 228 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { | 228 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { |
| @@ -249,10 +249,10 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { | |||
| 249 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system); | 249 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 252 | AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_, |
| 253 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 253 | Core::System& system_) |
| 254 | : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), | 254 | : ServiceFramework{system_, "appletAE"}, nvflinger{nvflinger_}, msg_queue{ |
| 255 | msg_queue(std::move(msg_queue)), system(system) { | 255 | std::move(msg_queue_)} { |
| 256 | // clang-format off | 256 | // clang-format off |
| 257 | static const FunctionInfo functions[] = { | 257 | static const FunctionInfo functions[] = { |
| 258 | {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, | 258 | {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, |
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 2e3e45915..adb207349 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h | |||
| @@ -23,8 +23,8 @@ class AppletMessageQueue; | |||
| 23 | 23 | ||
| 24 | class AppletAE final : public ServiceFramework<AppletAE> { | 24 | class AppletAE final : public ServiceFramework<AppletAE> { |
| 25 | public: | 25 | public: |
| 26 | explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletAE(NVFlinger::NVFlinger& nvflinger_, |
| 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); | 27 | std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); |
| 28 | ~AppletAE() override; | 28 | ~AppletAE() override; |
| 29 | 29 | ||
| 30 | const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; | 30 | const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; |
| @@ -34,9 +34,8 @@ private: | |||
| 34 | void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); | 34 | void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); |
| 35 | void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); | 35 | void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); |
| 36 | 36 | ||
| 37 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 37 | NVFlinger::NVFlinger& nvflinger; |
| 38 | std::shared_ptr<AppletMessageQueue> msg_queue; | 38 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 39 | Core::System& system; | ||
| 40 | }; | 39 | }; |
| 41 | 40 | ||
| 42 | } // namespace AM | 41 | } // namespace AM |
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index a2ffaa440..f9eba8f52 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp | |||
| @@ -12,10 +12,11 @@ namespace Service::AM { | |||
| 12 | 12 | ||
| 13 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { | 13 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { |
| 14 | public: | 14 | public: |
| 15 | explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 15 | explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger_, |
| 16 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 16 | std::shared_ptr<AppletMessageQueue> msg_queue_, |
| 17 | : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), | 17 | Core::System& system_) |
| 18 | msg_queue(std::move(msg_queue)), system(system) { | 18 | : ServiceFramework{system_, "IApplicationProxy"}, nvflinger{nvflinger_}, |
| 19 | msg_queue{std::move(msg_queue_)} { | ||
| 19 | // clang-format off | 20 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 21 | {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, | 22 | {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
| @@ -39,7 +40,7 @@ private: | |||
| 39 | 40 | ||
| 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 41 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 41 | rb.Push(RESULT_SUCCESS); | 42 | rb.Push(RESULT_SUCCESS); |
| 42 | rb.PushIpcInterface<IAudioController>(); | 43 | rb.PushIpcInterface<IAudioController>(system); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 46 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| @@ -47,7 +48,7 @@ private: | |||
| 47 | 48 | ||
| 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 49 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 50 | rb.PushIpcInterface<IDisplayController>(); | 51 | rb.PushIpcInterface<IDisplayController>(system); |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 54 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| @@ -55,7 +56,7 @@ private: | |||
| 55 | 56 | ||
| 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 57 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 57 | rb.Push(RESULT_SUCCESS); | 58 | rb.Push(RESULT_SUCCESS); |
| 58 | rb.PushIpcInterface<IDebugFunctions>(); | 59 | rb.PushIpcInterface<IDebugFunctions>(system); |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 62 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| @@ -98,9 +99,8 @@ private: | |||
| 98 | rb.PushIpcInterface<IApplicationFunctions>(system); | 99 | rb.PushIpcInterface<IApplicationFunctions>(system); |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 102 | NVFlinger::NVFlinger& nvflinger; |
| 102 | std::shared_ptr<AppletMessageQueue> msg_queue; | 103 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 103 | Core::System& system; | ||
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | 106 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { |
| @@ -111,10 +111,10 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | |||
| 111 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system); | 111 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 114 | AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_, |
| 115 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 115 | Core::System& system_) |
| 116 | : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), | 116 | : ServiceFramework{system_, "appletOE"}, nvflinger{nvflinger_}, msg_queue{ |
| 117 | msg_queue(std::move(msg_queue)), system(system) { | 117 | std::move(msg_queue_)} { |
| 118 | static const FunctionInfo functions[] = { | 118 | static const FunctionInfo functions[] = { |
| 119 | {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, | 119 | {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, |
| 120 | }; | 120 | }; |
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 758da792d..6c1aa255a 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h | |||
| @@ -23,8 +23,8 @@ class AppletMessageQueue; | |||
| 23 | 23 | ||
| 24 | class AppletOE final : public ServiceFramework<AppletOE> { | 24 | class AppletOE final : public ServiceFramework<AppletOE> { |
| 25 | public: | 25 | public: |
| 26 | explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletOE(NVFlinger::NVFlinger& nvflinger_, |
| 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); | 27 | std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_); |
| 28 | ~AppletOE() override; | 28 | ~AppletOE() override; |
| 29 | 29 | ||
| 30 | const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; | 30 | const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; |
| @@ -32,9 +32,8 @@ public: | |||
| 32 | private: | 32 | private: |
| 33 | void OpenApplicationProxy(Kernel::HLERequestContext& ctx); | 33 | void OpenApplicationProxy(Kernel::HLERequestContext& ctx); |
| 34 | 34 | ||
| 35 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 35 | NVFlinger::NVFlinger& nvflinger; |
| 36 | std::shared_ptr<AppletMessageQueue> msg_queue; | 36 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 37 | Core::System& system; | ||
| 38 | }; | 37 | }; |
| 39 | 38 | ||
| 40 | } // namespace AM | 39 | } // namespace AM |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 4e0800f9a..08676c3fc 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -142,14 +142,14 @@ void Applet::Initialize() { | |||
| 142 | 142 | ||
| 143 | AppletFrontendSet::AppletFrontendSet() = default; | 143 | AppletFrontendSet::AppletFrontendSet() = default; |
| 144 | 144 | ||
| 145 | AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, | 145 | AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, |
| 146 | ErrorApplet error, ParentalControlsApplet parental_controls, | 146 | ParentalControlsApplet parental_controls_applet, |
| 147 | PhotoViewer photo_viewer, ProfileSelect profile_select, | 147 | PhotoViewer photo_viewer_, ProfileSelect profile_select_, |
| 148 | SoftwareKeyboard software_keyboard, WebBrowser web_browser) | 148 | SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) |
| 149 | : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)}, | 149 | : controller{std::move(controller_applet)}, error{std::move(error_applet)}, |
| 150 | parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)}, | 150 | parental_controls{std::move(parental_controls_applet)}, |
| 151 | profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)}, | 151 | photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, |
| 152 | web_browser{std::move(web_browser)} {} | 152 | software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} |
| 153 | 153 | ||
| 154 | AppletFrontendSet::~AppletFrontendSet() = default; | 154 | AppletFrontendSet::~AppletFrontendSet() = default; |
| 155 | 155 | ||
| @@ -170,10 +170,6 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | |||
| 170 | frontend.controller = std::move(set.controller); | 170 | frontend.controller = std::move(set.controller); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | if (set.e_commerce != nullptr) { | ||
| 174 | frontend.e_commerce = std::move(set.e_commerce); | ||
| 175 | } | ||
| 176 | |||
| 177 | if (set.error != nullptr) { | 173 | if (set.error != nullptr) { |
| 178 | frontend.error = std::move(set.error); | 174 | frontend.error = std::move(set.error); |
| 179 | } | 175 | } |
| @@ -206,11 +202,8 @@ void AppletManager::SetDefaultAppletFrontendSet() { | |||
| 206 | 202 | ||
| 207 | void AppletManager::SetDefaultAppletsIfMissing() { | 203 | void AppletManager::SetDefaultAppletsIfMissing() { |
| 208 | if (frontend.controller == nullptr) { | 204 | if (frontend.controller == nullptr) { |
| 209 | frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>(); | 205 | frontend.controller = |
| 210 | } | 206 | std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager()); |
| 211 | |||
| 212 | if (frontend.e_commerce == nullptr) { | ||
| 213 | frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); | ||
| 214 | } | 207 | } |
| 215 | 208 | ||
| 216 | if (frontend.error == nullptr) { | 209 | if (frontend.error == nullptr) { |
| @@ -256,13 +249,14 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { | |||
| 256 | return std::make_shared<ProfileSelect>(system, *frontend.profile_select); | 249 | return std::make_shared<ProfileSelect>(system, *frontend.profile_select); |
| 257 | case AppletId::SoftwareKeyboard: | 250 | case AppletId::SoftwareKeyboard: |
| 258 | return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); | 251 | return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); |
| 252 | case AppletId::Web: | ||
| 253 | case AppletId::Shop: | ||
| 254 | case AppletId::OfflineWeb: | ||
| 255 | case AppletId::LoginShare: | ||
| 256 | case AppletId::WebAuth: | ||
| 257 | return std::make_shared<WebBrowser>(system, *frontend.web_browser); | ||
| 259 | case AppletId::PhotoViewer: | 258 | case AppletId::PhotoViewer: |
| 260 | return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); | 259 | return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); |
| 261 | case AppletId::LibAppletShop: | ||
| 262 | return std::make_shared<WebBrowser>(system, *frontend.web_browser, | ||
| 263 | frontend.e_commerce.get()); | ||
| 264 | case AppletId::LibAppletOff: | ||
| 265 | return std::make_shared<WebBrowser>(system, *frontend.web_browser); | ||
| 266 | default: | 260 | default: |
| 267 | UNIMPLEMENTED_MSG( | 261 | UNIMPLEMENTED_MSG( |
| 268 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", | 262 | "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index a1f4cf897..4fd792c05 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -50,13 +50,13 @@ enum class AppletId : u32 { | |||
| 50 | ProfileSelect = 0x10, | 50 | ProfileSelect = 0x10, |
| 51 | SoftwareKeyboard = 0x11, | 51 | SoftwareKeyboard = 0x11, |
| 52 | MiiEdit = 0x12, | 52 | MiiEdit = 0x12, |
| 53 | LibAppletWeb = 0x13, | 53 | Web = 0x13, |
| 54 | LibAppletShop = 0x14, | 54 | Shop = 0x14, |
| 55 | PhotoViewer = 0x15, | 55 | PhotoViewer = 0x15, |
| 56 | Settings = 0x16, | 56 | Settings = 0x16, |
| 57 | LibAppletOff = 0x17, | 57 | OfflineWeb = 0x17, |
| 58 | LibAppletWhitelisted = 0x18, | 58 | LoginShare = 0x18, |
| 59 | LibAppletAuth = 0x19, | 59 | WebAuth = 0x19, |
| 60 | MyPage = 0x1A, | 60 | MyPage = 0x1A, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| @@ -157,7 +157,6 @@ protected: | |||
| 157 | 157 | ||
| 158 | struct AppletFrontendSet { | 158 | struct AppletFrontendSet { |
| 159 | using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; | 159 | using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; |
| 160 | using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>; | ||
| 161 | using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; | 160 | using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; |
| 162 | using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; | 161 | using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; |
| 163 | using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; | 162 | using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; |
| @@ -166,10 +165,10 @@ struct AppletFrontendSet { | |||
| 166 | using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; | 165 | using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; |
| 167 | 166 | ||
| 168 | AppletFrontendSet(); | 167 | AppletFrontendSet(); |
| 169 | AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error, | 168 | AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, |
| 170 | ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, | 169 | ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, |
| 171 | ProfileSelect profile_select, SoftwareKeyboard software_keyboard, | 170 | ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, |
| 172 | WebBrowser web_browser); | 171 | WebBrowser web_browser_); |
| 173 | ~AppletFrontendSet(); | 172 | ~AppletFrontendSet(); |
| 174 | 173 | ||
| 175 | AppletFrontendSet(const AppletFrontendSet&) = delete; | 174 | AppletFrontendSet(const AppletFrontendSet&) = delete; |
| @@ -179,7 +178,6 @@ struct AppletFrontendSet { | |||
| 179 | AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; | 178 | AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; |
| 180 | 179 | ||
| 181 | ControllerApplet controller; | 180 | ControllerApplet controller; |
| 182 | ECommerceApplet e_commerce; | ||
| 183 | ErrorApplet error; | 181 | ErrorApplet error; |
| 184 | ParentalControlsApplet parental_controls; | 182 | ParentalControlsApplet parental_controls; |
| 185 | PhotoViewer photo_viewer; | 183 | PhotoViewer photo_viewer; |
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp index 2151da783..7edfca64e 100644 --- a/src/core/hle/service/am/applets/controller.cpp +++ b/src/core/hle/service/am/applets/controller.cpp | |||
| @@ -25,18 +25,18 @@ namespace Service::AM::Applets { | |||
| 25 | static Core::Frontend::ControllerParameters ConvertToFrontendParameters( | 25 | static Core::Frontend::ControllerParameters ConvertToFrontendParameters( |
| 26 | ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, | 26 | ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, |
| 27 | std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { | 27 | std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { |
| 28 | HID::Controller_NPad::NPadType npad_style_set; | 28 | HID::Controller_NPad::NpadStyleSet npad_style_set; |
| 29 | npad_style_set.raw = private_arg.style_set; | 29 | npad_style_set.raw = private_arg.style_set; |
| 30 | 30 | ||
| 31 | return { | 31 | return { |
| 32 | .min_players = std::max(s8(1), header.player_count_min), | 32 | .min_players = std::max(s8{1}, header.player_count_min), |
| 33 | .max_players = header.player_count_max, | 33 | .max_players = header.player_count_max, |
| 34 | .keep_controllers_connected = header.enable_take_over_connection, | 34 | .keep_controllers_connected = header.enable_take_over_connection, |
| 35 | .enable_single_mode = header.enable_single_mode, | 35 | .enable_single_mode = header.enable_single_mode, |
| 36 | .enable_border_color = header.enable_identification_color, | 36 | .enable_border_color = header.enable_identification_color, |
| 37 | .border_colors = identification_colors, | 37 | .border_colors = std::move(identification_colors), |
| 38 | .enable_explain_text = enable_text, | 38 | .enable_explain_text = enable_text, |
| 39 | .explain_text = text, | 39 | .explain_text = std::move(text), |
| 40 | .allow_pro_controller = npad_style_set.pro_controller == 1, | 40 | .allow_pro_controller = npad_style_set.pro_controller == 1, |
| 41 | .allow_handheld = npad_style_set.handheld == 1, | 41 | .allow_handheld = npad_style_set.handheld == 1, |
| 42 | .allow_dual_joycons = npad_style_set.joycon_dual == 1, | 42 | .allow_dual_joycons = npad_style_set.joycon_dual == 1, |
| @@ -46,7 +46,7 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters( | |||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) | 48 | Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) |
| 49 | : Applet{system_.Kernel()}, frontend(frontend_) {} | 49 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 50 | 50 | ||
| 51 | Controller::~Controller() = default; | 51 | Controller::~Controller() = default; |
| 52 | 52 | ||
| @@ -62,7 +62,7 @@ void Controller::Initialize() { | |||
| 62 | common_args.play_startup_sound, common_args.size, common_args.system_tick, | 62 | common_args.play_startup_sound, common_args.size, common_args.system_tick, |
| 63 | common_args.theme_color); | 63 | common_args.theme_color); |
| 64 | 64 | ||
| 65 | library_applet_version = LibraryAppletVersion{common_args.library_version}; | 65 | controller_applet_version = ControllerAppletVersion{common_args.library_version}; |
| 66 | 66 | ||
| 67 | const auto private_arg_storage = broker.PopNormalDataToApplet(); | 67 | const auto private_arg_storage = broker.PopNormalDataToApplet(); |
| 68 | ASSERT(private_arg_storage != nullptr); | 68 | ASSERT(private_arg_storage != nullptr); |
| @@ -70,39 +70,78 @@ void Controller::Initialize() { | |||
| 70 | const auto& private_arg = private_arg_storage->GetData(); | 70 | const auto& private_arg = private_arg_storage->GetData(); |
| 71 | ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); | 71 | ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); |
| 72 | 72 | ||
| 73 | std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate)); | 73 | std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size()); |
| 74 | ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), | 74 | ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), |
| 75 | "Unknown ControllerSupportArgPrivate revision={} with size={}", | 75 | "Unknown ControllerSupportArgPrivate revision={} with size={}", |
| 76 | library_applet_version, controller_private_arg.arg_private_size); | 76 | controller_applet_version, controller_private_arg.arg_private_size); |
| 77 | |||
| 78 | // Some games such as Cave Story+ set invalid values for the ControllerSupportMode. | ||
| 79 | // Defer to arg_size to set the ControllerSupportMode. | ||
| 80 | if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) { | ||
| 81 | switch (controller_private_arg.arg_size) { | ||
| 82 | case sizeof(ControllerSupportArgOld): | ||
| 83 | case sizeof(ControllerSupportArgNew): | ||
| 84 | controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; | ||
| 85 | break; | ||
| 86 | case sizeof(ControllerUpdateFirmwareArg): | ||
| 87 | controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate; | ||
| 88 | break; | ||
| 89 | default: | ||
| 90 | UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}", | ||
| 91 | controller_private_arg.mode, controller_private_arg.arg_size); | ||
| 92 | controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller. | ||
| 98 | // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem. | ||
| 99 | if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) { | ||
| 100 | if (controller_private_arg.flag_1 && | ||
| 101 | controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) { | ||
| 102 | controller_private_arg.caller = ControllerSupportCaller::System; | ||
| 103 | } else { | ||
| 104 | controller_private_arg.caller = ControllerSupportCaller::Application; | ||
| 105 | } | ||
| 106 | } | ||
| 77 | 107 | ||
| 78 | switch (controller_private_arg.mode) { | 108 | switch (controller_private_arg.mode) { |
| 79 | case ControllerSupportMode::ShowControllerSupport: { | 109 | case ControllerSupportMode::ShowControllerSupport: |
| 110 | case ControllerSupportMode::ShowControllerStrapGuide: { | ||
| 80 | const auto user_arg_storage = broker.PopNormalDataToApplet(); | 111 | const auto user_arg_storage = broker.PopNormalDataToApplet(); |
| 81 | ASSERT(user_arg_storage != nullptr); | 112 | ASSERT(user_arg_storage != nullptr); |
| 82 | 113 | ||
| 83 | const auto& user_arg = user_arg_storage->GetData(); | 114 | const auto& user_arg = user_arg_storage->GetData(); |
| 84 | switch (library_applet_version) { | 115 | switch (controller_applet_version) { |
| 85 | case LibraryAppletVersion::Version3: | 116 | case ControllerAppletVersion::Version3: |
| 86 | case LibraryAppletVersion::Version4: | 117 | case ControllerAppletVersion::Version4: |
| 87 | case LibraryAppletVersion::Version5: | 118 | case ControllerAppletVersion::Version5: |
| 88 | ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); | 119 | ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); |
| 89 | std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld)); | 120 | std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size()); |
| 90 | break; | 121 | break; |
| 91 | case LibraryAppletVersion::Version7: | 122 | case ControllerAppletVersion::Version7: |
| 92 | ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); | 123 | ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); |
| 93 | std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); | 124 | std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size()); |
| 94 | break; | 125 | break; |
| 95 | default: | 126 | default: |
| 96 | UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", | 127 | UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", |
| 97 | library_applet_version, controller_private_arg.arg_size); | 128 | controller_applet_version, controller_private_arg.arg_size); |
| 98 | ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); | 129 | ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); |
| 99 | std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); | 130 | std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); |
| 100 | break; | 131 | break; |
| 101 | } | 132 | } |
| 102 | break; | 133 | break; |
| 103 | } | 134 | } |
| 104 | case ControllerSupportMode::ShowControllerStrapGuide: | 135 | case ControllerSupportMode::ShowControllerFirmwareUpdate: { |
| 105 | case ControllerSupportMode::ShowControllerFirmwareUpdate: | 136 | const auto update_arg_storage = broker.PopNormalDataToApplet(); |
| 137 | ASSERT(update_arg_storage != nullptr); | ||
| 138 | |||
| 139 | const auto& update_arg = update_arg_storage->GetData(); | ||
| 140 | ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg)); | ||
| 141 | |||
| 142 | std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size()); | ||
| 143 | break; | ||
| 144 | } | ||
| 106 | default: { | 145 | default: { |
| 107 | UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); | 146 | UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); |
| 108 | break; | 147 | break; |
| @@ -126,10 +165,10 @@ void Controller::Execute() { | |||
| 126 | switch (controller_private_arg.mode) { | 165 | switch (controller_private_arg.mode) { |
| 127 | case ControllerSupportMode::ShowControllerSupport: { | 166 | case ControllerSupportMode::ShowControllerSupport: { |
| 128 | const auto parameters = [this] { | 167 | const auto parameters = [this] { |
| 129 | switch (library_applet_version) { | 168 | switch (controller_applet_version) { |
| 130 | case LibraryAppletVersion::Version3: | 169 | case ControllerAppletVersion::Version3: |
| 131 | case LibraryAppletVersion::Version4: | 170 | case ControllerAppletVersion::Version4: |
| 132 | case LibraryAppletVersion::Version5: | 171 | case ControllerAppletVersion::Version5: |
| 133 | return ConvertToFrontendParameters( | 172 | return ConvertToFrontendParameters( |
| 134 | controller_private_arg, controller_user_arg_old.header, | 173 | controller_private_arg, controller_user_arg_old.header, |
| 135 | controller_user_arg_old.enable_explain_text, | 174 | controller_user_arg_old.enable_explain_text, |
| @@ -138,7 +177,7 @@ void Controller::Execute() { | |||
| 138 | controller_user_arg_old.identification_colors.end()), | 177 | controller_user_arg_old.identification_colors.end()), |
| 139 | std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(), | 178 | std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(), |
| 140 | controller_user_arg_old.explain_text.end())); | 179 | controller_user_arg_old.explain_text.end())); |
| 141 | case LibraryAppletVersion::Version7: | 180 | case ControllerAppletVersion::Version7: |
| 142 | default: | 181 | default: |
| 143 | return ConvertToFrontendParameters( | 182 | return ConvertToFrontendParameters( |
| 144 | controller_private_arg, controller_user_arg_new.header, | 183 | controller_private_arg, controller_user_arg_new.header, |
| @@ -170,6 +209,9 @@ void Controller::Execute() { | |||
| 170 | } | 209 | } |
| 171 | case ControllerSupportMode::ShowControllerStrapGuide: | 210 | case ControllerSupportMode::ShowControllerStrapGuide: |
| 172 | case ControllerSupportMode::ShowControllerFirmwareUpdate: | 211 | case ControllerSupportMode::ShowControllerFirmwareUpdate: |
| 212 | UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", | ||
| 213 | controller_private_arg.mode); | ||
| 214 | [[fallthrough]]; | ||
| 173 | default: { | 215 | default: { |
| 174 | ConfigurationComplete(); | 216 | ConfigurationComplete(); |
| 175 | break; | 217 | break; |
| @@ -180,20 +222,19 @@ void Controller::Execute() { | |||
| 180 | void Controller::ConfigurationComplete() { | 222 | void Controller::ConfigurationComplete() { |
| 181 | ControllerSupportResultInfo result_info{}; | 223 | ControllerSupportResultInfo result_info{}; |
| 182 | 224 | ||
| 183 | const auto& players = Settings::values.players; | 225 | const auto& players = Settings::values.players.GetValue(); |
| 184 | 226 | ||
| 185 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. | 227 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. |
| 186 | // Otherwise, only count connected players from P1-P8. | 228 | // Otherwise, only count connected players from P1-P8. |
| 187 | result_info.player_count = | 229 | result_info.player_count = |
| 188 | is_single_mode ? 1 | 230 | is_single_mode |
| 189 | : static_cast<s8>(std::count_if( | 231 | ? 1 |
| 190 | players.begin(), players.end() - 2, | 232 | : static_cast<s8>(std::count_if(players.begin(), players.end() - 2, |
| 191 | [](Settings::PlayerInput player) { return player.connected; })); | 233 | [](const auto& player) { return player.connected; })); |
| 192 | 234 | ||
| 193 | result_info.selected_id = HID::Controller_NPad::IndexToNPad( | 235 | result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance( |
| 194 | std::distance(players.begin(), | 236 | players.begin(), std::find_if(players.begin(), players.end(), |
| 195 | std::find_if(players.begin(), players.end(), | 237 | [](const auto& player) { return player.connected; }))); |
| 196 | [](Settings::PlayerInput player) { return player.connected; }))); | ||
| 197 | 238 | ||
| 198 | result_info.result = 0; | 239 | result_info.result = 0; |
| 199 | 240 | ||
| @@ -203,7 +244,7 @@ void Controller::ConfigurationComplete() { | |||
| 203 | complete = true; | 244 | complete = true; |
| 204 | out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); | 245 | out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); |
| 205 | std::memcpy(out_data.data(), &result_info, out_data.size()); | 246 | std::memcpy(out_data.data(), &result_info, out_data.size()); |
| 206 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data))); | 247 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); |
| 207 | broker.SignalStateChanged(); | 248 | broker.SignalStateChanged(); |
| 208 | } | 249 | } |
| 209 | 250 | ||
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h index f7bb3fba9..d4c9da7b1 100644 --- a/src/core/hle/service/am/applets/controller.h +++ b/src/core/hle/service/am/applets/controller.h | |||
| @@ -21,7 +21,7 @@ namespace Service::AM::Applets { | |||
| 21 | using IdentificationColor = std::array<u8, 4>; | 21 | using IdentificationColor = std::array<u8, 4>; |
| 22 | using ExplainText = std::array<char, 0x81>; | 22 | using ExplainText = std::array<char, 0x81>; |
| 23 | 23 | ||
| 24 | enum class LibraryAppletVersion : u32_le { | 24 | enum class ControllerAppletVersion : u32_le { |
| 25 | Version3 = 0x3, // 1.0.0 - 2.3.0 | 25 | Version3 = 0x3, // 1.0.0 - 2.3.0 |
| 26 | Version4 = 0x4, // 3.0.0 - 5.1.0 | 26 | Version4 = 0x4, // 3.0.0 - 5.1.0 |
| 27 | Version5 = 0x5, // 6.0.0 - 7.0.1 | 27 | Version5 = 0x5, // 6.0.0 - 7.0.1 |
| @@ -29,14 +29,18 @@ enum class LibraryAppletVersion : u32_le { | |||
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | enum class ControllerSupportMode : u8 { | 31 | enum class ControllerSupportMode : u8 { |
| 32 | ShowControllerSupport = 0, | 32 | ShowControllerSupport, |
| 33 | ShowControllerStrapGuide = 1, | 33 | ShowControllerStrapGuide, |
| 34 | ShowControllerFirmwareUpdate = 2, | 34 | ShowControllerFirmwareUpdate, |
| 35 | |||
| 36 | MaxControllerSupportMode, | ||
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| 37 | enum class ControllerSupportCaller : u8 { | 39 | enum class ControllerSupportCaller : u8 { |
| 38 | Application = 0, | 40 | Application, |
| 39 | System = 1, | 41 | System, |
| 42 | |||
| 43 | MaxControllerSupportCaller, | ||
| 40 | }; | 44 | }; |
| 41 | 45 | ||
| 42 | struct ControllerSupportArgPrivate { | 46 | struct ControllerSupportArgPrivate { |
| @@ -84,6 +88,13 @@ struct ControllerSupportArgNew { | |||
| 84 | static_assert(sizeof(ControllerSupportArgNew) == 0x430, | 88 | static_assert(sizeof(ControllerSupportArgNew) == 0x430, |
| 85 | "ControllerSupportArgNew has incorrect size."); | 89 | "ControllerSupportArgNew has incorrect size."); |
| 86 | 90 | ||
| 91 | struct ControllerUpdateFirmwareArg { | ||
| 92 | bool enable_force_update{}; | ||
| 93 | INSERT_PADDING_BYTES(3); | ||
| 94 | }; | ||
| 95 | static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4, | ||
| 96 | "ControllerUpdateFirmwareArg has incorrect size."); | ||
| 97 | |||
| 87 | struct ControllerSupportResultInfo { | 98 | struct ControllerSupportResultInfo { |
| 88 | s8 player_count{}; | 99 | s8 player_count{}; |
| 89 | INSERT_PADDING_BYTES(3); | 100 | INSERT_PADDING_BYTES(3); |
| @@ -109,11 +120,13 @@ public: | |||
| 109 | 120 | ||
| 110 | private: | 121 | private: |
| 111 | const Core::Frontend::ControllerApplet& frontend; | 122 | const Core::Frontend::ControllerApplet& frontend; |
| 123 | Core::System& system; | ||
| 112 | 124 | ||
| 113 | LibraryAppletVersion library_applet_version; | 125 | ControllerAppletVersion controller_applet_version; |
| 114 | ControllerSupportArgPrivate controller_private_arg; | 126 | ControllerSupportArgPrivate controller_private_arg; |
| 115 | ControllerSupportArgOld controller_user_arg_old; | 127 | ControllerSupportArgOld controller_user_arg_old; |
| 116 | ControllerSupportArgNew controller_user_arg_new; | 128 | ControllerSupportArgNew controller_user_arg_new; |
| 129 | ControllerUpdateFirmwareArg controller_update_arg; | ||
| 117 | bool complete{false}; | 130 | bool complete{false}; |
| 118 | ResultCode status{RESULT_SUCCESS}; | 131 | ResultCode status{RESULT_SUCCESS}; |
| 119 | bool is_single_mode{false}; | 132 | bool is_single_mode{false}; |
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index f12fd7f89..d85505082 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp | |||
| @@ -87,7 +87,7 @@ ResultCode Decode64BitError(u64 error) { | |||
| 87 | } // Anonymous namespace | 87 | } // Anonymous namespace |
| 88 | 88 | ||
| 89 | Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) | 89 | Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) |
| 90 | : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} | 90 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 91 | 91 | ||
| 92 | Error::~Error() = default; | 92 | Error::~Error() = default; |
| 93 | 93 | ||
| @@ -125,7 +125,7 @@ void Error::Initialize() { | |||
| 125 | error_code = Decode64BitError(args->error_record.error_code_64); | 125 | error_code = Decode64BitError(args->error_record.error_code_64); |
| 126 | break; | 126 | break; |
| 127 | default: | 127 | default: |
| 128 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); | 128 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); |
| 129 | } | 129 | } |
| 130 | } | 130 | } |
| 131 | 131 | ||
| @@ -179,14 +179,14 @@ void Error::Execute() { | |||
| 179 | error_code, std::chrono::seconds{args->error_record.posix_time}, callback); | 179 | error_code, std::chrono::seconds{args->error_record.posix_time}, callback); |
| 180 | break; | 180 | break; |
| 181 | default: | 181 | default: |
| 182 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); | 182 | UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); |
| 183 | DisplayCompleted(); | 183 | DisplayCompleted(); |
| 184 | } | 184 | } |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | void Error::DisplayCompleted() { | 187 | void Error::DisplayCompleted() { |
| 188 | complete = true; | 188 | complete = true; |
| 189 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); | 189 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); |
| 190 | broker.SignalStateChanged(); | 190 | broker.SignalStateChanged(); |
| 191 | } | 191 | } |
| 192 | 192 | ||
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 104501ac5..4d1df5cbe 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp | |||
| @@ -38,7 +38,7 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) | 40 | Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) |
| 41 | : Applet{system_.Kernel()}, frontend(frontend_) {} | 41 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 42 | 42 | ||
| 43 | Auth::~Auth() = default; | 43 | Auth::~Auth() = default; |
| 44 | 44 | ||
| @@ -90,7 +90,7 @@ void Auth::Execute() { | |||
| 90 | const auto unimplemented_log = [this] { | 90 | const auto unimplemented_log = [this] { |
| 91 | UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " | 91 | UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " |
| 92 | "arg1={:02X}, arg2={:02X}", | 92 | "arg1={:02X}, arg2={:02X}", |
| 93 | static_cast<u32>(type), arg0, arg1, arg2); | 93 | type, arg0, arg1, arg2); |
| 94 | }; | 94 | }; |
| 95 | 95 | ||
| 96 | switch (type) { | 96 | switch (type) { |
| @@ -135,8 +135,8 @@ void Auth::Execute() { | |||
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | void Auth::AuthFinished(bool successful) { | 138 | void Auth::AuthFinished(bool is_successful) { |
| 139 | this->successful = successful; | 139 | successful = is_successful; |
| 140 | 140 | ||
| 141 | struct Return { | 141 | struct Return { |
| 142 | ResultCode result_code; | 142 | ResultCode result_code; |
| @@ -148,12 +148,12 @@ void Auth::AuthFinished(bool successful) { | |||
| 148 | std::vector<u8> out(sizeof(Return)); | 148 | std::vector<u8> out(sizeof(Return)); |
| 149 | std::memcpy(out.data(), &return_, sizeof(Return)); | 149 | std::memcpy(out.data(), &return_, sizeof(Return)); |
| 150 | 150 | ||
| 151 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out))); | 151 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out))); |
| 152 | broker.SignalStateChanged(); | 152 | broker.SignalStateChanged(); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) | 155 | PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) |
| 156 | : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} | 156 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 157 | 157 | ||
| 158 | PhotoViewer::~PhotoViewer() = default; | 158 | PhotoViewer::~PhotoViewer() = default; |
| 159 | 159 | ||
| @@ -193,17 +193,17 @@ void PhotoViewer::Execute() { | |||
| 193 | frontend.ShowAllPhotos(callback); | 193 | frontend.ShowAllPhotos(callback); |
| 194 | break; | 194 | break; |
| 195 | default: | 195 | default: |
| 196 | UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", static_cast<u8>(mode)); | 196 | UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); |
| 197 | } | 197 | } |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | void PhotoViewer::ViewFinished() { | 200 | void PhotoViewer::ViewFinished() { |
| 201 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); | 201 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); |
| 202 | broker.SignalStateChanged(); | 202 | broker.SignalStateChanged(); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | StubApplet::StubApplet(Core::System& system_, AppletId id_) | 205 | StubApplet::StubApplet(Core::System& system_, AppletId id_) |
| 206 | : Applet{system_.Kernel()}, id(id_), system{system_} {} | 206 | : Applet{system_.Kernel()}, id{id_}, system{system_} {} |
| 207 | 207 | ||
| 208 | StubApplet::~StubApplet() = default; | 208 | StubApplet::~StubApplet() = default; |
| 209 | 209 | ||
| @@ -234,8 +234,9 @@ void StubApplet::ExecuteInteractive() { | |||
| 234 | LOG_WARNING(Service_AM, "called (STUBBED)"); | 234 | LOG_WARNING(Service_AM, "called (STUBBED)"); |
| 235 | LogCurrentStorage(broker, "ExecuteInteractive"); | 235 | LogCurrentStorage(broker, "ExecuteInteractive"); |
| 236 | 236 | ||
| 237 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); | 237 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); |
| 238 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); | 238 | broker.PushInteractiveDataFromApplet( |
| 239 | std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); | ||
| 239 | broker.SignalStateChanged(); | 240 | broker.SignalStateChanged(); |
| 240 | } | 241 | } |
| 241 | 242 | ||
| @@ -243,8 +244,9 @@ void StubApplet::Execute() { | |||
| 243 | LOG_WARNING(Service_AM, "called (STUBBED)"); | 244 | LOG_WARNING(Service_AM, "called (STUBBED)"); |
| 244 | LogCurrentStorage(broker, "Execute"); | 245 | LogCurrentStorage(broker, "Execute"); |
| 245 | 246 | ||
| 246 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); | 247 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); |
| 247 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); | 248 | broker.PushInteractiveDataFromApplet( |
| 249 | std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); | ||
| 248 | broker.SignalStateChanged(); | 250 | broker.SignalStateChanged(); |
| 249 | } | 251 | } |
| 250 | 252 | ||
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index cfa2df369..ba76ae3d3 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h | |||
| @@ -29,10 +29,11 @@ public: | |||
| 29 | void ExecuteInteractive() override; | 29 | void ExecuteInteractive() override; |
| 30 | void Execute() override; | 30 | void Execute() override; |
| 31 | 31 | ||
| 32 | void AuthFinished(bool successful = true); | 32 | void AuthFinished(bool is_successful = true); |
| 33 | 33 | ||
| 34 | private: | 34 | private: |
| 35 | Core::Frontend::ParentalControlsApplet& frontend; | 35 | Core::Frontend::ParentalControlsApplet& frontend; |
| 36 | Core::System& system; | ||
| 36 | bool complete = false; | 37 | bool complete = false; |
| 37 | bool successful = false; | 38 | bool successful = false; |
| 38 | 39 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 70cc23552..77fba16c7 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp | |||
| @@ -17,7 +17,7 @@ constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; | |||
| 17 | 17 | ||
| 18 | ProfileSelect::ProfileSelect(Core::System& system_, | 18 | ProfileSelect::ProfileSelect(Core::System& system_, |
| 19 | const Core::Frontend::ProfileSelectApplet& frontend_) | 19 | const Core::Frontend::ProfileSelectApplet& frontend_) |
| 20 | : Applet{system_.Kernel()}, frontend(frontend_) {} | 20 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 21 | 21 | ||
| 22 | ProfileSelect::~ProfileSelect() = default; | 22 | ProfileSelect::~ProfileSelect() = default; |
| 23 | 23 | ||
| @@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() { | |||
| 50 | 50 | ||
| 51 | void ProfileSelect::Execute() { | 51 | void ProfileSelect::Execute() { |
| 52 | if (complete) { | 52 | if (complete) { |
| 53 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); | 53 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); |
| 54 | return; | 54 | return; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| @@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | |||
| 71 | 71 | ||
| 72 | final_data = std::vector<u8>(sizeof(UserSelectionOutput)); | 72 | final_data = std::vector<u8>(sizeof(UserSelectionOutput)); |
| 73 | std::memcpy(final_data.data(), &output, final_data.size()); | 73 | std::memcpy(final_data.data(), &output, final_data.size()); |
| 74 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); | 74 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); |
| 75 | broker.SignalStateChanged(); | 75 | broker.SignalStateChanged(); |
| 76 | } | 76 | } |
| 77 | 77 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index 16364ead7..648d33a24 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h | |||
| @@ -53,6 +53,7 @@ private: | |||
| 53 | bool complete = false; | 53 | bool complete = false; |
| 54 | ResultCode status = RESULT_SUCCESS; | 54 | ResultCode status = RESULT_SUCCESS; |
| 55 | std::vector<u8> final_data; | 55 | std::vector<u8> final_data; |
| 56 | Core::System& system; | ||
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 58 | } // namespace Service::AM::Applets | 59 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index bdeb0737a..3022438b1 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -53,7 +53,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( | |||
| 53 | 53 | ||
| 54 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, | 54 | SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, |
| 55 | const Core::Frontend::SoftwareKeyboardApplet& frontend_) | 55 | const Core::Frontend::SoftwareKeyboardApplet& frontend_) |
| 56 | : Applet{system_.Kernel()}, frontend(frontend_) {} | 56 | : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} |
| 57 | 57 | ||
| 58 | SoftwareKeyboard::~SoftwareKeyboard() = default; | 58 | SoftwareKeyboard::~SoftwareKeyboard() = default; |
| 59 | 59 | ||
| @@ -122,7 +122,7 @@ void SoftwareKeyboard::ExecuteInteractive() { | |||
| 122 | 122 | ||
| 123 | switch (request) { | 123 | switch (request) { |
| 124 | case Request::Calc: { | 124 | case Request::Calc: { |
| 125 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{1})); | 125 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1})); |
| 126 | broker.SignalStateChanged(); | 126 | broker.SignalStateChanged(); |
| 127 | break; | 127 | break; |
| 128 | } | 128 | } |
| @@ -135,7 +135,7 @@ void SoftwareKeyboard::ExecuteInteractive() { | |||
| 135 | 135 | ||
| 136 | void SoftwareKeyboard::Execute() { | 136 | void SoftwareKeyboard::Execute() { |
| 137 | if (complete) { | 137 | if (complete) { |
| 138 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); | 138 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); |
| 139 | broker.SignalStateChanged(); | 139 | broker.SignalStateChanged(); |
| 140 | return; | 140 | return; |
| 141 | } | 141 | } |
| @@ -179,15 +179,17 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | |||
| 179 | final_data = output_main; | 179 | final_data = output_main; |
| 180 | 180 | ||
| 181 | if (complete) { | 181 | if (complete) { |
| 182 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); | 182 | broker.PushNormalDataFromApplet( |
| 183 | std::make_shared<IStorage>(system, std::move(output_main))); | ||
| 183 | broker.SignalStateChanged(); | 184 | broker.SignalStateChanged(); |
| 184 | } else { | 185 | } else { |
| 185 | broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub))); | 186 | broker.PushInteractiveDataFromApplet( |
| 187 | std::make_shared<IStorage>(system, std::move(output_sub))); | ||
| 186 | } | 188 | } |
| 187 | } else { | 189 | } else { |
| 188 | output_main[0] = 1; | 190 | output_main[0] = 1; |
| 189 | complete = true; | 191 | complete = true; |
| 190 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); | 192 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(output_main))); |
| 191 | broker.SignalStateChanged(); | 193 | broker.SignalStateChanged(); |
| 192 | } | 194 | } |
| 193 | } | 195 | } |
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 5a3824b5a..1d260fef8 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h | |||
| @@ -80,6 +80,7 @@ private: | |||
| 80 | bool complete = false; | 80 | bool complete = false; |
| 81 | bool is_inline = false; | 81 | bool is_inline = false; |
| 82 | std::vector<u8> final_data; | 82 | std::vector<u8> final_data; |
| 83 | Core::System& system; | ||
| 83 | }; | 84 | }; |
| 84 | 85 | ||
| 85 | } // namespace Service::AM::Applets | 86 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index efe595c4f..2ab420789 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -1,558 +1,478 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2020 yuzu Emulator Project |
| 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 <array> | ||
| 6 | #include <cstring> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_paths.h" | 6 | #include "common/common_paths.h" |
| 12 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 13 | #include "common/hex_util.h" | ||
| 14 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 15 | #include "common/string_util.h" | 9 | #include "common/string_util.h" |
| 16 | #include "core/core.h" | 10 | #include "core/core.h" |
| 17 | #include "core/file_sys/content_archive.h" | 11 | #include "core/file_sys/content_archive.h" |
| 18 | #include "core/file_sys/mode.h" | 12 | #include "core/file_sys/mode.h" |
| 19 | #include "core/file_sys/nca_metadata.h" | 13 | #include "core/file_sys/nca_metadata.h" |
| 14 | #include "core/file_sys/patch_manager.h" | ||
| 20 | #include "core/file_sys/registered_cache.h" | 15 | #include "core/file_sys/registered_cache.h" |
| 21 | #include "core/file_sys/romfs.h" | 16 | #include "core/file_sys/romfs.h" |
| 22 | #include "core/file_sys/system_archive/system_archive.h" | 17 | #include "core/file_sys/system_archive/system_archive.h" |
| 23 | #include "core/file_sys/vfs_types.h" | 18 | #include "core/file_sys/vfs_vector.h" |
| 24 | #include "core/frontend/applets/general_frontend.h" | ||
| 25 | #include "core/frontend/applets/web_browser.h" | 19 | #include "core/frontend/applets/web_browser.h" |
| 26 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| 21 | #include "core/hle/result.h" | ||
| 22 | #include "core/hle/service/am/am.h" | ||
| 27 | #include "core/hle/service/am/applets/web_browser.h" | 23 | #include "core/hle/service/am/applets/web_browser.h" |
| 28 | #include "core/hle/service/filesystem/filesystem.h" | 24 | #include "core/hle/service/filesystem/filesystem.h" |
| 29 | #include "core/loader/loader.h" | 25 | #include "core/hle/service/ns/pl_u.h" |
| 30 | 26 | ||
| 31 | namespace Service::AM::Applets { | 27 | namespace Service::AM::Applets { |
| 32 | 28 | ||
| 33 | enum class WebArgTLVType : u16 { | ||
| 34 | InitialURL = 0x1, | ||
| 35 | ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name. | ||
| 36 | CallbackURL = 0x3, | ||
| 37 | CallbackableURL = 0x4, | ||
| 38 | ApplicationID = 0x5, | ||
| 39 | DocumentPath = 0x6, | ||
| 40 | DocumentKind = 0x7, | ||
| 41 | SystemDataID = 0x8, | ||
| 42 | ShareStartPage = 0x9, | ||
| 43 | Whitelist = 0xA, | ||
| 44 | News = 0xB, | ||
| 45 | UserID = 0xE, | ||
| 46 | AlbumEntry0 = 0xF, | ||
| 47 | ScreenShotEnabled = 0x10, | ||
| 48 | EcClientCertEnabled = 0x11, | ||
| 49 | Unk12 = 0x12, | ||
| 50 | PlayReportEnabled = 0x13, | ||
| 51 | Unk14 = 0x14, | ||
| 52 | Unk15 = 0x15, | ||
| 53 | BootDisplayKind = 0x17, | ||
| 54 | BackgroundKind = 0x18, | ||
| 55 | FooterEnabled = 0x19, | ||
| 56 | PointerEnabled = 0x1A, | ||
| 57 | LeftStickMode = 0x1B, | ||
| 58 | KeyRepeatFrame1 = 0x1C, | ||
| 59 | KeyRepeatFrame2 = 0x1D, | ||
| 60 | BootAsMediaPlayerInv = 0x1E, | ||
| 61 | DisplayUrlKind = 0x1F, | ||
| 62 | BootAsMediaPlayer = 0x21, | ||
| 63 | ShopJumpEnabled = 0x22, | ||
| 64 | MediaAutoPlayEnabled = 0x23, | ||
| 65 | LobbyParameter = 0x24, | ||
| 66 | ApplicationAlbumEntry = 0x26, | ||
| 67 | JsExtensionEnabled = 0x27, | ||
| 68 | AdditionalCommentText = 0x28, | ||
| 69 | TouchEnabledOnContents = 0x29, | ||
| 70 | UserAgentAdditionalString = 0x2A, | ||
| 71 | AdditionalMediaData0 = 0x2B, | ||
| 72 | MediaPlayerAutoCloseEnabled = 0x2C, | ||
| 73 | PageCacheEnabled = 0x2D, | ||
| 74 | WebAudioEnabled = 0x2E, | ||
| 75 | Unk2F = 0x2F, | ||
| 76 | YouTubeVideoWhitelist = 0x31, | ||
| 77 | FooterFixedKind = 0x32, | ||
| 78 | PageFadeEnabled = 0x33, | ||
| 79 | MediaCreatorApplicationRatingAge = 0x34, | ||
| 80 | BootLoadingIconEnabled = 0x35, | ||
| 81 | PageScrollIndicationEnabled = 0x36, | ||
| 82 | MediaPlayerSpeedControlEnabled = 0x37, | ||
| 83 | AlbumEntry1 = 0x38, | ||
| 84 | AlbumEntry2 = 0x39, | ||
| 85 | AlbumEntry3 = 0x3A, | ||
| 86 | AdditionalMediaData1 = 0x3B, | ||
| 87 | AdditionalMediaData2 = 0x3C, | ||
| 88 | AdditionalMediaData3 = 0x3D, | ||
| 89 | BootFooterButton = 0x3E, | ||
| 90 | OverrideWebAudioVolume = 0x3F, | ||
| 91 | OverrideMediaAudioVolume = 0x40, | ||
| 92 | BootMode = 0x41, | ||
| 93 | WebSessionEnabled = 0x42, | ||
| 94 | }; | ||
| 95 | |||
| 96 | enum class ShimKind : u32 { | ||
| 97 | Shop = 1, | ||
| 98 | Login = 2, | ||
| 99 | Offline = 3, | ||
| 100 | Share = 4, | ||
| 101 | Web = 5, | ||
| 102 | Wifi = 6, | ||
| 103 | Lobby = 7, | ||
| 104 | }; | ||
| 105 | |||
| 106 | enum class ShopWebTarget { | ||
| 107 | ApplicationInfo, | ||
| 108 | AddOnContentList, | ||
| 109 | SubscriptionList, | ||
| 110 | ConsumableItemList, | ||
| 111 | Home, | ||
| 112 | Settings, | ||
| 113 | }; | ||
| 114 | |||
| 115 | namespace { | 29 | namespace { |
| 116 | 30 | ||
| 117 | constexpr std::size_t SHIM_KIND_COUNT = 0x8; | 31 | template <typename T> |
| 118 | 32 | void ParseRawValue(T& value, const std::vector<u8>& data) { | |
| 119 | struct WebArgHeader { | 33 | static_assert(std::is_trivially_copyable_v<T>, |
| 120 | u16 count; | 34 | "It's undefined behavior to use memcpy with non-trivially copyable objects"); |
| 121 | INSERT_PADDING_BYTES(2); | 35 | std::memcpy(&value, data.data(), data.size()); |
| 122 | ShimKind kind; | 36 | } |
| 123 | }; | ||
| 124 | static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); | ||
| 125 | |||
| 126 | struct WebArgTLV { | ||
| 127 | WebArgTLVType type; | ||
| 128 | u16 size; | ||
| 129 | u32 offset; | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size."); | ||
| 132 | |||
| 133 | struct WebCommonReturnValue { | ||
| 134 | u32 result_code; | ||
| 135 | INSERT_PADDING_BYTES(0x4); | ||
| 136 | std::array<char, 0x1000> last_url; | ||
| 137 | u64 last_url_size; | ||
| 138 | }; | ||
| 139 | static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); | ||
| 140 | |||
| 141 | struct WebWifiPageArg { | ||
| 142 | INSERT_PADDING_BYTES(4); | ||
| 143 | std::array<char, 0x100> connection_test_url; | ||
| 144 | std::array<char, 0x400> initial_url; | ||
| 145 | std::array<u8, 0x10> nifm_network_uuid; | ||
| 146 | u32 nifm_requirement; | ||
| 147 | }; | ||
| 148 | static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size."); | ||
| 149 | |||
| 150 | struct WebWifiReturnValue { | ||
| 151 | INSERT_PADDING_BYTES(4); | ||
| 152 | u32 result; | ||
| 153 | }; | ||
| 154 | static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size."); | ||
| 155 | |||
| 156 | enum class OfflineWebSource : u32 { | ||
| 157 | OfflineHtmlPage = 0x1, | ||
| 158 | ApplicationLegalInformation = 0x2, | ||
| 159 | SystemDataPage = 0x3, | ||
| 160 | }; | ||
| 161 | |||
| 162 | std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) { | ||
| 163 | if (arg.size() < sizeof(WebArgHeader)) | ||
| 164 | return {}; | ||
| 165 | |||
| 166 | WebArgHeader header{}; | ||
| 167 | std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); | ||
| 168 | |||
| 169 | std::map<WebArgTLVType, std::vector<u8>> out; | ||
| 170 | u64 offset = sizeof(WebArgHeader); | ||
| 171 | for (std::size_t i = 0; i < header.count; ++i) { | ||
| 172 | if (arg.size() < (offset + sizeof(WebArgTLV))) | ||
| 173 | return out; | ||
| 174 | 37 | ||
| 175 | WebArgTLV tlv{}; | 38 | template <typename T> |
| 176 | std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); | 39 | T ParseRawValue(const std::vector<u8>& data) { |
| 177 | offset += sizeof(WebArgTLV); | 40 | T value; |
| 41 | ParseRawValue(value, data); | ||
| 42 | return value; | ||
| 43 | } | ||
| 178 | 44 | ||
| 179 | offset += tlv.offset; | 45 | std::string ParseStringValue(const std::vector<u8>& data) { |
| 180 | if (arg.size() < (offset + tlv.size)) | 46 | return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast<const char*>(data.data()), |
| 181 | return out; | 47 | data.size()); |
| 48 | } | ||
| 182 | 49 | ||
| 183 | std::vector<u8> data(tlv.size); | 50 | std::string GetMainURL(const std::string& url) { |
| 184 | std::memcpy(data.data(), arg.data() + offset, tlv.size); | 51 | const auto index = url.find('?'); |
| 185 | offset += tlv.size; | ||
| 186 | 52 | ||
| 187 | out.insert_or_assign(tlv.type, data); | 53 | if (index == std::string::npos) { |
| 54 | return url; | ||
| 188 | } | 55 | } |
| 189 | 56 | ||
| 190 | return out; | 57 | return url.substr(0, index); |
| 191 | } | 58 | } |
| 192 | 59 | ||
| 193 | FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id, | 60 | WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) { |
| 194 | FileSys::ContentRecordType type) { | 61 | std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader)); |
| 195 | const auto& installed{system.GetContentProvider()}; | ||
| 196 | const auto res = installed.GetEntry(title_id, type); | ||
| 197 | 62 | ||
| 198 | if (res != nullptr) { | 63 | if (web_arg.size() == sizeof(WebArgHeader)) { |
| 199 | return res->GetRomFS(); | 64 | return {}; |
| 200 | } | 65 | } |
| 201 | 66 | ||
| 202 | if (type == FileSys::ContentRecordType::Data) { | 67 | WebArgInputTLVMap input_tlv_map; |
| 203 | return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | 68 | |
| 69 | u64 current_offset = sizeof(WebArgHeader); | ||
| 70 | |||
| 71 | for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) { | ||
| 72 | if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) { | ||
| 73 | return input_tlv_map; | ||
| 74 | } | ||
| 75 | |||
| 76 | WebArgInputTLV input_tlv; | ||
| 77 | std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV)); | ||
| 78 | |||
| 79 | current_offset += sizeof(WebArgInputTLV); | ||
| 80 | |||
| 81 | if (web_arg.size() < current_offset + input_tlv.arg_data_size) { | ||
| 82 | return input_tlv_map; | ||
| 83 | } | ||
| 84 | |||
| 85 | std::vector<u8> data(input_tlv.arg_data_size); | ||
| 86 | std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size); | ||
| 87 | |||
| 88 | current_offset += input_tlv.arg_data_size; | ||
| 89 | |||
| 90 | input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data)); | ||
| 204 | } | 91 | } |
| 205 | 92 | ||
| 206 | return nullptr; | 93 | return input_tlv_map; |
| 207 | } | 94 | } |
| 208 | 95 | ||
| 209 | } // Anonymous namespace | 96 | FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id, |
| 97 | FileSys::ContentRecordType nca_type) { | ||
| 98 | if (nca_type == FileSys::ContentRecordType::Data) { | ||
| 99 | const auto nca = | ||
| 100 | system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type); | ||
| 101 | |||
| 102 | if (nca == nullptr) { | ||
| 103 | LOG_ERROR(Service_AM, | ||
| 104 | "NCA of type={} with title_id={:016X} is not found in the System NAND!", | ||
| 105 | nca_type, title_id); | ||
| 106 | return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | ||
| 107 | } | ||
| 210 | 108 | ||
| 211 | WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, | 109 | return nca->GetRomFS(); |
| 212 | Core::Frontend::ECommerceApplet* frontend_e_commerce_) | 110 | } else { |
| 213 | : Applet{system_.Kernel()}, frontend(frontend_), | 111 | const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type); |
| 214 | frontend_e_commerce(frontend_e_commerce_), system{system_} {} | ||
| 215 | 112 | ||
| 216 | WebBrowser::~WebBrowser() = default; | 113 | if (nca == nullptr) { |
| 114 | LOG_ERROR(Service_AM, | ||
| 115 | "NCA of type={} with title_id={:016X} is not found in the ContentProvider!", | ||
| 116 | nca_type, title_id); | ||
| 117 | return nullptr; | ||
| 118 | } | ||
| 217 | 119 | ||
| 218 | void WebBrowser::Initialize() { | 120 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 219 | Applet::Initialize(); | 121 | system.GetContentProvider()}; |
| 220 | 122 | ||
| 221 | complete = false; | 123 | return pm.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), nca_type); |
| 222 | temporary_dir.clear(); | 124 | } |
| 223 | filename.clear(); | 125 | } |
| 224 | status = RESULT_SUCCESS; | ||
| 225 | 126 | ||
| 226 | const auto web_arg_storage = broker.PopNormalDataToApplet(); | 127 | void ExtractSharedFonts(Core::System& system) { |
| 227 | ASSERT(web_arg_storage != nullptr); | 128 | static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{ |
| 228 | const auto& web_arg = web_arg_storage->GetData(); | 129 | "FontStandard.ttf", |
| 130 | "FontChineseSimplified.ttf", | ||
| 131 | "FontExtendedChineseSimplified.ttf", | ||
| 132 | "FontChineseTraditional.ttf", | ||
| 133 | "FontKorean.ttf", | ||
| 134 | "FontNintendoExtended.ttf", | ||
| 135 | "FontNintendoExtended2.ttf", | ||
| 136 | }; | ||
| 229 | 137 | ||
| 230 | ASSERT(web_arg.size() >= 0x8); | 138 | for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { |
| 231 | std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind)); | 139 | const auto fonts_dir = Common::FS::SanitizePath( |
| 140 | fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), | ||
| 141 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 232 | 142 | ||
| 233 | args = GetWebArguments(web_arg); | 143 | const auto font_file_path = |
| 144 | Common::FS::SanitizePath(fmt::format("{}/{}", fonts_dir, DECRYPTED_SHARED_FONTS[i]), | ||
| 145 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 234 | 146 | ||
| 235 | InitializeInternal(); | 147 | if (Common::FS::Exists(font_file_path)) { |
| 236 | } | 148 | continue; |
| 149 | } | ||
| 237 | 150 | ||
| 238 | bool WebBrowser::TransactionComplete() const { | 151 | const auto font = NS::SHARED_FONTS[i]; |
| 239 | return complete; | 152 | const auto font_title_id = static_cast<u64>(font.first); |
| 240 | } | ||
| 241 | 153 | ||
| 242 | ResultCode WebBrowser::GetStatus() const { | 154 | const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry( |
| 243 | return status; | 155 | font_title_id, FileSys::ContentRecordType::Data); |
| 244 | } | ||
| 245 | 156 | ||
| 246 | void WebBrowser::ExecuteInteractive() { | 157 | FileSys::VirtualFile romfs; |
| 247 | UNIMPLEMENTED_MSG("Unexpected interactive data recieved!"); | ||
| 248 | } | ||
| 249 | 158 | ||
| 250 | void WebBrowser::Execute() { | 159 | if (!nca) { |
| 251 | if (complete) { | 160 | romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id); |
| 252 | return; | 161 | } else { |
| 253 | } | 162 | romfs = nca->GetRomFS(); |
| 163 | } | ||
| 254 | 164 | ||
| 255 | if (status != RESULT_SUCCESS) { | 165 | if (!romfs) { |
| 256 | complete = true; | 166 | LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!", |
| 167 | font_title_id); | ||
| 168 | continue; | ||
| 169 | } | ||
| 257 | 170 | ||
| 258 | // This is a workaround in order not to softlock yuzu when an error happens during the | 171 | const auto extracted_romfs = FileSys::ExtractRomFS(romfs); |
| 259 | // webapplet init. In order to avoid an svcBreak, the status is set to RESULT_SUCCESS | ||
| 260 | Finalize(); | ||
| 261 | status = RESULT_SUCCESS; | ||
| 262 | 172 | ||
| 263 | return; | 173 | if (!extracted_romfs) { |
| 264 | } | 174 | LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!", |
| 175 | font_title_id); | ||
| 176 | continue; | ||
| 177 | } | ||
| 265 | 178 | ||
| 266 | ExecuteInternal(); | 179 | const auto font_file = extracted_romfs->GetFile(font.second); |
| 267 | } | ||
| 268 | 180 | ||
| 269 | void WebBrowser::UnpackRomFS() { | 181 | if (!font_file) { |
| 270 | if (unpacked) | 182 | LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!", |
| 271 | return; | 183 | font_title_id, font.second); |
| 184 | continue; | ||
| 185 | } | ||
| 272 | 186 | ||
| 273 | ASSERT(offline_romfs != nullptr); | 187 | std::vector<u32> font_data_u32(font_file->GetSize() / sizeof(u32)); |
| 274 | const auto dir = | 188 | font_file->ReadBytes<u32>(font_data_u32.data(), font_file->GetSize()); |
| 275 | FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); | ||
| 276 | const auto& vfs{system.GetFilesystem()}; | ||
| 277 | const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); | ||
| 278 | FileSys::VfsRawCopyD(dir, temp_dir); | ||
| 279 | 189 | ||
| 280 | unpacked = true; | 190 | std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), |
| 281 | } | 191 | Common::swap32); |
| 282 | 192 | ||
| 283 | void WebBrowser::Finalize() { | 193 | std::vector<u8> decrypted_data(font_file->GetSize() - 8); |
| 284 | complete = true; | ||
| 285 | 194 | ||
| 286 | WebCommonReturnValue out{}; | 195 | NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data); |
| 287 | out.result_code = 0; | ||
| 288 | out.last_url_size = 0; | ||
| 289 | 196 | ||
| 290 | std::vector<u8> data(sizeof(WebCommonReturnValue)); | 197 | FileSys::VirtualFile decrypted_font = std::make_shared<FileSys::VectorVfsFile>( |
| 291 | std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); | 198 | std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); |
| 292 | 199 | ||
| 293 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data))); | 200 | const auto temp_dir = |
| 294 | broker.SignalStateChanged(); | 201 | system.GetFilesystem()->CreateDirectory(fonts_dir, FileSys::Mode::ReadWrite); |
| 202 | |||
| 203 | const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); | ||
| 295 | 204 | ||
| 296 | if (!temporary_dir.empty() && Common::FS::IsDirectory(temporary_dir)) { | 205 | FileSys::VfsRawCopy(decrypted_font, out_file); |
| 297 | Common::FS::DeleteDirRecursively(temporary_dir); | ||
| 298 | } | 206 | } |
| 299 | } | 207 | } |
| 300 | 208 | ||
| 301 | void WebBrowser::InitializeInternal() { | 209 | } // namespace |
| 302 | using WebAppletInitializer = void (WebBrowser::*)(); | ||
| 303 | 210 | ||
| 304 | constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{ | 211 | WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) |
| 305 | nullptr, &WebBrowser::InitializeShop, | 212 | : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} |
| 306 | nullptr, &WebBrowser::InitializeOffline, | ||
| 307 | nullptr, nullptr, | ||
| 308 | nullptr, nullptr, | ||
| 309 | }; | ||
| 310 | 213 | ||
| 311 | const auto index = static_cast<u32>(kind); | 214 | WebBrowser::~WebBrowser() = default; |
| 312 | 215 | ||
| 313 | if (index > functions.size() || functions[index] == nullptr) { | 216 | void WebBrowser::Initialize() { |
| 314 | LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); | 217 | Applet::Initialize(); |
| 315 | return; | ||
| 316 | } | ||
| 317 | 218 | ||
| 318 | const auto function = functions[index]; | 219 | LOG_INFO(Service_AM, "Initializing Web Browser Applet."); |
| 319 | (this->*function)(); | ||
| 320 | } | ||
| 321 | 220 | ||
| 322 | void WebBrowser::ExecuteInternal() { | 221 | LOG_DEBUG(Service_AM, |
| 323 | using WebAppletExecutor = void (WebBrowser::*)(); | 222 | "Initializing Applet with common_args: arg_version={}, lib_version={}, " |
| 223 | "play_startup_sound={}, size={}, system_tick={}, theme_color={}", | ||
| 224 | common_args.arguments_version, common_args.library_version, | ||
| 225 | common_args.play_startup_sound, common_args.size, common_args.system_tick, | ||
| 226 | common_args.theme_color); | ||
| 324 | 227 | ||
| 325 | constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{ | 228 | web_applet_version = WebAppletVersion{common_args.library_version}; |
| 326 | nullptr, &WebBrowser::ExecuteShop, | ||
| 327 | nullptr, &WebBrowser::ExecuteOffline, | ||
| 328 | nullptr, nullptr, | ||
| 329 | nullptr, nullptr, | ||
| 330 | }; | ||
| 331 | 229 | ||
| 332 | const auto index = static_cast<u32>(kind); | 230 | const auto web_arg_storage = broker.PopNormalDataToApplet(); |
| 231 | ASSERT(web_arg_storage != nullptr); | ||
| 333 | 232 | ||
| 334 | if (index > functions.size() || functions[index] == nullptr) { | 233 | const auto& web_arg = web_arg_storage->GetData(); |
| 335 | LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); | 234 | ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; }); |
| 336 | return; | ||
| 337 | } | ||
| 338 | 235 | ||
| 339 | const auto function = functions[index]; | 236 | web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header); |
| 340 | (this->*function)(); | ||
| 341 | } | ||
| 342 | 237 | ||
| 343 | void WebBrowser::InitializeShop() { | 238 | LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}", |
| 344 | if (frontend_e_commerce == nullptr) { | 239 | web_arg_header.total_tlv_entries, web_arg_header.shim_kind); |
| 345 | LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!"); | ||
| 346 | status = RESULT_UNKNOWN; | ||
| 347 | return; | ||
| 348 | } | ||
| 349 | 240 | ||
| 350 | const auto user_id_data = args.find(WebArgTLVType::UserID); | 241 | ExtractSharedFonts(system); |
| 351 | 242 | ||
| 352 | user_id = std::nullopt; | 243 | switch (web_arg_header.shim_kind) { |
| 353 | if (user_id_data != args.end()) { | 244 | case ShimKind::Shop: |
| 354 | user_id = u128{}; | 245 | InitializeShop(); |
| 355 | std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128)); | 246 | break; |
| 247 | case ShimKind::Login: | ||
| 248 | InitializeLogin(); | ||
| 249 | break; | ||
| 250 | case ShimKind::Offline: | ||
| 251 | InitializeOffline(); | ||
| 252 | break; | ||
| 253 | case ShimKind::Share: | ||
| 254 | InitializeShare(); | ||
| 255 | break; | ||
| 256 | case ShimKind::Web: | ||
| 257 | InitializeWeb(); | ||
| 258 | break; | ||
| 259 | case ShimKind::Wifi: | ||
| 260 | InitializeWifi(); | ||
| 261 | break; | ||
| 262 | case ShimKind::Lobby: | ||
| 263 | InitializeLobby(); | ||
| 264 | break; | ||
| 265 | default: | ||
| 266 | UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind); | ||
| 267 | break; | ||
| 356 | } | 268 | } |
| 269 | } | ||
| 357 | 270 | ||
| 358 | const auto url = args.find(WebArgTLVType::ShopArgumentsURL); | 271 | bool WebBrowser::TransactionComplete() const { |
| 272 | return complete; | ||
| 273 | } | ||
| 359 | 274 | ||
| 360 | if (url == args.end()) { | 275 | ResultCode WebBrowser::GetStatus() const { |
| 361 | LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); | 276 | return status; |
| 362 | status = RESULT_UNKNOWN; | 277 | } |
| 363 | return; | ||
| 364 | } | ||
| 365 | 278 | ||
| 366 | std::vector<std::string> split_query; | 279 | void WebBrowser::ExecuteInteractive() { |
| 367 | Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer( | 280 | UNIMPLEMENTED_MSG("WebSession is not implemented"); |
| 368 | reinterpret_cast<const char*>(url->second.data()), url->second.size()), | 281 | } |
| 369 | '?', split_query); | ||
| 370 | |||
| 371 | // 2 -> Main URL '?' Query Parameters | ||
| 372 | // Less is missing info, More is malformed | ||
| 373 | if (split_query.size() != 2) { | ||
| 374 | LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed"); | ||
| 375 | status = RESULT_UNKNOWN; | ||
| 376 | return; | ||
| 377 | } | ||
| 378 | 282 | ||
| 379 | std::vector<std::string> queries; | 283 | void WebBrowser::Execute() { |
| 380 | Common::SplitString(split_query[1], '&', queries); | 284 | switch (web_arg_header.shim_kind) { |
| 285 | case ShimKind::Shop: | ||
| 286 | ExecuteShop(); | ||
| 287 | break; | ||
| 288 | case ShimKind::Login: | ||
| 289 | ExecuteLogin(); | ||
| 290 | break; | ||
| 291 | case ShimKind::Offline: | ||
| 292 | ExecuteOffline(); | ||
| 293 | break; | ||
| 294 | case ShimKind::Share: | ||
| 295 | ExecuteShare(); | ||
| 296 | break; | ||
| 297 | case ShimKind::Web: | ||
| 298 | ExecuteWeb(); | ||
| 299 | break; | ||
| 300 | case ShimKind::Wifi: | ||
| 301 | ExecuteWifi(); | ||
| 302 | break; | ||
| 303 | case ShimKind::Lobby: | ||
| 304 | ExecuteLobby(); | ||
| 305 | break; | ||
| 306 | default: | ||
| 307 | UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind); | ||
| 308 | WebBrowserExit(WebExitReason::EndButtonPressed); | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | } | ||
| 381 | 312 | ||
| 382 | const auto split_single_query = | 313 | void WebBrowser::ExtractOfflineRomFS() { |
| 383 | [](const std::string& in) -> std::pair<std::string, std::string> { | 314 | LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir); |
| 384 | const auto index = in.find('='); | ||
| 385 | if (index == std::string::npos || index == in.size() - 1) { | ||
| 386 | return {in, ""}; | ||
| 387 | } | ||
| 388 | 315 | ||
| 389 | return {in.substr(0, index), in.substr(index + 1)}; | 316 | const auto extracted_romfs_dir = |
| 390 | }; | 317 | FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); |
| 391 | 318 | ||
| 392 | std::transform(queries.begin(), queries.end(), | 319 | const auto temp_dir = |
| 393 | std::inserter(shop_query, std::next(shop_query.begin())), split_single_query); | 320 | system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite); |
| 394 | 321 | ||
| 395 | const auto scene = shop_query.find("scene"); | 322 | FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); |
| 323 | } | ||
| 396 | 324 | ||
| 397 | if (scene == shop_query.end()) { | 325 | void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) { |
| 398 | LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); | 326 | if ((web_arg_header.shim_kind == ShimKind::Share && |
| 399 | status = RESULT_UNKNOWN; | 327 | web_applet_version >= WebAppletVersion::Version196608) || |
| 400 | return; | 328 | (web_arg_header.shim_kind == ShimKind::Web && |
| 329 | web_applet_version >= WebAppletVersion::Version524288)) { | ||
| 330 | // TODO: Push Output TLVs instead of a WebCommonReturnValue | ||
| 401 | } | 331 | } |
| 402 | 332 | ||
| 403 | const std::map<std::string, ShopWebTarget, std::less<>> target_map{ | 333 | WebCommonReturnValue web_common_return_value; |
| 404 | {"product_detail", ShopWebTarget::ApplicationInfo}, | ||
| 405 | {"aocs", ShopWebTarget::AddOnContentList}, | ||
| 406 | {"subscriptions", ShopWebTarget::SubscriptionList}, | ||
| 407 | {"consumption", ShopWebTarget::ConsumableItemList}, | ||
| 408 | {"settings", ShopWebTarget::Settings}, | ||
| 409 | {"top", ShopWebTarget::Home}, | ||
| 410 | }; | ||
| 411 | 334 | ||
| 412 | const auto target = target_map.find(scene->second); | 335 | web_common_return_value.exit_reason = exit_reason; |
| 413 | if (target == target_map.end()) { | 336 | std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size()); |
| 414 | LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); | 337 | web_common_return_value.last_url_size = last_url.size(); |
| 415 | status = RESULT_UNKNOWN; | ||
| 416 | return; | ||
| 417 | } | ||
| 418 | 338 | ||
| 419 | shop_web_target = target->second; | 339 | LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}", |
| 340 | exit_reason, last_url, last_url.size()); | ||
| 420 | 341 | ||
| 421 | const auto title_id_data = shop_query.find("dst_app_id"); | 342 | complete = true; |
| 422 | if (title_id_data != shop_query.end()) { | 343 | std::vector<u8> out_data(sizeof(WebCommonReturnValue)); |
| 423 | title_id = std::stoull(title_id_data->second, nullptr, 0x10); | 344 | std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); |
| 424 | } | 345 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); |
| 346 | broker.SignalStateChanged(); | ||
| 347 | } | ||
| 425 | 348 | ||
| 426 | const auto mode_data = shop_query.find("mode"); | 349 | bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const { |
| 427 | if (mode_data != shop_query.end()) { | 350 | return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end(); |
| 428 | shop_full_display = mode_data->second == "full"; | ||
| 429 | } | ||
| 430 | } | 351 | } |
| 431 | 352 | ||
| 432 | void WebBrowser::InitializeOffline() { | 353 | std::optional<std::vector<u8>> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) { |
| 433 | if (args.find(WebArgTLVType::DocumentPath) == args.end() || | 354 | const auto map_it = web_arg_input_tlv_map.find(input_tlv_type); |
| 434 | args.find(WebArgTLVType::DocumentKind) == args.end() || | 355 | |
| 435 | args.find(WebArgTLVType::ApplicationID) == args.end()) { | 356 | if (map_it == web_arg_input_tlv_map.end()) { |
| 436 | status = RESULT_UNKNOWN; | 357 | return std::nullopt; |
| 437 | LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!"); | ||
| 438 | } | 358 | } |
| 439 | 359 | ||
| 440 | const auto url_data = args[WebArgTLVType::DocumentPath]; | 360 | return map_it->second; |
| 441 | filename = Common::StringFromFixedZeroTerminatedBuffer( | 361 | } |
| 442 | reinterpret_cast<const char*>(url_data.data()), url_data.size()); | ||
| 443 | 362 | ||
| 444 | OfflineWebSource source; | 363 | void WebBrowser::InitializeShop() {} |
| 445 | ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4); | ||
| 446 | std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource)); | ||
| 447 | 364 | ||
| 448 | constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{ | 365 | void WebBrowser::InitializeLogin() {} |
| 449 | "manual", | 366 | |
| 450 | "legal", | 367 | void WebBrowser::InitializeOffline() { |
| 451 | "system", | 368 | const auto document_path = |
| 452 | }; | 369 | ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value()); |
| 370 | |||
| 371 | const auto document_kind = | ||
| 372 | ParseRawValue<DocumentKind>(GetInputTLVData(WebArgInputTLVType::DocumentKind).value()); | ||
| 373 | |||
| 374 | std::string additional_paths; | ||
| 453 | 375 | ||
| 454 | temporary_dir = | 376 | switch (document_kind) { |
| 455 | Common::FS::SanitizePath(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) + | 377 | case DocumentKind::OfflineHtmlPage: |
| 456 | "web_applet_" + WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], | 378 | default: |
| 457 | Common::FS::DirectorySeparator::PlatformDefault); | 379 | title_id = system.CurrentProcess()->GetTitleID(); |
| 458 | Common::FS::DeleteDirRecursively(temporary_dir); | 380 | nca_type = FileSys::ContentRecordType::HtmlDocument; |
| 459 | 381 | additional_paths = "html-document"; | |
| 460 | u64 title_id = 0; // 0 corresponds to current process | ||
| 461 | ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8); | ||
| 462 | std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64)); | ||
| 463 | FileSys::ContentRecordType type = FileSys::ContentRecordType::Data; | ||
| 464 | |||
| 465 | switch (source) { | ||
| 466 | case OfflineWebSource::OfflineHtmlPage: | ||
| 467 | // While there is an AppID TLV field, in official SW this is always ignored. | ||
| 468 | title_id = 0; | ||
| 469 | type = FileSys::ContentRecordType::HtmlDocument; | ||
| 470 | break; | 382 | break; |
| 471 | case OfflineWebSource::ApplicationLegalInformation: | 383 | case DocumentKind::ApplicationLegalInformation: |
| 472 | type = FileSys::ContentRecordType::LegalInformation; | 384 | title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::ApplicationID).value()); |
| 385 | nca_type = FileSys::ContentRecordType::LegalInformation; | ||
| 473 | break; | 386 | break; |
| 474 | case OfflineWebSource::SystemDataPage: | 387 | case DocumentKind::SystemDataPage: |
| 475 | type = FileSys::ContentRecordType::Data; | 388 | title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::SystemDataID).value()); |
| 389 | nca_type = FileSys::ContentRecordType::Data; | ||
| 476 | break; | 390 | break; |
| 477 | } | 391 | } |
| 478 | 392 | ||
| 479 | if (title_id == 0) { | 393 | static constexpr std::array<const char*, 3> RESOURCE_TYPES{ |
| 480 | title_id = system.CurrentProcess()->GetTitleID(); | 394 | "manual", |
| 481 | } | 395 | "legal_information", |
| 396 | "system_data", | ||
| 397 | }; | ||
| 482 | 398 | ||
| 483 | offline_romfs = GetApplicationRomFS(system, title_id, type); | 399 | offline_cache_dir = Common::FS::SanitizePath( |
| 484 | if (offline_romfs == nullptr) { | 400 | fmt::format("{}/offline_web_applet_{}/{:016X}", |
| 485 | status = RESULT_UNKNOWN; | 401 | Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), |
| 486 | LOG_ERROR(Service_AM, "Failed to find offline data for request!"); | 402 | RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id), |
| 487 | } | 403 | Common::FS::DirectorySeparator::PlatformDefault); |
| 488 | 404 | ||
| 489 | std::string path_additional_directory; | 405 | offline_document = Common::FS::SanitizePath( |
| 490 | if (source == OfflineWebSource::OfflineHtmlPage) { | 406 | fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path), |
| 491 | path_additional_directory = std::string(DIR_SEP).append("html-document"); | 407 | Common::FS::DirectorySeparator::PlatformDefault); |
| 492 | } | 408 | } |
| 409 | |||
| 410 | void WebBrowser::InitializeShare() {} | ||
| 493 | 411 | ||
| 494 | filename = | 412 | void WebBrowser::InitializeWeb() { |
| 495 | Common::FS::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, | 413 | external_url = ParseStringValue(GetInputTLVData(WebArgInputTLVType::InitialURL).value()); |
| 496 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 497 | } | 414 | } |
| 498 | 415 | ||
| 416 | void WebBrowser::InitializeWifi() {} | ||
| 417 | |||
| 418 | void WebBrowser::InitializeLobby() {} | ||
| 419 | |||
| 499 | void WebBrowser::ExecuteShop() { | 420 | void WebBrowser::ExecuteShop() { |
| 500 | const auto callback = [this]() { Finalize(); }; | 421 | LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented"); |
| 422 | WebBrowserExit(WebExitReason::EndButtonPressed); | ||
| 423 | } | ||
| 501 | 424 | ||
| 502 | const auto check_optional_parameter = [this](const auto& p) { | 425 | void WebBrowser::ExecuteLogin() { |
| 503 | if (!p.has_value()) { | 426 | LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented"); |
| 504 | LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); | 427 | WebBrowserExit(WebExitReason::EndButtonPressed); |
| 505 | status = RESULT_UNKNOWN; | 428 | } |
| 506 | return false; | ||
| 507 | } | ||
| 508 | 429 | ||
| 509 | return true; | 430 | void WebBrowser::ExecuteOffline() { |
| 510 | }; | 431 | const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document), |
| 432 | Common::FS::DirectorySeparator::PlatformDefault); | ||
| 511 | 433 | ||
| 512 | switch (shop_web_target) { | 434 | if (!Common::FS::Exists(main_url)) { |
| 513 | case ShopWebTarget::ApplicationInfo: | 435 | offline_romfs = GetOfflineRomFS(system, title_id, nca_type); |
| 514 | if (!check_optional_parameter(title_id)) | 436 | |
| 515 | return; | 437 | if (offline_romfs == nullptr) { |
| 516 | frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id, | 438 | LOG_ERROR(Service_AM, |
| 517 | shop_full_display, shop_extra_parameter); | 439 | "RomFS with title_id={:016X} and nca_type={} cannot be extracted!", title_id, |
| 518 | break; | 440 | nca_type); |
| 519 | case ShopWebTarget::AddOnContentList: | 441 | WebBrowserExit(WebExitReason::WindowClosed); |
| 520 | if (!check_optional_parameter(title_id)) | ||
| 521 | return; | ||
| 522 | frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display); | ||
| 523 | break; | ||
| 524 | case ShopWebTarget::ConsumableItemList: | ||
| 525 | if (!check_optional_parameter(title_id)) | ||
| 526 | return; | ||
| 527 | frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id); | ||
| 528 | break; | ||
| 529 | case ShopWebTarget::Home: | ||
| 530 | if (!check_optional_parameter(user_id)) | ||
| 531 | return; | ||
| 532 | if (!check_optional_parameter(shop_full_display)) | ||
| 533 | return; | ||
| 534 | frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display); | ||
| 535 | break; | ||
| 536 | case ShopWebTarget::Settings: | ||
| 537 | if (!check_optional_parameter(user_id)) | ||
| 538 | return; | ||
| 539 | if (!check_optional_parameter(shop_full_display)) | ||
| 540 | return; | ||
| 541 | frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display); | ||
| 542 | break; | ||
| 543 | case ShopWebTarget::SubscriptionList: | ||
| 544 | if (!check_optional_parameter(title_id)) | ||
| 545 | return; | 442 | return; |
| 546 | frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id); | 443 | } |
| 547 | break; | ||
| 548 | default: | ||
| 549 | UNREACHABLE(); | ||
| 550 | } | 444 | } |
| 445 | |||
| 446 | LOG_INFO(Service_AM, "Opening offline document at {}", offline_document); | ||
| 447 | |||
| 448 | frontend.OpenLocalWebPage( | ||
| 449 | offline_document, [this] { ExtractOfflineRomFS(); }, | ||
| 450 | [this](WebExitReason exit_reason, std::string last_url) { | ||
| 451 | WebBrowserExit(exit_reason, last_url); | ||
| 452 | }); | ||
| 551 | } | 453 | } |
| 552 | 454 | ||
| 553 | void WebBrowser::ExecuteOffline() { | 455 | void WebBrowser::ExecuteShare() { |
| 554 | frontend.OpenPageLocal( | 456 | LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented"); |
| 555 | filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); | 457 | WebBrowserExit(WebExitReason::EndButtonPressed); |
| 458 | } | ||
| 459 | |||
| 460 | void WebBrowser::ExecuteWeb() { | ||
| 461 | LOG_INFO(Service_AM, "Opening external URL at {}", external_url); | ||
| 462 | |||
| 463 | frontend.OpenExternalWebPage(external_url, | ||
| 464 | [this](WebExitReason exit_reason, std::string last_url) { | ||
| 465 | WebBrowserExit(exit_reason, last_url); | ||
| 466 | }); | ||
| 556 | } | 467 | } |
| 557 | 468 | ||
| 469 | void WebBrowser::ExecuteWifi() { | ||
| 470 | LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented"); | ||
| 471 | WebBrowserExit(WebExitReason::EndButtonPressed); | ||
| 472 | } | ||
| 473 | |||
| 474 | void WebBrowser::ExecuteLobby() { | ||
| 475 | LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); | ||
| 476 | WebBrowserExit(WebExitReason::EndButtonPressed); | ||
| 477 | } | ||
| 558 | } // namespace Service::AM::Applets | 478 | } // namespace Service::AM::Applets |
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 8d4027411..04c274754 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h | |||
| @@ -1,28 +1,31 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2020 yuzu Emulator Project |
| 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 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <map> | 7 | #include <optional> |
| 8 | |||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | 11 | #include "core/file_sys/vfs_types.h" |
| 9 | #include "core/hle/service/am/am.h" | 12 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/am/applets/applets.h" | 13 | #include "core/hle/service/am/applets/applets.h" |
| 14 | #include "core/hle/service/am/applets/web_types.h" | ||
| 11 | 15 | ||
| 12 | namespace Core { | 16 | namespace Core { |
| 13 | class System; | 17 | class System; |
| 14 | } | 18 | } |
| 15 | 19 | ||
| 16 | namespace Service::AM::Applets { | 20 | namespace FileSys { |
| 21 | enum class ContentRecordType : u8; | ||
| 22 | } | ||
| 17 | 23 | ||
| 18 | enum class ShimKind : u32; | 24 | namespace Service::AM::Applets { |
| 19 | enum class ShopWebTarget; | ||
| 20 | enum class WebArgTLVType : u16; | ||
| 21 | 25 | ||
| 22 | class WebBrowser final : public Applet { | 26 | class WebBrowser final : public Applet { |
| 23 | public: | 27 | public: |
| 24 | WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, | 28 | WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_); |
| 25 | Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr); | ||
| 26 | 29 | ||
| 27 | ~WebBrowser() override; | 30 | ~WebBrowser() override; |
| 28 | 31 | ||
| @@ -33,49 +36,50 @@ public: | |||
| 33 | void ExecuteInteractive() override; | 36 | void ExecuteInteractive() override; |
| 34 | void Execute() override; | 37 | void Execute() override; |
| 35 | 38 | ||
| 36 | // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary | 39 | void ExtractOfflineRomFS(); |
| 37 | // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in | ||
| 38 | // size. Attempting to access files at filename before invocation is likely to not work. | ||
| 39 | void UnpackRomFS(); | ||
| 40 | 40 | ||
| 41 | // Callback to be fired when the frontend is finished browsing. This will delete the temporary | 41 | void WebBrowserExit(WebExitReason exit_reason, std::string last_url = ""); |
| 42 | // manual RomFS extracted files, so ensure this is only called at actual finalization. | ||
| 43 | void Finalize(); | ||
| 44 | 42 | ||
| 45 | private: | 43 | private: |
| 46 | void InitializeInternal(); | 44 | bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const; |
| 47 | void ExecuteInternal(); | ||
| 48 | 45 | ||
| 49 | // Specific initializers for the types of web applets | 46 | std::optional<std::vector<u8>> GetInputTLVData(WebArgInputTLVType input_tlv_type); |
| 47 | |||
| 48 | // Initializers for the various types of browser applets | ||
| 50 | void InitializeShop(); | 49 | void InitializeShop(); |
| 50 | void InitializeLogin(); | ||
| 51 | void InitializeOffline(); | 51 | void InitializeOffline(); |
| 52 | void InitializeShare(); | ||
| 53 | void InitializeWeb(); | ||
| 54 | void InitializeWifi(); | ||
| 55 | void InitializeLobby(); | ||
| 52 | 56 | ||
| 53 | // Specific executors for the types of web applets | 57 | // Executors for the various types of browser applets |
| 54 | void ExecuteShop(); | 58 | void ExecuteShop(); |
| 59 | void ExecuteLogin(); | ||
| 55 | void ExecuteOffline(); | 60 | void ExecuteOffline(); |
| 61 | void ExecuteShare(); | ||
| 62 | void ExecuteWeb(); | ||
| 63 | void ExecuteWifi(); | ||
| 64 | void ExecuteLobby(); | ||
| 56 | 65 | ||
| 57 | Core::Frontend::WebBrowserApplet& frontend; | 66 | const Core::Frontend::WebBrowserApplet& frontend; |
| 58 | |||
| 59 | // Extra frontends for specialized functions | ||
| 60 | Core::Frontend::ECommerceApplet* frontend_e_commerce; | ||
| 61 | 67 | ||
| 62 | bool complete = false; | 68 | bool complete{false}; |
| 63 | bool unpacked = false; | 69 | ResultCode status{RESULT_SUCCESS}; |
| 64 | ResultCode status = RESULT_SUCCESS; | ||
| 65 | 70 | ||
| 66 | ShimKind kind; | 71 | WebAppletVersion web_applet_version; |
| 67 | std::map<WebArgTLVType, std::vector<u8>> args; | 72 | WebExitReason web_exit_reason; |
| 73 | WebArgHeader web_arg_header; | ||
| 74 | WebArgInputTLVMap web_arg_input_tlv_map; | ||
| 68 | 75 | ||
| 76 | u64 title_id; | ||
| 77 | FileSys::ContentRecordType nca_type; | ||
| 78 | std::string offline_cache_dir; | ||
| 79 | std::string offline_document; | ||
| 69 | FileSys::VirtualFile offline_romfs; | 80 | FileSys::VirtualFile offline_romfs; |
| 70 | std::string temporary_dir; | 81 | |
| 71 | std::string filename; | 82 | std::string external_url; |
| 72 | |||
| 73 | ShopWebTarget shop_web_target; | ||
| 74 | std::map<std::string, std::string, std::less<>> shop_query; | ||
| 75 | std::optional<u64> title_id = 0; | ||
| 76 | std::optional<u128> user_id; | ||
| 77 | std::optional<bool> shop_full_display; | ||
| 78 | std::string shop_extra_parameter; | ||
| 79 | 83 | ||
| 80 | Core::System& system; | 84 | Core::System& system; |
| 81 | }; | 85 | }; |
diff --git a/src/core/hle/service/am/applets/web_types.h b/src/core/hle/service/am/applets/web_types.h new file mode 100644 index 000000000..419c2bf79 --- /dev/null +++ b/src/core/hle/service/am/applets/web_types.h | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <unordered_map> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_funcs.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/swap.h" | ||
| 14 | |||
| 15 | namespace Service::AM::Applets { | ||
| 16 | |||
| 17 | enum class WebAppletVersion : u32_le { | ||
| 18 | Version0 = 0x0, // Only used by WifiWebAuthApplet | ||
| 19 | Version131072 = 0x20000, // 1.0.0 - 2.3.0 | ||
| 20 | Version196608 = 0x30000, // 3.0.0 - 4.1.0 | ||
| 21 | Version327680 = 0x50000, // 5.0.0 - 5.1.0 | ||
| 22 | Version393216 = 0x60000, // 6.0.0 - 7.0.1 | ||
| 23 | Version524288 = 0x80000, // 8.0.0+ | ||
| 24 | }; | ||
| 25 | |||
| 26 | enum class ShimKind : u32 { | ||
| 27 | Shop = 1, | ||
| 28 | Login = 2, | ||
| 29 | Offline = 3, | ||
| 30 | Share = 4, | ||
| 31 | Web = 5, | ||
| 32 | Wifi = 6, | ||
| 33 | Lobby = 7, | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum class WebExitReason : u32 { | ||
| 37 | EndButtonPressed = 0, | ||
| 38 | BackButtonPressed = 1, | ||
| 39 | ExitRequested = 2, | ||
| 40 | CallbackURL = 3, | ||
| 41 | WindowClosed = 4, | ||
| 42 | ErrorDialog = 7, | ||
| 43 | }; | ||
| 44 | |||
| 45 | enum class WebArgInputTLVType : u16 { | ||
| 46 | InitialURL = 0x1, | ||
| 47 | CallbackURL = 0x3, | ||
| 48 | CallbackableURL = 0x4, | ||
| 49 | ApplicationID = 0x5, | ||
| 50 | DocumentPath = 0x6, | ||
| 51 | DocumentKind = 0x7, | ||
| 52 | SystemDataID = 0x8, | ||
| 53 | ShareStartPage = 0x9, | ||
| 54 | Whitelist = 0xA, | ||
| 55 | News = 0xB, | ||
| 56 | UserID = 0xE, | ||
| 57 | AlbumEntry0 = 0xF, | ||
| 58 | ScreenShotEnabled = 0x10, | ||
| 59 | EcClientCertEnabled = 0x11, | ||
| 60 | PlayReportEnabled = 0x13, | ||
| 61 | BootDisplayKind = 0x17, | ||
| 62 | BackgroundKind = 0x18, | ||
| 63 | FooterEnabled = 0x19, | ||
| 64 | PointerEnabled = 0x1A, | ||
| 65 | LeftStickMode = 0x1B, | ||
| 66 | KeyRepeatFrame1 = 0x1C, | ||
| 67 | KeyRepeatFrame2 = 0x1D, | ||
| 68 | BootAsMediaPlayerInverted = 0x1E, | ||
| 69 | DisplayURLKind = 0x1F, | ||
| 70 | BootAsMediaPlayer = 0x21, | ||
| 71 | ShopJumpEnabled = 0x22, | ||
| 72 | MediaAutoPlayEnabled = 0x23, | ||
| 73 | LobbyParameter = 0x24, | ||
| 74 | ApplicationAlbumEntry = 0x26, | ||
| 75 | JsExtensionEnabled = 0x27, | ||
| 76 | AdditionalCommentText = 0x28, | ||
| 77 | TouchEnabledOnContents = 0x29, | ||
| 78 | UserAgentAdditionalString = 0x2A, | ||
| 79 | AdditionalMediaData0 = 0x2B, | ||
| 80 | MediaPlayerAutoCloseEnabled = 0x2C, | ||
| 81 | PageCacheEnabled = 0x2D, | ||
| 82 | WebAudioEnabled = 0x2E, | ||
| 83 | YouTubeVideoWhitelist = 0x31, | ||
| 84 | FooterFixedKind = 0x32, | ||
| 85 | PageFadeEnabled = 0x33, | ||
| 86 | MediaCreatorApplicationRatingAge = 0x34, | ||
| 87 | BootLoadingIconEnabled = 0x35, | ||
| 88 | PageScrollIndicatorEnabled = 0x36, | ||
| 89 | MediaPlayerSpeedControlEnabled = 0x37, | ||
| 90 | AlbumEntry1 = 0x38, | ||
| 91 | AlbumEntry2 = 0x39, | ||
| 92 | AlbumEntry3 = 0x3A, | ||
| 93 | AdditionalMediaData1 = 0x3B, | ||
| 94 | AdditionalMediaData2 = 0x3C, | ||
| 95 | AdditionalMediaData3 = 0x3D, | ||
| 96 | BootFooterButton = 0x3E, | ||
| 97 | OverrideWebAudioVolume = 0x3F, | ||
| 98 | OverrideMediaAudioVolume = 0x40, | ||
| 99 | BootMode = 0x41, | ||
| 100 | WebSessionEnabled = 0x42, | ||
| 101 | MediaPlayerOfflineEnabled = 0x43, | ||
| 102 | }; | ||
| 103 | |||
| 104 | enum class WebArgOutputTLVType : u16 { | ||
| 105 | ShareExitReason = 0x1, | ||
| 106 | LastURL = 0x2, | ||
| 107 | LastURLSize = 0x3, | ||
| 108 | SharePostResult = 0x4, | ||
| 109 | PostServiceName = 0x5, | ||
| 110 | PostServiceNameSize = 0x6, | ||
| 111 | PostID = 0x7, | ||
| 112 | PostIDSize = 0x8, | ||
| 113 | MediaPlayerAutoClosedByCompletion = 0x9, | ||
| 114 | }; | ||
| 115 | |||
| 116 | enum class DocumentKind : u32 { | ||
| 117 | OfflineHtmlPage = 1, | ||
| 118 | ApplicationLegalInformation = 2, | ||
| 119 | SystemDataPage = 3, | ||
| 120 | }; | ||
| 121 | |||
| 122 | enum class ShareStartPage : u32 { | ||
| 123 | Default, | ||
| 124 | Settings, | ||
| 125 | }; | ||
| 126 | |||
| 127 | enum class BootDisplayKind : u32 { | ||
| 128 | Default, | ||
| 129 | White, | ||
| 130 | Black, | ||
| 131 | }; | ||
| 132 | |||
| 133 | enum class BackgroundKind : u32 { | ||
| 134 | Default, | ||
| 135 | }; | ||
| 136 | |||
| 137 | enum class LeftStickMode : u32 { | ||
| 138 | Pointer, | ||
| 139 | Cursor, | ||
| 140 | }; | ||
| 141 | |||
| 142 | enum class WebSessionBootMode : u32 { | ||
| 143 | AllForeground, | ||
| 144 | AllForegroundInitiallyHidden, | ||
| 145 | }; | ||
| 146 | |||
| 147 | struct WebArgHeader { | ||
| 148 | u16 total_tlv_entries{}; | ||
| 149 | INSERT_PADDING_BYTES(2); | ||
| 150 | ShimKind shim_kind{}; | ||
| 151 | }; | ||
| 152 | static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); | ||
| 153 | |||
| 154 | struct WebArgInputTLV { | ||
| 155 | WebArgInputTLVType input_tlv_type{}; | ||
| 156 | u16 arg_data_size{}; | ||
| 157 | INSERT_PADDING_WORDS(1); | ||
| 158 | }; | ||
| 159 | static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size."); | ||
| 160 | |||
| 161 | struct WebArgOutputTLV { | ||
| 162 | WebArgOutputTLVType output_tlv_type{}; | ||
| 163 | u16 arg_data_size{}; | ||
| 164 | INSERT_PADDING_WORDS(1); | ||
| 165 | }; | ||
| 166 | static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size."); | ||
| 167 | |||
| 168 | struct WebCommonReturnValue { | ||
| 169 | WebExitReason exit_reason{}; | ||
| 170 | INSERT_PADDING_WORDS(1); | ||
| 171 | std::array<char, 0x1000> last_url{}; | ||
| 172 | u64 last_url_size{}; | ||
| 173 | }; | ||
| 174 | static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); | ||
| 175 | |||
| 176 | using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>; | ||
| 177 | |||
| 178 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp index d256d57c8..6196773d5 100644 --- a/src/core/hle/service/am/idle.cpp +++ b/src/core/hle/service/am/idle.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::AM { | 7 | namespace Service::AM { |
| 8 | 8 | ||
| 9 | IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { | 9 | IdleSys::IdleSys(Core::System& system_) : ServiceFramework{system_, "idle:sys"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetAutoPowerDownEvent"}, | 12 | {0, nullptr, "GetAutoPowerDownEvent"}, |
diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h index c44e856b1..e290c30b1 100644 --- a/src/core/hle/service/am/idle.h +++ b/src/core/hle/service/am/idle.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::AM { | 13 | namespace Service::AM { |
| 10 | 14 | ||
| 11 | class IdleSys final : public ServiceFramework<IdleSys> { | 15 | class IdleSys final : public ServiceFramework<IdleSys> { |
| 12 | public: | 16 | public: |
| 13 | explicit IdleSys(); | 17 | explicit IdleSys(Core::System& system_); |
| 14 | ~IdleSys() override; | 18 | ~IdleSys() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 37389ccda..55de67e1d 100644 --- a/src/core/hle/service/am/omm.cpp +++ b/src/core/hle/service/am/omm.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::AM { | 7 | namespace Service::AM { |
| 8 | 8 | ||
| 9 | OMM::OMM() : ServiceFramework{"omm"} { | 9 | OMM::OMM(Core::System& system_) : ServiceFramework{system_, "omm"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetOperationMode"}, | 12 | {0, nullptr, "GetOperationMode"}, |
diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h index 59dc91b72..3766150fe 100644 --- a/src/core/hle/service/am/omm.h +++ b/src/core/hle/service/am/omm.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::AM { | 13 | namespace Service::AM { |
| 10 | 14 | ||
| 11 | class OMM final : public ServiceFramework<OMM> { | 15 | class OMM final : public ServiceFramework<OMM> { |
| 12 | public: | 16 | public: |
| 13 | explicit OMM(); | 17 | explicit OMM(Core::System& system_); |
| 14 | ~OMM() override; | 18 | ~OMM() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp index f27729ce7..95218d9ee 100644 --- a/src/core/hle/service/am/spsm.cpp +++ b/src/core/hle/service/am/spsm.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::AM { | 7 | namespace Service::AM { |
| 8 | 8 | ||
| 9 | SPSM::SPSM() : ServiceFramework{"spsm"} { | 9 | SPSM::SPSM(Core::System& system_) : ServiceFramework{system_, "spsm"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetState"}, | 12 | {0, nullptr, "GetState"}, |
diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h index 3a0b979fa..04bbf9e68 100644 --- a/src/core/hle/service/am/spsm.h +++ b/src/core/hle/service/am/spsm.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::AM { | 13 | namespace Service::AM { |
| 10 | 14 | ||
| 11 | class SPSM final : public ServiceFramework<SPSM> { | 15 | class SPSM final : public ServiceFramework<SPSM> { |
| 12 | public: | 16 | public: |
| 13 | explicit SPSM(); | 17 | explicit SPSM(Core::System& system_); |
| 14 | ~SPSM() override; | 18 | ~SPSM() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/am/tcap.cpp b/src/core/hle/service/am/tcap.cpp index a75cbdda8..4d0971c03 100644 --- a/src/core/hle/service/am/tcap.cpp +++ b/src/core/hle/service/am/tcap.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::AM { | 7 | namespace Service::AM { |
| 8 | 8 | ||
| 9 | TCAP::TCAP() : ServiceFramework{"tcap"} { | 9 | TCAP::TCAP(Core::System& system_) : ServiceFramework{system_, "tcap"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetContinuousHighSkinTemperatureEvent"}, | 12 | {0, nullptr, "GetContinuousHighSkinTemperatureEvent"}, |
diff --git a/src/core/hle/service/am/tcap.h b/src/core/hle/service/am/tcap.h index 2021b55d1..e9578f16e 100644 --- a/src/core/hle/service/am/tcap.h +++ b/src/core/hle/service/am/tcap.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::AM { | 13 | namespace Service::AM { |
| 10 | 14 | ||
| 11 | class TCAP final : public ServiceFramework<TCAP> { | 15 | class TCAP final : public ServiceFramework<TCAP> { |
| 12 | public: | 16 | public: |
| 13 | explicit TCAP(); | 17 | explicit TCAP(Core::System& system_); |
| 14 | ~TCAP() override; | 18 | ~TCAP() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 8e79f707b..23e28565b 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | #include <numeric> | 6 | #include <numeric> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | ||
| 10 | #include "core/file_sys/common_funcs.h" | ||
| 9 | #include "core/file_sys/content_archive.h" | 11 | #include "core/file_sys/content_archive.h" |
| 10 | #include "core/file_sys/control_metadata.h" | 12 | #include "core/file_sys/control_metadata.h" |
| 11 | #include "core/file_sys/nca_metadata.h" | 13 | #include "core/file_sys/nca_metadata.h" |
| @@ -22,11 +24,8 @@ | |||
| 22 | 24 | ||
| 23 | namespace Service::AOC { | 25 | namespace Service::AOC { |
| 24 | 26 | ||
| 25 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | ||
| 26 | constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000; | ||
| 27 | |||
| 28 | static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { | 27 | static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { |
| 29 | return (title_id & DLC_BASE_TITLE_ID_MASK) == base; | 28 | return FileSys::GetBaseTitleID(title_id) == base; |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { | 31 | static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { |
| @@ -47,8 +46,64 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { | |||
| 47 | return add_on_content; | 46 | return add_on_content; |
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | AOC_U::AOC_U(Core::System& system) | 49 | class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> { |
| 51 | : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) { | 50 | public: |
| 51 | explicit IPurchaseEventManager(Core::System& system_) | ||
| 52 | : ServiceFramework{system_, "IPurchaseEventManager"} { | ||
| 53 | // clang-format off | ||
| 54 | static const FunctionInfo functions[] = { | ||
| 55 | {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"}, | ||
| 56 | {1, &IPurchaseEventManager::SetDeliveryTarget, "SetDeliveryTarget"}, | ||
| 57 | {2, &IPurchaseEventManager::GetPurchasedEventReadableHandle, "GetPurchasedEventReadableHandle"}, | ||
| 58 | {3, nullptr, "PopPurchasedProductInfo"}, | ||
| 59 | {4, nullptr, "PopPurchasedProductInfoWithUid"}, | ||
| 60 | }; | ||
| 61 | // clang-format on | ||
| 62 | |||
| 63 | RegisterHandlers(functions); | ||
| 64 | |||
| 65 | purchased_event = Kernel::WritableEvent::CreateEventPair( | ||
| 66 | system.Kernel(), "IPurchaseEventManager:PurchasedEvent"); | ||
| 67 | } | ||
| 68 | |||
| 69 | private: | ||
| 70 | void SetDefaultDeliveryTarget(Kernel::HLERequestContext& ctx) { | ||
| 71 | IPC::RequestParser rp{ctx}; | ||
| 72 | |||
| 73 | const auto unknown_1 = rp.Pop<u64>(); | ||
| 74 | [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer(); | ||
| 75 | |||
| 76 | LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1); | ||
| 77 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 79 | rb.Push(RESULT_SUCCESS); | ||
| 80 | } | ||
| 81 | |||
| 82 | void SetDeliveryTarget(Kernel::HLERequestContext& ctx) { | ||
| 83 | IPC::RequestParser rp{ctx}; | ||
| 84 | |||
| 85 | const auto unknown_1 = rp.Pop<u64>(); | ||
| 86 | [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer(); | ||
| 87 | |||
| 88 | LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1); | ||
| 89 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 91 | rb.Push(RESULT_SUCCESS); | ||
| 92 | } | ||
| 93 | |||
| 94 | void GetPurchasedEventReadableHandle(Kernel::HLERequestContext& ctx) { | ||
| 95 | LOG_WARNING(Service_AOC, "called"); | ||
| 96 | |||
| 97 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 98 | rb.Push(RESULT_SUCCESS); | ||
| 99 | rb.PushCopyObjects(purchased_event.readable); | ||
| 100 | } | ||
| 101 | |||
| 102 | Kernel::EventPair purchased_event; | ||
| 103 | }; | ||
| 104 | |||
| 105 | AOC_U::AOC_U(Core::System& system_) | ||
| 106 | : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)} { | ||
| 52 | // clang-format off | 107 | // clang-format off |
| 53 | static const FunctionInfo functions[] = { | 108 | static const FunctionInfo functions[] = { |
| 54 | {0, nullptr, "CountAddOnContentByApplicationId"}, | 109 | {0, nullptr, "CountAddOnContentByApplicationId"}, |
| @@ -61,8 +116,8 @@ AOC_U::AOC_U(Core::System& system) | |||
| 61 | {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, | 116 | {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, |
| 62 | {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, | 117 | {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, |
| 63 | {9, nullptr, "GetAddOnContentLostErrorCode"}, | 118 | {9, nullptr, "GetAddOnContentLostErrorCode"}, |
| 64 | {100, nullptr, "CreateEcPurchasedEventManager"}, | 119 | {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"}, |
| 65 | {101, nullptr, "CreatePermanentEcPurchasedEventManager"}, | 120 | {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"}, |
| 66 | }; | 121 | }; |
| 67 | // clang-format on | 122 | // clang-format on |
| 68 | 123 | ||
| @@ -122,11 +177,11 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 122 | const auto& disabled = Settings::values.disabled_addons[current]; | 177 | const auto& disabled = Settings::values.disabled_addons[current]; |
| 123 | if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) { | 178 | if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) { |
| 124 | for (u64 content_id : add_on_content) { | 179 | for (u64 content_id : add_on_content) { |
| 125 | if ((content_id & DLC_BASE_TITLE_ID_MASK) != current) { | 180 | if (FileSys::GetBaseTitleID(content_id) != current) { |
| 126 | continue; | 181 | continue; |
| 127 | } | 182 | } |
| 128 | 183 | ||
| 129 | out.push_back(static_cast<u32>(content_id & 0x7FF)); | 184 | out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id))); |
| 130 | } | 185 | } |
| 131 | } | 186 | } |
| 132 | 187 | ||
| @@ -163,11 +218,12 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { | |||
| 163 | rb.Push(RESULT_SUCCESS); | 218 | rb.Push(RESULT_SUCCESS); |
| 164 | 219 | ||
| 165 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 220 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 166 | FileSys::PatchManager pm{title_id}; | 221 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 222 | system.GetContentProvider()}; | ||
| 167 | 223 | ||
| 168 | const auto res = pm.GetControlMetadata(); | 224 | const auto res = pm.GetControlMetadata(); |
| 169 | if (res.first == nullptr) { | 225 | if (res.first == nullptr) { |
| 170 | rb.Push(title_id + DLC_BASE_TO_AOC_ID); | 226 | rb.Push(FileSys::GetAOCBaseTitleID(title_id)); |
| 171 | return; | 227 | return; |
| 172 | } | 228 | } |
| 173 | 229 | ||
| @@ -199,6 +255,22 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) { | |||
| 199 | rb.PushCopyObjects(aoc_change_event.readable); | 255 | rb.PushCopyObjects(aoc_change_event.readable); |
| 200 | } | 256 | } |
| 201 | 257 | ||
| 258 | void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { | ||
| 259 | LOG_WARNING(Service_AOC, "(STUBBED) called"); | ||
| 260 | |||
| 261 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 262 | rb.Push(RESULT_SUCCESS); | ||
| 263 | rb.PushIpcInterface<IPurchaseEventManager>(system); | ||
| 264 | } | ||
| 265 | |||
| 266 | void AOC_U::CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { | ||
| 267 | LOG_WARNING(Service_AOC, "(STUBBED) called"); | ||
| 268 | |||
| 269 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 270 | rb.Push(RESULT_SUCCESS); | ||
| 271 | rb.PushIpcInterface<IPurchaseEventManager>(system); | ||
| 272 | } | ||
| 273 | |||
| 202 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 274 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 203 | std::make_shared<AOC_U>(system)->InstallAsService(service_manager); | 275 | std::make_shared<AOC_U>(system)->InstallAsService(service_manager); |
| 204 | } | 276 | } |
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 848b2f416..26ee51be0 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 Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class WritableEvent; | 14 | class WritableEvent; |
| 11 | } | 15 | } |
| @@ -23,10 +27,11 @@ private: | |||
| 23 | void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx); | 27 | void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx); |
| 24 | void PrepareAddOnContent(Kernel::HLERequestContext& ctx); | 28 | void PrepareAddOnContent(Kernel::HLERequestContext& ctx); |
| 25 | void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); | 29 | void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); |
| 30 | void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx); | ||
| 31 | void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); | ||
| 26 | 32 | ||
| 27 | std::vector<u64> add_on_content; | 33 | std::vector<u64> add_on_content; |
| 28 | Kernel::EventPair aoc_change_event; | 34 | Kernel::EventPair aoc_change_event; |
| 29 | Core::System& system; | ||
| 30 | }; | 35 | }; |
| 31 | 36 | ||
| 32 | /// Registers all AOC services with the specified service manager. | 37 | /// Registers all AOC services with the specified service manager. |
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 85bbf5988..97d6619dd 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 "core/core.h" | ||
| 5 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 6 | #include "core/hle/service/apm/apm.h" | 7 | #include "core/hle/service/apm/apm.h" |
| 7 | #include "core/hle/service/apm/interface.h" | 8 | #include "core/hle/service/apm/interface.h" |
| @@ -13,13 +14,14 @@ Module::~Module() = default; | |||
| 13 | 14 | ||
| 14 | void InstallInterfaces(Core::System& system) { | 15 | void InstallInterfaces(Core::System& system) { |
| 15 | auto module_ = std::make_shared<Module>(); | 16 | auto module_ = std::make_shared<Module>(); |
| 16 | std::make_shared<APM>(module_, system.GetAPMController(), "apm") | 17 | std::make_shared<APM>(system, module_, system.GetAPMController(), "apm") |
| 17 | ->InstallAsService(system.ServiceManager()); | 18 | ->InstallAsService(system.ServiceManager()); |
| 18 | std::make_shared<APM>(module_, system.GetAPMController(), "apm:p") | 19 | std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:p") |
| 19 | ->InstallAsService(system.ServiceManager()); | 20 | ->InstallAsService(system.ServiceManager()); |
| 20 | std::make_shared<APM>(module_, system.GetAPMController(), "apm:am") | 21 | std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:am") |
| 22 | ->InstallAsService(system.ServiceManager()); | ||
| 23 | std::make_shared<APM_Sys>(system, system.GetAPMController()) | ||
| 21 | ->InstallAsService(system.ServiceManager()); | 24 | ->InstallAsService(system.ServiceManager()); |
| 22 | std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager()); | ||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | } // namespace Service::APM | 27 | } // namespace Service::APM |
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index cf4c2bb11..691fe6c16 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h | |||
| @@ -4,7 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | namespace Core { |
| 8 | class System; | ||
| 9 | } | ||
| 8 | 10 | ||
| 9 | namespace Service::APM { | 11 | namespace Service::APM { |
| 10 | 12 | ||
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp index 25a886238..03636642b 100644 --- a/src/core/hle/service/apm/controller.cpp +++ b/src/core/hle/service/apm/controller.cpp | |||
| @@ -48,8 +48,7 @@ void Controller::SetPerformanceConfiguration(PerformanceMode mode, | |||
| 48 | [config](const auto& entry) { return entry.first == config; }); | 48 | [config](const auto& entry) { return entry.first == config; }); |
| 49 | 49 | ||
| 50 | if (iter == config_to_speed.cend()) { | 50 | if (iter == config_to_speed.cend()) { |
| 51 | LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", | 51 | LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", config); |
| 52 | static_cast<u32>(config)); | ||
| 53 | return; | 52 | return; |
| 54 | } | 53 | } |
| 55 | 54 | ||
| @@ -69,7 +68,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { | |||
| 69 | } | 68 | } |
| 70 | 69 | ||
| 71 | PerformanceMode Controller::GetCurrentPerformanceMode() const { | 70 | PerformanceMode Controller::GetCurrentPerformanceMode() const { |
| 72 | return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; | 71 | return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked |
| 72 | : PerformanceMode::Handheld; | ||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { | 75 | PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { |
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 06f0f8edd..0bff97a37 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp | |||
| @@ -12,7 +12,8 @@ namespace Service::APM { | |||
| 12 | 12 | ||
| 13 | class ISession final : public ServiceFramework<ISession> { | 13 | class ISession final : public ServiceFramework<ISession> { |
| 14 | public: | 14 | public: |
| 15 | ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) { | 15 | explicit ISession(Core::System& system_, Controller& controller_) |
| 16 | : ServiceFramework{system_, "ISession"}, controller{controller_} { | ||
| 16 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 17 | {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, | 18 | {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, |
| 18 | {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, | 19 | {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, |
| @@ -27,8 +28,7 @@ private: | |||
| 27 | 28 | ||
| 28 | const auto mode = rp.PopEnum<PerformanceMode>(); | 29 | const auto mode = rp.PopEnum<PerformanceMode>(); |
| 29 | const auto config = rp.PopEnum<PerformanceConfiguration>(); | 30 | const auto config = rp.PopEnum<PerformanceConfiguration>(); |
| 30 | LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode), | 31 | LOG_DEBUG(Service_APM, "called mode={} config={}", mode, config); |
| 31 | static_cast<u32>(config)); | ||
| 32 | 32 | ||
| 33 | controller.SetPerformanceConfiguration(mode, config); | 33 | controller.SetPerformanceConfiguration(mode, config); |
| 34 | 34 | ||
| @@ -40,7 +40,7 @@ private: | |||
| 40 | IPC::RequestParser rp{ctx}; | 40 | IPC::RequestParser rp{ctx}; |
| 41 | 41 | ||
| 42 | const auto mode = rp.PopEnum<PerformanceMode>(); | 42 | const auto mode = rp.PopEnum<PerformanceMode>(); |
| 43 | LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode)); | 43 | LOG_DEBUG(Service_APM, "called mode={}", mode); |
| 44 | 44 | ||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | 45 | IPC::ResponseBuilder rb{ctx, 3}; |
| 46 | rb.Push(RESULT_SUCCESS); | 46 | rb.Push(RESULT_SUCCESS); |
| @@ -50,12 +50,13 @@ private: | |||
| 50 | Controller& controller; | 50 | Controller& controller; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name) | 53 | APM::APM(Core::System& system_, std::shared_ptr<Module> apm_, Controller& controller_, |
| 54 | : ServiceFramework(name), apm(std::move(apm)), controller(controller) { | 54 | const char* name) |
| 55 | : ServiceFramework{system_, name}, apm(std::move(apm_)), controller{controller_} { | ||
| 55 | static const FunctionInfo functions[] = { | 56 | static const FunctionInfo functions[] = { |
| 56 | {0, &APM::OpenSession, "OpenSession"}, | 57 | {0, &APM::OpenSession, "OpenSession"}, |
| 57 | {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, | 58 | {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, |
| 58 | {6, nullptr, "IsCpuOverclockEnabled"}, | 59 | {6, &APM::IsCpuOverclockEnabled, "IsCpuOverclockEnabled"}, |
| 59 | }; | 60 | }; |
| 60 | RegisterHandlers(functions); | 61 | RegisterHandlers(functions); |
| 61 | } | 62 | } |
| @@ -67,7 +68,7 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) { | |||
| 67 | 68 | ||
| 68 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 69 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 69 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 70 | rb.PushIpcInterface<ISession>(controller); | 71 | rb.PushIpcInterface<ISession>(system, controller); |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | 74 | void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { |
| @@ -77,7 +78,16 @@ void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | |||
| 77 | rb.PushEnum(controller.GetCurrentPerformanceMode()); | 78 | rb.PushEnum(controller.GetCurrentPerformanceMode()); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) { | 81 | void APM::IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { |
| 82 | LOG_WARNING(Service_APM, "(STUBBED) called"); | ||
| 83 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 85 | rb.Push(RESULT_SUCCESS); | ||
| 86 | rb.Push(false); | ||
| 87 | } | ||
| 88 | |||
| 89 | APM_Sys::APM_Sys(Core::System& system_, Controller& controller_) | ||
| 90 | : ServiceFramework{system_, "apm:sys"}, controller{controller_} { | ||
| 81 | // clang-format off | 91 | // clang-format off |
| 82 | static const FunctionInfo functions[] = { | 92 | static const FunctionInfo functions[] = { |
| 83 | {0, nullptr, "RequestPerformanceMode"}, | 93 | {0, nullptr, "RequestPerformanceMode"}, |
| @@ -101,14 +111,14 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { | |||
| 101 | 111 | ||
| 102 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 112 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 103 | rb.Push(RESULT_SUCCESS); | 113 | rb.Push(RESULT_SUCCESS); |
| 104 | rb.PushIpcInterface<ISession>(controller); | 114 | rb.PushIpcInterface<ISession>(system, controller); |
| 105 | } | 115 | } |
| 106 | 116 | ||
| 107 | void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { | 117 | void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { |
| 108 | IPC::RequestParser rp{ctx}; | 118 | IPC::RequestParser rp{ctx}; |
| 109 | const auto mode = rp.PopEnum<CpuBoostMode>(); | 119 | const auto mode = rp.PopEnum<CpuBoostMode>(); |
| 110 | 120 | ||
| 111 | LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode)); | 121 | LOG_DEBUG(Service_APM, "called, mode={:08X}", mode); |
| 112 | 122 | ||
| 113 | controller.SetFromCpuBoostMode(mode); | 123 | controller.SetFromCpuBoostMode(mode); |
| 114 | 124 | ||
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index de1b89437..063ad5308 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h | |||
| @@ -13,12 +13,14 @@ class Module; | |||
| 13 | 13 | ||
| 14 | class APM final : public ServiceFramework<APM> { | 14 | class APM final : public ServiceFramework<APM> { |
| 15 | public: | 15 | public: |
| 16 | explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name); | 16 | explicit APM(Core::System& system_, std::shared_ptr<Module> apm_, Controller& controller_, |
| 17 | const char* name); | ||
| 17 | ~APM() override; | 18 | ~APM() override; |
| 18 | 19 | ||
| 19 | private: | 20 | private: |
| 20 | void OpenSession(Kernel::HLERequestContext& ctx); | 21 | void OpenSession(Kernel::HLERequestContext& ctx); |
| 21 | void GetPerformanceMode(Kernel::HLERequestContext& ctx); | 22 | void GetPerformanceMode(Kernel::HLERequestContext& ctx); |
| 23 | void IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx); | ||
| 22 | 24 | ||
| 23 | std::shared_ptr<Module> apm; | 25 | std::shared_ptr<Module> apm; |
| 24 | Controller& controller; | 26 | Controller& controller; |
| @@ -26,7 +28,7 @@ private: | |||
| 26 | 28 | ||
| 27 | class APM_Sys final : public ServiceFramework<APM_Sys> { | 29 | class APM_Sys final : public ServiceFramework<APM_Sys> { |
| 28 | public: | 30 | public: |
| 29 | explicit APM_Sys(Controller& controller); | 31 | explicit APM_Sys(Core::System& system_, Controller& controller); |
| 30 | ~APM_Sys() override; | 32 | ~APM_Sys() override; |
| 31 | 33 | ||
| 32 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); | 34 | void SetCpuBoostMode(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 6ddb547fb..84890be72 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::Audio { | 9 | namespace Service::Audio { |
| 10 | 10 | ||
| 11 | AudCtl::AudCtl() : ServiceFramework{"audctl"} { | 11 | AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { |
| 12 | // clang-format off | 12 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {0, nullptr, "GetTargetVolume"}, | 14 | {0, nullptr, "GetTargetVolume"}, |
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h index c7fafc02e..15f6c77a0 100644 --- a/src/core/hle/service/audio/audctl.h +++ b/src/core/hle/service/audio/audctl.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudCtl final : public ServiceFramework<AudCtl> { | 15 | class AudCtl final : public ServiceFramework<AudCtl> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudCtl(); | 17 | explicit AudCtl(Core::System& system_); |
| 14 | ~AudCtl() override; | 18 | ~AudCtl() override; |
| 15 | 19 | ||
| 16 | private: | 20 | private: |
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp index 8fff3e4b4..6264e4bda 100644 --- a/src/core/hle/service/audio/auddbg.cpp +++ b/src/core/hle/service/audio/auddbg.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 8 | 8 | ||
| 9 | AudDbg::AudDbg(const char* name) : ServiceFramework{name} { | 9 | AudDbg::AudDbg(Core::System& system_, const char* name) : ServiceFramework{system_, name} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "RequestSuspendForDebug"}, | 12 | {0, nullptr, "RequestSuspendForDebug"}, |
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h index 6689f4759..d1653eedd 100644 --- a/src/core/hle/service/audio/auddbg.h +++ b/src/core/hle/service/audio/auddbg.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudDbg final : public ServiceFramework<AudDbg> { | 15 | class AudDbg final : public ServiceFramework<AudDbg> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudDbg(const char* name); | 17 | explicit AudDbg(Core::System& system_, const char* name); |
| 14 | ~AudDbg() override; | 18 | ~AudDbg() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp index ddd12f35e..79c3aa920 100644 --- a/src/core/hle/service/audio/audin_a.cpp +++ b/src/core/hle/service/audio/audin_a.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 8 | 8 | ||
| 9 | AudInA::AudInA() : ServiceFramework{"audin:a"} { | 9 | AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "RequestSuspendAudioIns"}, | 12 | {0, nullptr, "RequestSuspendAudioIns"}, |
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h index e7623bc29..15120a4b6 100644 --- a/src/core/hle/service/audio/audin_a.h +++ b/src/core/hle/service/audio/audin_a.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudInA final : public ServiceFramework<AudInA> { | 15 | class AudInA final : public ServiceFramework<AudInA> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudInA(); | 17 | explicit AudInA(Core::System& system_); |
| 14 | ~AudInA() override; | 18 | ~AudInA() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 3e2299426..26a6deddf 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp | |||
| @@ -11,7 +11,7 @@ namespace Service::Audio { | |||
| 11 | 11 | ||
| 12 | class IAudioIn final : public ServiceFramework<IAudioIn> { | 12 | class IAudioIn final : public ServiceFramework<IAudioIn> { |
| 13 | public: | 13 | public: |
| 14 | IAudioIn() : ServiceFramework("IAudioIn") { | 14 | explicit IAudioIn(Core::System& system_) : ServiceFramework{system_, "IAudioIn"} { |
| 15 | // clang-format off | 15 | // clang-format off |
| 16 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 17 | {0, nullptr, "GetAudioInState"}, | 17 | {0, nullptr, "GetAudioInState"}, |
| @@ -36,7 +36,7 @@ public: | |||
| 36 | } | 36 | } |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | AudInU::AudInU() : ServiceFramework("audin:u") { | 39 | AudInU::AudInU(Core::System& system_) : ServiceFramework{system_, "audin:u"} { |
| 40 | // clang-format off | 40 | // clang-format off |
| 41 | static const FunctionInfo functions[] = { | 41 | static const FunctionInfo functions[] = { |
| 42 | {0, &AudInU::ListAudioIns, "ListAudioIns"}, | 42 | {0, &AudInU::ListAudioIns, "ListAudioIns"}, |
| @@ -96,7 +96,7 @@ void AudInU::OpenInOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 96 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
| 97 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 98 | rb.PushRaw<AudInOutParams>(params); | 98 | rb.PushRaw<AudInOutParams>(params); |
| 99 | rb.PushIpcInterface<IAudioIn>(); | 99 | rb.PushIpcInterface<IAudioIn>(system); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) { | 102 | void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h index a599f4a64..0d75ae5ac 100644 --- a/src/core/hle/service/audio/audin_u.h +++ b/src/core/hle/service/audio/audin_u.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,7 +18,7 @@ namespace Service::Audio { | |||
| 14 | 18 | ||
| 15 | class AudInU final : public ServiceFramework<AudInU> { | 19 | class AudInU final : public ServiceFramework<AudInU> { |
| 16 | public: | 20 | public: |
| 17 | explicit AudInU(); | 21 | explicit AudInU(Core::System& system_); |
| 18 | ~AudInU() override; | 22 | ~AudInU() override; |
| 19 | 23 | ||
| 20 | private: | 24 | private: |
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 1781bec83..b3f24f9bb 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp | |||
| @@ -20,22 +20,22 @@ | |||
| 20 | namespace Service::Audio { | 20 | namespace Service::Audio { |
| 21 | 21 | ||
| 22 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 22 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 23 | std::make_shared<AudCtl>()->InstallAsService(service_manager); | 23 | std::make_shared<AudCtl>(system)->InstallAsService(service_manager); |
| 24 | std::make_shared<AudOutA>()->InstallAsService(service_manager); | 24 | std::make_shared<AudOutA>(system)->InstallAsService(service_manager); |
| 25 | std::make_shared<AudOutU>(system)->InstallAsService(service_manager); | 25 | std::make_shared<AudOutU>(system)->InstallAsService(service_manager); |
| 26 | std::make_shared<AudInA>()->InstallAsService(service_manager); | 26 | std::make_shared<AudInA>(system)->InstallAsService(service_manager); |
| 27 | std::make_shared<AudInU>()->InstallAsService(service_manager); | 27 | std::make_shared<AudInU>(system)->InstallAsService(service_manager); |
| 28 | std::make_shared<AudRecA>()->InstallAsService(service_manager); | 28 | std::make_shared<AudRecA>(system)->InstallAsService(service_manager); |
| 29 | std::make_shared<AudRecU>()->InstallAsService(service_manager); | 29 | std::make_shared<AudRecU>(system)->InstallAsService(service_manager); |
| 30 | std::make_shared<AudRenA>()->InstallAsService(service_manager); | 30 | std::make_shared<AudRenA>(system)->InstallAsService(service_manager); |
| 31 | std::make_shared<AudRenU>(system)->InstallAsService(service_manager); | 31 | std::make_shared<AudRenU>(system)->InstallAsService(service_manager); |
| 32 | std::make_shared<CodecCtl>()->InstallAsService(service_manager); | 32 | std::make_shared<CodecCtl>(system)->InstallAsService(service_manager); |
| 33 | std::make_shared<HwOpus>()->InstallAsService(service_manager); | 33 | std::make_shared<HwOpus>(system)->InstallAsService(service_manager); |
| 34 | 34 | ||
| 35 | std::make_shared<AudDbg>("audin:d")->InstallAsService(service_manager); | 35 | std::make_shared<AudDbg>(system, "audin:d")->InstallAsService(service_manager); |
| 36 | std::make_shared<AudDbg>("audout:d")->InstallAsService(service_manager); | 36 | std::make_shared<AudDbg>(system, "audout:d")->InstallAsService(service_manager); |
| 37 | std::make_shared<AudDbg>("audrec:d")->InstallAsService(service_manager); | 37 | std::make_shared<AudDbg>(system, "audrec:d")->InstallAsService(service_manager); |
| 38 | std::make_shared<AudDbg>("audren:d")->InstallAsService(service_manager); | 38 | std::make_shared<AudDbg>(system, "audren:d")->InstallAsService(service_manager); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | } // namespace Service::Audio | 41 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp index 85febbca3..19825fd5d 100644 --- a/src/core/hle/service/audio/audout_a.cpp +++ b/src/core/hle/service/audio/audout_a.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 8 | 8 | ||
| 9 | AudOutA::AudOutA() : ServiceFramework{"audout:a"} { | 9 | AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "RequestSuspendAudioOuts"}, | 12 | {0, nullptr, "RequestSuspendAudioOuts"}, |
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h index d65b66e8e..2043dfb77 100644 --- a/src/core/hle/service/audio/audout_a.h +++ b/src/core/hle/service/audio/audout_a.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudOutA final : public ServiceFramework<AudOutA> { | 15 | class AudOutA final : public ServiceFramework<AudOutA> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudOutA(); | 17 | explicit AudOutA(Core::System& system_); |
| 14 | ~AudOutA() override; | 18 | ~AudOutA() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 9b4910e53..0cd797109 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -40,11 +40,11 @@ enum class AudioState : u32 { | |||
| 40 | 40 | ||
| 41 | class IAudioOut final : public ServiceFramework<IAudioOut> { | 41 | class IAudioOut final : public ServiceFramework<IAudioOut> { |
| 42 | public: | 42 | public: |
| 43 | IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, | 43 | IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_, |
| 44 | std::string&& device_name, std::string&& unique_name) | 44 | std::string&& device_name_, std::string&& unique_name) |
| 45 | : ServiceFramework("IAudioOut"), audio_core(audio_core), | 45 | : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, |
| 46 | device_name(std::move(device_name)), | 46 | device_name{std::move(device_name_)}, audio_params{audio_params_}, main_memory{ |
| 47 | audio_params(audio_params), main_memory{system.Memory()} { | 47 | system.Memory()} { |
| 48 | // clang-format off | 48 | // clang-format off |
| 49 | static const FunctionInfo functions[] = { | 49 | static const FunctionInfo functions[] = { |
| 50 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | 50 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, |
| @@ -70,8 +70,10 @@ public: | |||
| 70 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); | 70 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); |
| 71 | 71 | ||
| 72 | stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, | 72 | stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, |
| 73 | audio_params.channel_count, std::move(unique_name), | 73 | audio_params.channel_count, std::move(unique_name), [this] { |
| 74 | [this] { buffer_event.writable->Signal(); }); | 74 | const auto guard = LockService(); |
| 75 | buffer_event.writable->Signal(); | ||
| 76 | }); | ||
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | private: | 79 | private: |
| @@ -213,7 +215,7 @@ private: | |||
| 213 | Core::Memory::Memory& main_memory; | 215 | Core::Memory::Memory& main_memory; |
| 214 | }; | 216 | }; |
| 215 | 217 | ||
| 216 | AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { | 218 | AudOutU::AudOutU(Core::System& system_) : ServiceFramework{system_, "audout:u"} { |
| 217 | // clang-format off | 219 | // clang-format off |
| 218 | static const FunctionInfo functions[] = { | 220 | static const FunctionInfo functions[] = { |
| 219 | {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, | 221 | {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, |
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index c9f532ccd..f7ae2f2bf 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h | |||
| @@ -34,8 +34,6 @@ private: | |||
| 34 | 34 | ||
| 35 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; | 35 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; |
| 36 | std::unique_ptr<AudioCore::AudioOut> audio_core; | 36 | std::unique_ptr<AudioCore::AudioOut> audio_core; |
| 37 | |||
| 38 | Core::System& system; | ||
| 39 | }; | 37 | }; |
| 40 | 38 | ||
| 41 | } // namespace Service::Audio | 39 | } // namespace Service::Audio |
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp index ce1bfb48d..c5ab7cad4 100644 --- a/src/core/hle/service/audio/audrec_a.cpp +++ b/src/core/hle/service/audio/audrec_a.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 8 | 8 | ||
| 9 | AudRecA::AudRecA() : ServiceFramework{"audrec:a"} { | 9 | AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "RequestSuspendFinalOutputRecorders"}, | 12 | {0, nullptr, "RequestSuspendFinalOutputRecorders"}, |
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h index 384d24c69..2cce90b1d 100644 --- a/src/core/hle/service/audio/audrec_a.h +++ b/src/core/hle/service/audio/audrec_a.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudRecA final : public ServiceFramework<AudRecA> { | 15 | class AudRecA final : public ServiceFramework<AudRecA> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudRecA(); | 17 | explicit AudRecA(Core::System& system_); |
| 14 | ~AudRecA() override; | 18 | ~AudRecA() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp index 1a5aed9ed..eb5c63c62 100644 --- a/src/core/hle/service/audio/audrec_u.cpp +++ b/src/core/hle/service/audio/audrec_u.cpp | |||
| @@ -8,7 +8,8 @@ namespace Service::Audio { | |||
| 8 | 8 | ||
| 9 | class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> { | 9 | class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> { |
| 10 | public: | 10 | public: |
| 11 | IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") { | 11 | explicit IFinalOutputRecorder(Core::System& system_) |
| 12 | : ServiceFramework{system_, "IFinalOutputRecorder"} { | ||
| 12 | // clang-format off | 13 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 14 | static const FunctionInfo functions[] = { |
| 14 | {0, nullptr, "GetFinalOutputRecorderState"}, | 15 | {0, nullptr, "GetFinalOutputRecorderState"}, |
| @@ -29,7 +30,7 @@ public: | |||
| 29 | } | 30 | } |
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| 32 | AudRecU::AudRecU() : ServiceFramework("audrec:u") { | 33 | AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} { |
| 33 | static const FunctionInfo functions[] = { | 34 | static const FunctionInfo functions[] = { |
| 34 | {0, nullptr, "OpenFinalOutputRecorder"}, | 35 | {0, nullptr, "OpenFinalOutputRecorder"}, |
| 35 | }; | 36 | }; |
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h index ca3d638e8..f79d49e5c 100644 --- a/src/core/hle/service/audio/audrec_u.h +++ b/src/core/hle/service/audio/audrec_u.h | |||
| @@ -6,15 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Core { |
| 10 | class HLERequestContext; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 14 | 14 | ||
| 15 | class AudRecU final : public ServiceFramework<AudRecU> { | 15 | class AudRecU final : public ServiceFramework<AudRecU> { |
| 16 | public: | 16 | public: |
| 17 | explicit AudRecU(); | 17 | explicit AudRecU(Core::System& system_); |
| 18 | ~AudRecU() override; | 18 | ~AudRecU() override; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp index edb66d985..5e9f866f0 100644 --- a/src/core/hle/service/audio/audren_a.cpp +++ b/src/core/hle/service/audio/audren_a.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 8 | 8 | ||
| 9 | AudRenA::AudRenA() : ServiceFramework{"audren:a"} { | 9 | AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "RequestSuspendAudioRenderers"}, | 12 | {0, nullptr, "RequestSuspendAudioRenderers"}, |
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h index 81fef0ffe..5d0a626ad 100644 --- a/src/core/hle/service/audio/audren_a.h +++ b/src/core/hle/service/audio/audren_a.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class AudRenA final : public ServiceFramework<AudRenA> { | 15 | class AudRenA final : public ServiceFramework<AudRenA> { |
| 12 | public: | 16 | public: |
| 13 | explicit AudRenA(); | 17 | explicit AudRenA(Core::System& system_); |
| 14 | ~AudRenA() override; | 18 | ~AudRenA() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index a2d3ded7b..c5c22d053 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -28,7 +28,7 @@ class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { | |||
| 28 | public: | 28 | public: |
| 29 | explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params, | 29 | explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params, |
| 30 | const std::size_t instance_number) | 30 | const std::size_t instance_number) |
| 31 | : ServiceFramework("IAudioRenderer") { | 31 | : ServiceFramework{system, "IAudioRenderer"} { |
| 32 | // clang-format off | 32 | // clang-format off |
| 33 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| 34 | {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, | 34 | {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, |
| @@ -49,16 +49,16 @@ public: | |||
| 49 | 49 | ||
| 50 | system_event = | 50 | system_event = |
| 51 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); | 51 | Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); |
| 52 | renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(), | 52 | renderer = std::make_unique<AudioCore::AudioRenderer>( |
| 53 | audren_params, system_event.writable, | 53 | system.CoreTiming(), system.Memory(), audren_params, |
| 54 | instance_number); | 54 | [this]() { |
| 55 | const auto guard = LockService(); | ||
| 56 | system_event.writable->Signal(); | ||
| 57 | }, | ||
| 58 | instance_number); | ||
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | private: | 61 | private: |
| 58 | void UpdateAudioCallback() { | ||
| 59 | system_event.writable->Signal(); | ||
| 60 | } | ||
| 61 | |||
| 62 | void GetSampleRate(Kernel::HLERequestContext& ctx) { | 62 | void GetSampleRate(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_DEBUG(Service_Audio, "called"); | 63 | LOG_DEBUG(Service_Audio, "called"); |
| 64 | 64 | ||
| @@ -167,8 +167,8 @@ private: | |||
| 167 | 167 | ||
| 168 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 168 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
| 169 | public: | 169 | public: |
| 170 | explicit IAudioDevice(Core::System& system, u32_le revision_num) | 170 | explicit IAudioDevice(Core::System& system_, u32_le revision_num) |
| 171 | : ServiceFramework("IAudioDevice"), revision{revision_num} { | 171 | : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} { |
| 172 | static const FunctionInfo functions[] = { | 172 | static const FunctionInfo functions[] = { |
| 173 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, | 173 | {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, |
| 174 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, | 174 | {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, |
| @@ -325,7 +325,7 @@ private: | |||
| 325 | 325 | ||
| 326 | }; // namespace Audio | 326 | }; // namespace Audio |
| 327 | 327 | ||
| 328 | AudRenU::AudRenU(Core::System& system_) : ServiceFramework("audren:u"), system{system_} { | 328 | AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} { |
| 329 | // clang-format off | 329 | // clang-format off |
| 330 | static const FunctionInfo functions[] = { | 330 | static const FunctionInfo functions[] = { |
| 331 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, | 331 | {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, |
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 4e0ccc792..d693dc406 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h | |||
| @@ -31,7 +31,6 @@ private: | |||
| 31 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); | 31 | void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); |
| 32 | 32 | ||
| 33 | std::size_t audren_instance_count = 0; | 33 | std::size_t audren_instance_count = 0; |
| 34 | Core::System& system; | ||
| 35 | }; | 34 | }; |
| 36 | 35 | ||
| 37 | // Describes a particular audio feature that may be supported in a particular revision. | 36 | // Describes a particular audio feature that may be supported in a particular revision. |
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp index c6864146d..94afec1b6 100644 --- a/src/core/hle/service/audio/codecctl.cpp +++ b/src/core/hle/service/audio/codecctl.cpp | |||
| @@ -2,14 +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 "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | ||
| 8 | #include "core/hle/service/audio/codecctl.h" | 5 | #include "core/hle/service/audio/codecctl.h" |
| 9 | 6 | ||
| 10 | namespace Service::Audio { | 7 | namespace Service::Audio { |
| 11 | 8 | ||
| 12 | CodecCtl::CodecCtl() : ServiceFramework("codecctl") { | 9 | CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} { |
| 13 | static const FunctionInfo functions[] = { | 10 | static const FunctionInfo functions[] = { |
| 14 | {0, nullptr, "InitializeCodecController"}, | 11 | {0, nullptr, "InitializeCodecController"}, |
| 15 | {1, nullptr, "FinalizeCodecController"}, | 12 | {1, nullptr, "FinalizeCodecController"}, |
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h index 2fe75b6e2..58e53259e 100644 --- a/src/core/hle/service/audio/codecctl.h +++ b/src/core/hle/service/audio/codecctl.h | |||
| @@ -6,15 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Core { |
| 10 | class HLERequestContext; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 14 | 14 | ||
| 15 | class CodecCtl final : public ServiceFramework<CodecCtl> { | 15 | class CodecCtl final : public ServiceFramework<CodecCtl> { |
| 16 | public: | 16 | public: |
| 17 | explicit CodecCtl(); | 17 | explicit CodecCtl(Core::System& system_); |
| 18 | ~CodecCtl() override; | 18 | ~CodecCtl() override; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index f1d81602c..ea3414fd2 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -160,8 +160,9 @@ private: | |||
| 160 | 160 | ||
| 161 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { | 161 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { |
| 162 | public: | 162 | public: |
| 163 | explicit IHardwareOpusDecoderManager(OpusDecoderState decoder_state) | 163 | explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state) |
| 164 | : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { | 164 | : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{ |
| 165 | std::move(decoder_state)} { | ||
| 165 | // clang-format off | 166 | // clang-format off |
| 166 | static const FunctionInfo functions[] = { | 167 | static const FunctionInfo functions[] = { |
| 167 | {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, | 168 | {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, |
| @@ -287,10 +288,10 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 287 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 288 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 288 | rb.Push(RESULT_SUCCESS); | 289 | rb.Push(RESULT_SUCCESS); |
| 289 | rb.PushIpcInterface<IHardwareOpusDecoderManager>( | 290 | rb.PushIpcInterface<IHardwareOpusDecoderManager>( |
| 290 | OpusDecoderState{std::move(decoder), sample_rate, channel_count}); | 291 | system, OpusDecoderState{std::move(decoder), sample_rate, channel_count}); |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 293 | HwOpus::HwOpus() : ServiceFramework("hwopus") { | 294 | HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} { |
| 294 | static const FunctionInfo functions[] = { | 295 | static const FunctionInfo functions[] = { |
| 295 | {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"}, | 296 | {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"}, |
| 296 | {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, | 297 | {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, |
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h index 602ede8ba..4f921f18e 100644 --- a/src/core/hle/service/audio/hwopus.h +++ b/src/core/hle/service/audio/hwopus.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Audio { | 13 | namespace Service::Audio { |
| 10 | 14 | ||
| 11 | class HwOpus final : public ServiceFramework<HwOpus> { | 15 | class HwOpus final : public ServiceFramework<HwOpus> { |
| 12 | public: | 16 | public: |
| 13 | explicit HwOpus(); | 17 | explicit HwOpus(Core::System& system_); |
| 14 | ~HwOpus() override; | 18 | ~HwOpus() override; |
| 15 | 19 | ||
| 16 | private: | 20 | private: |
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index def3410cc..174388445 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp | |||
| @@ -84,7 +84,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) { | |||
| 84 | 84 | ||
| 85 | void ProgressServiceBackend::SignalUpdate() const { | 85 | void ProgressServiceBackend::SignalUpdate() const { |
| 86 | if (need_hle_lock) { | 86 | if (need_hle_lock) { |
| 87 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | 87 | std::lock_guard lock(HLE::g_hle_lock); |
| 88 | event.writable->Signal(); | 88 | event.writable->Signal(); |
| 89 | } else { | 89 | } else { |
| 90 | event.writable->Signal(); | 90 | event.writable->Signal(); |
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index ca021a99f..e43f3f47f 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp | |||
| @@ -196,7 +196,9 @@ private: | |||
| 196 | const std::string& content_type_name) { | 196 | const std::string& content_type_name) { |
| 197 | if (client == nullptr) { | 197 | if (client == nullptr) { |
| 198 | client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT); | 198 | client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT); |
| 199 | client->set_timeout_sec(timeout_seconds); | 199 | client->set_connection_timeout(timeout_seconds); |
| 200 | client->set_read_timeout(timeout_seconds); | ||
| 201 | client->set_write_timeout(timeout_seconds); | ||
| 200 | } | 202 | } |
| 201 | 203 | ||
| 202 | httplib::Headers headers{ | 204 | httplib::Headers headers{ |
| @@ -255,7 +257,7 @@ private: | |||
| 255 | return out; | 257 | return out; |
| 256 | } | 258 | } |
| 257 | 259 | ||
| 258 | std::unique_ptr<httplib::Client> client; | 260 | std::unique_ptr<httplib::SSLClient> client; |
| 259 | std::string path; | 261 | std::string path; |
| 260 | u64 title_id; | 262 | u64 title_id; |
| 261 | u64 build_id; | 263 | u64 build_id; |
| @@ -443,13 +445,25 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) | |||
| 443 | Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, | 445 | Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, |
| 444 | std::map<std::string, EventStatus>& games) { | 446 | std::map<std::string, EventStatus>& games) { |
| 445 | httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)}; | 447 | httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)}; |
| 446 | client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS)); | 448 | client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS)); |
| 449 | client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS)); | ||
| 450 | client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS)); | ||
| 447 | 451 | ||
| 448 | httplib::Headers headers{ | 452 | httplib::Headers headers{ |
| 449 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, | 453 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, |
| 450 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, | 454 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, |
| 451 | }; | 455 | }; |
| 452 | 456 | ||
| 457 | if (!client.is_valid()) { | ||
| 458 | LOG_ERROR(Service_BCAT, "Client is invalid, going offline!"); | ||
| 459 | return StatusResult::Offline; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (!client.is_socket_open()) { | ||
| 463 | LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!"); | ||
| 464 | return StatusResult::Offline; | ||
| 465 | } | ||
| 466 | |||
| 453 | const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); | 467 | const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); |
| 454 | if (response == nullptr) | 468 | if (response == nullptr) |
| 455 | return StatusResult::Offline; | 469 | return StatusResult::Offline; |
| @@ -469,7 +483,7 @@ Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, | |||
| 469 | global = json["global"].get<std::string>(); | 483 | global = json["global"].get<std::string>(); |
| 470 | 484 | ||
| 471 | if (json["games"].is_array()) { | 485 | if (json["games"].is_array()) { |
| 472 | for (const auto object : json["games"]) { | 486 | for (const auto& object : json["games"]) { |
| 473 | if (object.is_object() && object.find("name") != object.end()) { | 487 | if (object.is_object() && object.find("name") != object.end()) { |
| 474 | EventStatus detail{}; | 488 | EventStatus detail{}; |
| 475 | if (object["header"].is_string()) { | 489 | if (object["header"].is_string()) { |
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index db0e06ca1..b8696a395 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/hex_util.h" | 8 | #include "common/hex_util.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/core.h" | ||
| 11 | #include "core/file_sys/vfs.h" | 12 | #include "core/file_sys/vfs.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| @@ -87,9 +88,11 @@ struct DeliveryCacheDirectoryEntry { | |||
| 87 | 88 | ||
| 88 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { | 89 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { |
| 89 | public: | 90 | public: |
| 90 | IDeliveryCacheProgressService(std::shared_ptr<Kernel::ReadableEvent> event, | 91 | explicit IDeliveryCacheProgressService(Core::System& system_, |
| 91 | const DeliveryCacheProgressImpl& impl) | 92 | std::shared_ptr<Kernel::ReadableEvent> event_, |
| 92 | : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { | 93 | const DeliveryCacheProgressImpl& impl_) |
| 94 | : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)}, | ||
| 95 | impl{impl_} { | ||
| 93 | // clang-format off | 96 | // clang-format off |
| 94 | static const FunctionInfo functions[] = { | 97 | static const FunctionInfo functions[] = { |
| 95 | {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, | 98 | {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, |
| @@ -125,7 +128,7 @@ private: | |||
| 125 | class IBcatService final : public ServiceFramework<IBcatService> { | 128 | class IBcatService final : public ServiceFramework<IBcatService> { |
| 126 | public: | 129 | public: |
| 127 | explicit IBcatService(Core::System& system_, Backend& backend_) | 130 | explicit IBcatService(Core::System& system_, Backend& backend_) |
| 128 | : ServiceFramework("IBcatService"), system{system_}, backend{backend_}, | 131 | : ServiceFramework{system_, "IBcatService"}, backend{backend_}, |
| 129 | progress{{ | 132 | progress{{ |
| 130 | ProgressServiceBackend{system_.Kernel(), "Normal"}, | 133 | ProgressServiceBackend{system_.Kernel(), "Normal"}, |
| 131 | ProgressServiceBackend{system_.Kernel(), "Directory"}, | 134 | ProgressServiceBackend{system_.Kernel(), "Directory"}, |
| @@ -170,7 +173,7 @@ private: | |||
| 170 | 173 | ||
| 171 | std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { | 174 | std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { |
| 172 | auto& backend{progress.at(static_cast<std::size_t>(type))}; | 175 | auto& backend{progress.at(static_cast<std::size_t>(type))}; |
| 173 | return std::make_shared<IDeliveryCacheProgressService>(backend.GetEvent(), | 176 | return std::make_shared<IDeliveryCacheProgressService>(system, backend.GetEvent(), |
| 174 | backend.GetImpl()); | 177 | backend.GetImpl()); |
| 175 | } | 178 | } |
| 176 | 179 | ||
| @@ -260,7 +263,6 @@ private: | |||
| 260 | rb.Push(RESULT_SUCCESS); | 263 | rb.Push(RESULT_SUCCESS); |
| 261 | } | 264 | } |
| 262 | 265 | ||
| 263 | Core::System& system; | ||
| 264 | Backend& backend; | 266 | Backend& backend; |
| 265 | 267 | ||
| 266 | std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress; | 268 | std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress; |
| @@ -276,8 +278,8 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | |||
| 276 | 278 | ||
| 277 | class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { | 279 | class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { |
| 278 | public: | 280 | public: |
| 279 | IDeliveryCacheFileService(FileSys::VirtualDir root_) | 281 | explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_) |
| 280 | : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { | 282 | : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) { |
| 281 | // clang-format off | 283 | // clang-format off |
| 282 | static const FunctionInfo functions[] = { | 284 | static const FunctionInfo functions[] = { |
| 283 | {0, &IDeliveryCacheFileService::Open, "Open"}, | 285 | {0, &IDeliveryCacheFileService::Open, "Open"}, |
| @@ -393,8 +395,8 @@ private: | |||
| 393 | class IDeliveryCacheDirectoryService final | 395 | class IDeliveryCacheDirectoryService final |
| 394 | : public ServiceFramework<IDeliveryCacheDirectoryService> { | 396 | : public ServiceFramework<IDeliveryCacheDirectoryService> { |
| 395 | public: | 397 | public: |
| 396 | IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) | 398 | explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_) |
| 397 | : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { | 399 | : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) { |
| 398 | // clang-format off | 400 | // clang-format off |
| 399 | static const FunctionInfo functions[] = { | 401 | static const FunctionInfo functions[] = { |
| 400 | {0, &IDeliveryCacheDirectoryService::Open, "Open"}, | 402 | {0, &IDeliveryCacheDirectoryService::Open, "Open"}, |
| @@ -491,8 +493,8 @@ private: | |||
| 491 | 493 | ||
| 492 | class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { | 494 | class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { |
| 493 | public: | 495 | public: |
| 494 | IDeliveryCacheStorageService(FileSys::VirtualDir root_) | 496 | explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_) |
| 495 | : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { | 497 | : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) { |
| 496 | // clang-format off | 498 | // clang-format off |
| 497 | static const FunctionInfo functions[] = { | 499 | static const FunctionInfo functions[] = { |
| 498 | {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, | 500 | {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, |
| @@ -517,7 +519,7 @@ private: | |||
| 517 | 519 | ||
| 518 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 520 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 519 | rb.Push(RESULT_SUCCESS); | 521 | rb.Push(RESULT_SUCCESS); |
| 520 | rb.PushIpcInterface<IDeliveryCacheFileService>(root); | 522 | rb.PushIpcInterface<IDeliveryCacheFileService>(system, root); |
| 521 | } | 523 | } |
| 522 | 524 | ||
| 523 | void CreateDirectoryService(Kernel::HLERequestContext& ctx) { | 525 | void CreateDirectoryService(Kernel::HLERequestContext& ctx) { |
| @@ -525,7 +527,7 @@ private: | |||
| 525 | 527 | ||
| 526 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 528 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 527 | rb.Push(RESULT_SUCCESS); | 529 | rb.Push(RESULT_SUCCESS); |
| 528 | rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root); | 530 | rb.PushIpcInterface<IDeliveryCacheDirectoryService>(system, root); |
| 529 | } | 531 | } |
| 530 | 532 | ||
| 531 | void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { | 533 | void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { |
| @@ -550,10 +552,10 @@ private: | |||
| 550 | void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { | 552 | void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { |
| 551 | LOG_DEBUG(Service_BCAT, "called"); | 553 | LOG_DEBUG(Service_BCAT, "called"); |
| 552 | 554 | ||
| 555 | const auto title_id = system.CurrentProcess()->GetTitleID(); | ||
| 553 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 556 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 554 | rb.Push(RESULT_SUCCESS); | 557 | rb.Push(RESULT_SUCCESS); |
| 555 | rb.PushIpcInterface<IDeliveryCacheStorageService>( | 558 | rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id)); |
| 556 | fsc.GetBCATDirectory(system.CurrentProcess()->GetTitleID())); | ||
| 557 | } | 559 | } |
| 558 | 560 | ||
| 559 | void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( | 561 | void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( |
| @@ -565,7 +567,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( | |||
| 565 | 567 | ||
| 566 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 568 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 567 | rb.Push(RESULT_SUCCESS); | 569 | rb.Push(RESULT_SUCCESS); |
| 568 | rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); | 570 | rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id)); |
| 569 | } | 571 | } |
| 570 | 572 | ||
| 571 | std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, | 573 | std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, |
| @@ -581,10 +583,9 @@ std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System | |||
| 581 | 583 | ||
| 582 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, | 584 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 583 | FileSystem::FileSystemController& fsc_, const char* name) | 585 | FileSystem::FileSystemController& fsc_, const char* name) |
| 584 | : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)}, | 586 | : ServiceFramework{system_, name}, fsc{fsc_}, module{std::move(module_)}, |
| 585 | backend{CreateBackendFromSettings(system_, | 587 | backend{CreateBackendFromSettings(system_, |
| 586 | [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })}, | 588 | [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })} {} |
| 587 | system{system_} {} | ||
| 588 | 589 | ||
| 589 | Module::Interface::~Interface() = default; | 590 | Module::Interface::~Interface() = default; |
| 590 | 591 | ||
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index e4ba23ba0..738731c06 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h | |||
| @@ -37,9 +37,6 @@ public: | |||
| 37 | 37 | ||
| 38 | std::shared_ptr<Module> module; | 38 | std::shared_ptr<Module> module; |
| 39 | std::unique_ptr<Backend> backend; | 39 | std::unique_ptr<Backend> backend; |
| 40 | |||
| 41 | private: | ||
| 42 | Core::System& system; | ||
| 43 | }; | 40 | }; |
| 44 | }; | 41 | }; |
| 45 | 42 | ||
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp index fac6b2f9c..e4630320e 100644 --- a/src/core/hle/service/bpc/bpc.cpp +++ b/src/core/hle/service/bpc/bpc.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::BPC { | |||
| 12 | 12 | ||
| 13 | class BPC final : public ServiceFramework<BPC> { | 13 | class BPC final : public ServiceFramework<BPC> { |
| 14 | public: | 14 | public: |
| 15 | explicit BPC() : ServiceFramework{"bpc"} { | 15 | explicit BPC(Core::System& system_) : ServiceFramework{system_, "bpc"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "ShutdownSystem"}, | 18 | {0, nullptr, "ShutdownSystem"}, |
| @@ -40,7 +40,7 @@ public: | |||
| 40 | 40 | ||
| 41 | class BPC_R final : public ServiceFramework<BPC_R> { | 41 | class BPC_R final : public ServiceFramework<BPC_R> { |
| 42 | public: | 42 | public: |
| 43 | explicit BPC_R() : ServiceFramework{"bpc:r"} { | 43 | explicit BPC_R(Core::System& system_) : ServiceFramework{system_, "bpc:r"} { |
| 44 | // clang-format off | 44 | // clang-format off |
| 45 | static const FunctionInfo functions[] = { | 45 | static const FunctionInfo functions[] = { |
| 46 | {0, nullptr, "GetRtcTime"}, | 46 | {0, nullptr, "GetRtcTime"}, |
| @@ -55,9 +55,9 @@ public: | |||
| 55 | } | 55 | } |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | void InstallInterfaces(SM::ServiceManager& sm) { | 58 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 59 | std::make_shared<BPC>()->InstallAsService(sm); | 59 | std::make_shared<BPC>(system)->InstallAsService(sm); |
| 60 | std::make_shared<BPC_R>()->InstallAsService(sm); | 60 | std::make_shared<BPC_R>(system)->InstallAsService(sm); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | } // namespace Service::BPC | 63 | } // namespace Service::BPC |
diff --git a/src/core/hle/service/bpc/bpc.h b/src/core/hle/service/bpc/bpc.h index eaa37be8d..6ec25aa9b 100644 --- a/src/core/hle/service/bpc/bpc.h +++ b/src/core/hle/service/bpc/bpc.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::BPC { | 15 | namespace Service::BPC { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::BPC | 19 | } // namespace Service::BPC |
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index f311afa2f..2de86f1f1 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/hle_ipc.h" | 8 | #include "core/hle/kernel/hle_ipc.h" |
| 8 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| @@ -16,7 +17,7 @@ namespace Service::BtDrv { | |||
| 16 | 17 | ||
| 17 | class Bt final : public ServiceFramework<Bt> { | 18 | class Bt final : public ServiceFramework<Bt> { |
| 18 | public: | 19 | public: |
| 19 | explicit Bt(Core::System& system) : ServiceFramework{"bt"} { | 20 | explicit Bt(Core::System& system_) : ServiceFramework{system_, "bt"} { |
| 20 | // clang-format off | 21 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 22 | {0, nullptr, "LeClientReadCharacteristic"}, | 23 | {0, nullptr, "LeClientReadCharacteristic"}, |
| @@ -51,7 +52,7 @@ private: | |||
| 51 | 52 | ||
| 52 | class BtDrv final : public ServiceFramework<BtDrv> { | 53 | class BtDrv final : public ServiceFramework<BtDrv> { |
| 53 | public: | 54 | public: |
| 54 | explicit BtDrv() : ServiceFramework{"btdrv"} { | 55 | explicit BtDrv(Core::System& system_) : ServiceFramework{system_, "btdrv"} { |
| 55 | // clang-format off | 56 | // clang-format off |
| 56 | static const FunctionInfo functions[] = { | 57 | static const FunctionInfo functions[] = { |
| 57 | {0, nullptr, "InitializeBluetoothDriver"}, | 58 | {0, nullptr, "InitializeBluetoothDriver"}, |
| @@ -165,7 +166,7 @@ public: | |||
| 165 | }; | 166 | }; |
| 166 | 167 | ||
| 167 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { | 168 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 168 | std::make_shared<BtDrv>()->InstallAsService(sm); | 169 | std::make_shared<BtDrv>(system)->InstallAsService(sm); |
| 169 | std::make_shared<Bt>(system)->InstallAsService(sm); | 170 | std::make_shared<Bt>(system)->InstallAsService(sm); |
| 170 | } | 171 | } |
| 171 | 172 | ||
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 0d251c6d0..38b55300e 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/hle_ipc.h" | 10 | #include "core/hle/kernel/hle_ipc.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| @@ -17,7 +18,7 @@ namespace Service::BTM { | |||
| 17 | 18 | ||
| 18 | class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { | 19 | class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { |
| 19 | public: | 20 | public: |
| 20 | explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} { | 21 | explicit IBtmUserCore(Core::System& system_) : ServiceFramework{system_, "IBtmUserCore"} { |
| 21 | // clang-format off | 22 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 23 | static const FunctionInfo functions[] = { |
| 23 | {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, | 24 | {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, |
| @@ -106,7 +107,7 @@ private: | |||
| 106 | 107 | ||
| 107 | class BTM_USR final : public ServiceFramework<BTM_USR> { | 108 | class BTM_USR final : public ServiceFramework<BTM_USR> { |
| 108 | public: | 109 | public: |
| 109 | explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) { | 110 | explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} { |
| 110 | // clang-format off | 111 | // clang-format off |
| 111 | static const FunctionInfo functions[] = { | 112 | static const FunctionInfo functions[] = { |
| 112 | {0, &BTM_USR::GetCore, "GetCore"}, | 113 | {0, &BTM_USR::GetCore, "GetCore"}, |
| @@ -123,13 +124,11 @@ private: | |||
| 123 | rb.Push(RESULT_SUCCESS); | 124 | rb.Push(RESULT_SUCCESS); |
| 124 | rb.PushIpcInterface<IBtmUserCore>(system); | 125 | rb.PushIpcInterface<IBtmUserCore>(system); |
| 125 | } | 126 | } |
| 126 | |||
| 127 | Core::System& system; | ||
| 128 | }; | 127 | }; |
| 129 | 128 | ||
| 130 | class BTM final : public ServiceFramework<BTM> { | 129 | class BTM final : public ServiceFramework<BTM> { |
| 131 | public: | 130 | public: |
| 132 | explicit BTM() : ServiceFramework{"btm"} { | 131 | explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} { |
| 133 | // clang-format off | 132 | // clang-format off |
| 134 | static const FunctionInfo functions[] = { | 133 | static const FunctionInfo functions[] = { |
| 135 | {0, nullptr, "GetState"}, | 134 | {0, nullptr, "GetState"}, |
| @@ -206,7 +205,7 @@ public: | |||
| 206 | 205 | ||
| 207 | class BTM_DBG final : public ServiceFramework<BTM_DBG> { | 206 | class BTM_DBG final : public ServiceFramework<BTM_DBG> { |
| 208 | public: | 207 | public: |
| 209 | explicit BTM_DBG() : ServiceFramework{"btm:dbg"} { | 208 | explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} { |
| 210 | // clang-format off | 209 | // clang-format off |
| 211 | static const FunctionInfo functions[] = { | 210 | static const FunctionInfo functions[] = { |
| 212 | {0, nullptr, "AcquireDiscoveryEvent"}, | 211 | {0, nullptr, "AcquireDiscoveryEvent"}, |
| @@ -231,7 +230,7 @@ public: | |||
| 231 | 230 | ||
| 232 | class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { | 231 | class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { |
| 233 | public: | 232 | public: |
| 234 | explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} { | 233 | explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} { |
| 235 | // clang-format off | 234 | // clang-format off |
| 236 | static const FunctionInfo functions[] = { | 235 | static const FunctionInfo functions[] = { |
| 237 | {0, nullptr, "StartGamepadPairing"}, | 236 | {0, nullptr, "StartGamepadPairing"}, |
| @@ -253,7 +252,7 @@ public: | |||
| 253 | 252 | ||
| 254 | class BTM_SYS final : public ServiceFramework<BTM_SYS> { | 253 | class BTM_SYS final : public ServiceFramework<BTM_SYS> { |
| 255 | public: | 254 | public: |
| 256 | explicit BTM_SYS() : ServiceFramework{"btm:sys"} { | 255 | explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} { |
| 257 | // clang-format off | 256 | // clang-format off |
| 258 | static const FunctionInfo functions[] = { | 257 | static const FunctionInfo functions[] = { |
| 259 | {0, &BTM_SYS::GetCore, "GetCore"}, | 258 | {0, &BTM_SYS::GetCore, "GetCore"}, |
| @@ -269,14 +268,14 @@ private: | |||
| 269 | 268 | ||
| 270 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 269 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 271 | rb.Push(RESULT_SUCCESS); | 270 | rb.Push(RESULT_SUCCESS); |
| 272 | rb.PushIpcInterface<IBtmSystemCore>(); | 271 | rb.PushIpcInterface<IBtmSystemCore>(system); |
| 273 | } | 272 | } |
| 274 | }; | 273 | }; |
| 275 | 274 | ||
| 276 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { | 275 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 277 | std::make_shared<BTM>()->InstallAsService(sm); | 276 | std::make_shared<BTM>(system)->InstallAsService(sm); |
| 278 | std::make_shared<BTM_DBG>()->InstallAsService(sm); | 277 | std::make_shared<BTM_DBG>(system)->InstallAsService(sm); |
| 279 | std::make_shared<BTM_SYS>()->InstallAsService(sm); | 278 | std::make_shared<BTM_SYS>(system)->InstallAsService(sm); |
| 280 | std::make_shared<BTM_USR>(system)->InstallAsService(sm); | 279 | std::make_shared<BTM_USR>(system)->InstallAsService(sm); |
| 281 | } | 280 | } |
| 282 | 281 | ||
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index ba5749b84..5b7fe8e9b 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp | |||
| @@ -13,13 +13,13 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Capture { | 14 | namespace Service::Capture { |
| 15 | 15 | ||
| 16 | void InstallInterfaces(SM::ServiceManager& sm) { | 16 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 17 | std::make_shared<CAPS_A>()->InstallAsService(sm); | 17 | std::make_shared<CAPS_A>(system)->InstallAsService(sm); |
| 18 | std::make_shared<CAPS_C>()->InstallAsService(sm); | 18 | std::make_shared<CAPS_C>(system)->InstallAsService(sm); |
| 19 | std::make_shared<CAPS_U>()->InstallAsService(sm); | 19 | std::make_shared<CAPS_U>(system)->InstallAsService(sm); |
| 20 | std::make_shared<CAPS_SC>()->InstallAsService(sm); | 20 | std::make_shared<CAPS_SC>(system)->InstallAsService(sm); |
| 21 | std::make_shared<CAPS_SS>()->InstallAsService(sm); | 21 | std::make_shared<CAPS_SS>(system)->InstallAsService(sm); |
| 22 | std::make_shared<CAPS_SU>()->InstallAsService(sm); | 22 | std::make_shared<CAPS_SU>(system)->InstallAsService(sm); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | } // namespace Service::Capture | 25 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index b8c67b6e2..3c4290c88 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::SM { | 13 | namespace Service::SM { |
| 10 | class ServiceManager; | 14 | class ServiceManager; |
| 11 | } | 15 | } |
| @@ -87,6 +91,6 @@ static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, | |||
| 87 | "ApplicationAlbumFileEntry has incorrect size."); | 91 | "ApplicationAlbumFileEntry has incorrect size."); |
| 88 | 92 | ||
| 89 | /// Registers all Capture services with the specified service manager. | 93 | /// Registers all Capture services with the specified service manager. |
| 90 | void InstallInterfaces(SM::ServiceManager& sm); | 94 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 91 | 95 | ||
| 92 | } // namespace Service::Capture | 96 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp index a0a3b2ae3..1fe4f0e14 100644 --- a/src/core/hle/service/caps/caps_a.cpp +++ b/src/core/hle/service/caps/caps_a.cpp | |||
| @@ -8,7 +8,8 @@ namespace Service::Capture { | |||
| 8 | 8 | ||
| 9 | class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { | 9 | class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { |
| 10 | public: | 10 | public: |
| 11 | explicit IAlbumAccessorSession() : ServiceFramework{"IAlbumAccessorSession"} { | 11 | explicit IAlbumAccessorSession(Core::System& system_) |
| 12 | : ServiceFramework{system_, "IAlbumAccessorSession"} { | ||
| 12 | // clang-format off | 13 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 14 | static const FunctionInfo functions[] = { |
| 14 | {2001, nullptr, "OpenAlbumMovieReadStream"}, | 15 | {2001, nullptr, "OpenAlbumMovieReadStream"}, |
| @@ -26,7 +27,7 @@ public: | |||
| 26 | } | 27 | } |
| 27 | }; | 28 | }; |
| 28 | 29 | ||
| 29 | CAPS_A::CAPS_A() : ServiceFramework("caps:a") { | 30 | CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} { |
| 30 | // clang-format off | 31 | // clang-format off |
| 31 | static const FunctionInfo functions[] = { | 32 | static const FunctionInfo functions[] = { |
| 32 | {0, nullptr, "GetAlbumFileCount"}, | 33 | {0, nullptr, "GetAlbumFileCount"}, |
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h index cb93aad5b..389cc6dbe 100644 --- a/src/core/hle/service/caps/caps_a.h +++ b/src/core/hle/service/caps/caps_a.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,7 +18,7 @@ namespace Service::Capture { | |||
| 14 | 18 | ||
| 15 | class CAPS_A final : public ServiceFramework<CAPS_A> { | 19 | class CAPS_A final : public ServiceFramework<CAPS_A> { |
| 16 | public: | 20 | public: |
| 17 | explicit CAPS_A(); | 21 | explicit CAPS_A(Core::System& system_); |
| 18 | ~CAPS_A() override; | 22 | ~CAPS_A() override; |
| 19 | }; | 23 | }; |
| 20 | 24 | ||
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp index ab17a187e..45c1c9d30 100644 --- a/src/core/hle/service/caps/caps_c.cpp +++ b/src/core/hle/service/caps/caps_c.cpp | |||
| @@ -2,13 +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 "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 5 | #include "core/hle/service/caps/caps_c.h" | 7 | #include "core/hle/service/caps/caps_c.h" |
| 6 | 8 | ||
| 7 | namespace Service::Capture { | 9 | namespace Service::Capture { |
| 8 | 10 | ||
| 9 | class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { | 11 | class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { |
| 10 | public: | 12 | public: |
| 11 | explicit IAlbumControlSession() : ServiceFramework{"IAlbumControlSession"} { | 13 | explicit IAlbumControlSession(Core::System& system_) |
| 14 | : ServiceFramework{system_, "IAlbumControlSession"} { | ||
| 12 | // clang-format off | 15 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 14 | {2001, nullptr, "OpenAlbumMovieReadStream"}, | 17 | {2001, nullptr, "OpenAlbumMovieReadStream"}, |
| @@ -42,12 +45,12 @@ public: | |||
| 42 | } | 45 | } |
| 43 | }; | 46 | }; |
| 44 | 47 | ||
| 45 | CAPS_C::CAPS_C() : ServiceFramework("caps:c") { | 48 | CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} { |
| 46 | // clang-format off | 49 | // clang-format off |
| 47 | static const FunctionInfo functions[] = { | 50 | static const FunctionInfo functions[] = { |
| 48 | {1, nullptr, "CaptureRawImage"}, | 51 | {1, nullptr, "CaptureRawImage"}, |
| 49 | {2, nullptr, "CaptureRawImageWithTimeout"}, | 52 | {2, nullptr, "CaptureRawImageWithTimeout"}, |
| 50 | {33, nullptr, "Unknown33"}, | 53 | {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"}, |
| 51 | {1001, nullptr, "RequestTakingScreenShot"}, | 54 | {1001, nullptr, "RequestTakingScreenShot"}, |
| 52 | {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, | 55 | {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, |
| 53 | {1011, nullptr, "NotifyTakingScreenShotRefused"}, | 56 | {1011, nullptr, "NotifyTakingScreenShotRefused"}, |
| @@ -72,4 +75,16 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") { | |||
| 72 | 75 | ||
| 73 | CAPS_C::~CAPS_C() = default; | 76 | CAPS_C::~CAPS_C() = default; |
| 74 | 77 | ||
| 78 | void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) { | ||
| 79 | IPC::RequestParser rp{ctx}; | ||
| 80 | const auto library_version{rp.Pop<u64>()}; | ||
| 81 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 82 | |||
| 83 | LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", | ||
| 84 | library_version, applet_resource_user_id); | ||
| 85 | |||
| 86 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 87 | rb.Push(RESULT_SUCCESS); | ||
| 88 | } | ||
| 89 | |||
| 75 | } // namespace Service::Capture | 90 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h index a9d028689..c6d1dfdce 100644 --- a/src/core/hle/service/caps/caps_c.h +++ b/src/core/hle/service/caps/caps_c.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,8 +18,11 @@ namespace Service::Capture { | |||
| 14 | 18 | ||
| 15 | class CAPS_C final : public ServiceFramework<CAPS_C> { | 19 | class CAPS_C final : public ServiceFramework<CAPS_C> { |
| 16 | public: | 20 | public: |
| 17 | explicit CAPS_C(); | 21 | explicit CAPS_C(Core::System& system_); |
| 18 | ~CAPS_C() override; | 22 | ~CAPS_C() override; |
| 23 | |||
| 24 | private: | ||
| 25 | void SetShimLibraryVersion(Kernel::HLERequestContext& ctx); | ||
| 19 | }; | 26 | }; |
| 20 | 27 | ||
| 21 | } // namespace Service::Capture | 28 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp index 822ee96c8..d91e18e80 100644 --- a/src/core/hle/service/caps/caps_sc.cpp +++ b/src/core/hle/service/caps/caps_sc.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Capture { | 7 | namespace Service::Capture { |
| 8 | 8 | ||
| 9 | CAPS_SC::CAPS_SC() : ServiceFramework("caps:sc") { | 9 | CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {1, nullptr, "CaptureRawImage"}, | 12 | {1, nullptr, "CaptureRawImage"}, |
diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h index ac3e929ca..e79a33ee5 100644 --- a/src/core/hle/service/caps/caps_sc.h +++ b/src/core/hle/service/caps/caps_sc.h | |||
| @@ -6,15 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Core { |
| 10 | class HLERequestContext; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Capture { | 13 | namespace Service::Capture { |
| 14 | 14 | ||
| 15 | class CAPS_SC final : public ServiceFramework<CAPS_SC> { | 15 | class CAPS_SC final : public ServiceFramework<CAPS_SC> { |
| 16 | public: | 16 | public: |
| 17 | explicit CAPS_SC(); | 17 | explicit CAPS_SC(Core::System& system_); |
| 18 | ~CAPS_SC() override; | 18 | ~CAPS_SC() override; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index 24dc716e7..2b5314691 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Capture { | 7 | namespace Service::Capture { |
| 8 | 8 | ||
| 9 | CAPS_SS::CAPS_SS() : ServiceFramework("caps:ss") { | 9 | CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {201, nullptr, "SaveScreenShot"}, | 12 | {201, nullptr, "SaveScreenShot"}, |
diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h index 450686e4f..1816f7885 100644 --- a/src/core/hle/service/caps/caps_ss.h +++ b/src/core/hle/service/caps/caps_ss.h | |||
| @@ -6,15 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Kernel { | 9 | namespace Core { |
| 10 | class HLERequestContext; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Capture { | 13 | namespace Service::Capture { |
| 14 | 14 | ||
| 15 | class CAPS_SS final : public ServiceFramework<CAPS_SS> { | 15 | class CAPS_SS final : public ServiceFramework<CAPS_SS> { |
| 16 | public: | 16 | public: |
| 17 | explicit CAPS_SS(); | 17 | explicit CAPS_SS(Core::System& system_); |
| 18 | ~CAPS_SS() override; | 18 | ~CAPS_SS() override; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index fffb2ecf9..eae39eb7b 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::Capture { | 9 | namespace Service::Capture { |
| 10 | 10 | ||
| 11 | CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") { | 11 | CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} { |
| 12 | // clang-format off | 12 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, | 14 | {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, |
| @@ -25,7 +25,12 @@ CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") { | |||
| 25 | CAPS_SU::~CAPS_SU() = default; | 25 | CAPS_SU::~CAPS_SU() = default; |
| 26 | 26 | ||
| 27 | void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) { | 27 | void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) { |
| 28 | LOG_WARNING(Service_Capture, "(STUBBED) called"); | 28 | IPC::RequestParser rp{ctx}; |
| 29 | const auto library_version{rp.Pop<u64>()}; | ||
| 30 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 31 | |||
| 32 | LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", | ||
| 33 | library_version, applet_resource_user_id); | ||
| 29 | 34 | ||
| 30 | IPC::ResponseBuilder rb{ctx, 2}; | 35 | IPC::ResponseBuilder rb{ctx, 2}; |
| 31 | rb.Push(RESULT_SUCCESS); | 36 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 62c9603a9..b366fdb13 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,7 +18,7 @@ namespace Service::Capture { | |||
| 14 | 18 | ||
| 15 | class CAPS_SU final : public ServiceFramework<CAPS_SU> { | 19 | class CAPS_SU final : public ServiceFramework<CAPS_SU> { |
| 16 | public: | 20 | public: |
| 17 | explicit CAPS_SU(); | 21 | explicit CAPS_SU(Core::System& system_); |
| 18 | ~CAPS_SU() override; | 22 | ~CAPS_SU() override; |
| 19 | 23 | ||
| 20 | private: | 24 | private: |
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp index f36d8de2d..842316a2e 100644 --- a/src/core/hle/service/caps/caps_u.cpp +++ b/src/core/hle/service/caps/caps_u.cpp | |||
| @@ -12,8 +12,8 @@ namespace Service::Capture { | |||
| 12 | class IAlbumAccessorApplicationSession final | 12 | class IAlbumAccessorApplicationSession final |
| 13 | : public ServiceFramework<IAlbumAccessorApplicationSession> { | 13 | : public ServiceFramework<IAlbumAccessorApplicationSession> { |
| 14 | public: | 14 | public: |
| 15 | explicit IAlbumAccessorApplicationSession() | 15 | explicit IAlbumAccessorApplicationSession(Core::System& system_) |
| 16 | : ServiceFramework{"IAlbumAccessorApplicationSession"} { | 16 | : ServiceFramework{system_, "IAlbumAccessorApplicationSession"} { |
| 17 | // clang-format off | 17 | // clang-format off |
| 18 | static const FunctionInfo functions[] = { | 18 | static const FunctionInfo functions[] = { |
| 19 | {2001, nullptr, "OpenAlbumMovieReadStream"}, | 19 | {2001, nullptr, "OpenAlbumMovieReadStream"}, |
| @@ -28,11 +28,10 @@ public: | |||
| 28 | } | 28 | } |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | CAPS_U::CAPS_U() : ServiceFramework("caps:u") { | 31 | CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} { |
| 32 | // clang-format off | 32 | // clang-format off |
| 33 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| 34 | {31, nullptr, "GetShimLibraryVersion"}, | 34 | {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"}, |
| 35 | {32, nullptr, "SetShimLibraryVersion"}, | ||
| 36 | {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, | 35 | {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, |
| 37 | {103, nullptr, "DeleteAlbumContentsFileForApplication"}, | 36 | {103, nullptr, "DeleteAlbumContentsFileForApplication"}, |
| 38 | {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, | 37 | {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, |
| @@ -42,7 +41,7 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") { | |||
| 42 | {130, nullptr, "PrecheckToCreateContentsForApplication"}, | 41 | {130, nullptr, "PrecheckToCreateContentsForApplication"}, |
| 43 | {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, | 42 | {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, |
| 44 | {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, | 43 | {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, |
| 45 | {142, nullptr, "GetAlbumFileList3AaeAruid"}, | 44 | {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"}, |
| 46 | {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, | 45 | {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, |
| 47 | {60002, nullptr, "OpenAccessorSessionForApplication"}, | 46 | {60002, nullptr, "OpenAccessorSessionForApplication"}, |
| 48 | }; | 47 | }; |
| @@ -53,6 +52,18 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") { | |||
| 53 | 52 | ||
| 54 | CAPS_U::~CAPS_U() = default; | 53 | CAPS_U::~CAPS_U() = default; |
| 55 | 54 | ||
| 55 | void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) { | ||
| 56 | IPC::RequestParser rp{ctx}; | ||
| 57 | const auto library_version{rp.Pop<u64>()}; | ||
| 58 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 59 | |||
| 60 | LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", | ||
| 61 | library_version, applet_resource_user_id); | ||
| 62 | |||
| 63 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 64 | rb.Push(RESULT_SUCCESS); | ||
| 65 | } | ||
| 66 | |||
| 56 | void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) { | 67 | void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) { |
| 57 | // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an | 68 | // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an |
| 58 | // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total | 69 | // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total |
| @@ -66,17 +77,24 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c | |||
| 66 | 77 | ||
| 67 | // TODO: Update this when we implement the album. | 78 | // TODO: Update this when we implement the album. |
| 68 | // Currently we do not have a method of accessing album entries, set this to 0 for now. | 79 | // Currently we do not have a method of accessing album entries, set this to 0 for now. |
| 69 | constexpr s32 total_entries{0}; | 80 | constexpr u32 total_entries_1{}; |
| 81 | constexpr u32 total_entries_2{}; | ||
| 70 | 82 | ||
| 71 | LOG_WARNING(Service_Capture, | 83 | LOG_WARNING( |
| 72 | "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " | 84 | Service_Capture, |
| 73 | "end_posix_time={}, applet_resource_user_id={}, total_entries={}", | 85 | "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " |
| 74 | pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, | 86 | "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}", |
| 75 | total_entries); | 87 | pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, |
| 88 | total_entries_1, total_entries_2); | ||
| 76 | 89 | ||
| 77 | IPC::ResponseBuilder rb{ctx, 3}; | 90 | IPC::ResponseBuilder rb{ctx, 4}; |
| 78 | rb.Push(RESULT_SUCCESS); | 91 | rb.Push(RESULT_SUCCESS); |
| 79 | rb.Push(total_entries); | 92 | rb.Push(total_entries_1); |
| 93 | rb.Push(total_entries_2); | ||
| 94 | } | ||
| 95 | |||
| 96 | void CAPS_U::GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx) { | ||
| 97 | GetAlbumContentsFileListForApplication(ctx); | ||
| 80 | } | 98 | } |
| 81 | 99 | ||
| 82 | } // namespace Service::Capture | 100 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h index 689364de4..e7e0d8775 100644 --- a/src/core/hle/service/caps/caps_u.h +++ b/src/core/hle/service/caps/caps_u.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -14,11 +18,13 @@ namespace Service::Capture { | |||
| 14 | 18 | ||
| 15 | class CAPS_U final : public ServiceFramework<CAPS_U> { | 19 | class CAPS_U final : public ServiceFramework<CAPS_U> { |
| 16 | public: | 20 | public: |
| 17 | explicit CAPS_U(); | 21 | explicit CAPS_U(Core::System& system_); |
| 18 | ~CAPS_U() override; | 22 | ~CAPS_U() override; |
| 19 | 23 | ||
| 20 | private: | 24 | private: |
| 25 | void SetShimLibraryVersion(Kernel::HLERequestContext& ctx); | ||
| 21 | void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); | 26 | void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); |
| 27 | void GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx); | ||
| 22 | }; | 28 | }; |
| 23 | 29 | ||
| 24 | } // namespace Service::Capture | 30 | } // namespace Service::Capture |
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp index 4ec8c3093..4924c61c3 100644 --- a/src/core/hle/service/erpt/erpt.cpp +++ b/src/core/hle/service/erpt/erpt.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::ERPT { | |||
| 12 | 12 | ||
| 13 | class ErrorReportContext final : public ServiceFramework<ErrorReportContext> { | 13 | class ErrorReportContext final : public ServiceFramework<ErrorReportContext> { |
| 14 | public: | 14 | public: |
| 15 | explicit ErrorReportContext() : ServiceFramework{"erpt:c"} { | 15 | explicit ErrorReportContext(Core::System& system_) : ServiceFramework{system_, "erpt:c"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SubmitContext"}, | 18 | {0, nullptr, "SubmitContext"}, |
| @@ -35,7 +35,7 @@ public: | |||
| 35 | 35 | ||
| 36 | class ErrorReportSession final : public ServiceFramework<ErrorReportSession> { | 36 | class ErrorReportSession final : public ServiceFramework<ErrorReportSession> { |
| 37 | public: | 37 | public: |
| 38 | explicit ErrorReportSession() : ServiceFramework{"erpt:r"} { | 38 | explicit ErrorReportSession(Core::System& system_) : ServiceFramework{system_, "erpt:r"} { |
| 39 | // clang-format off | 39 | // clang-format off |
| 40 | static const FunctionInfo functions[] = { | 40 | static const FunctionInfo functions[] = { |
| 41 | {0, nullptr, "OpenReport"}, | 41 | {0, nullptr, "OpenReport"}, |
| @@ -48,9 +48,9 @@ public: | |||
| 48 | } | 48 | } |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | void InstallInterfaces(SM::ServiceManager& sm) { | 51 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 52 | std::make_shared<ErrorReportContext>()->InstallAsService(sm); | 52 | std::make_shared<ErrorReportContext>(system)->InstallAsService(sm); |
| 53 | std::make_shared<ErrorReportSession>()->InstallAsService(sm); | 53 | std::make_shared<ErrorReportSession>(system)->InstallAsService(sm); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | } // namespace Service::ERPT | 56 | } // namespace Service::ERPT |
diff --git a/src/core/hle/service/erpt/erpt.h b/src/core/hle/service/erpt/erpt.h index de439ab6d..8cd5c081f 100644 --- a/src/core/hle/service/erpt/erpt.h +++ b/src/core/hle/service/erpt/erpt.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::ERPT { | 15 | namespace Service::ERPT { |
| 12 | 16 | ||
| 13 | /// Registers all ERPT services with the specified service manager. | 17 | /// Registers all ERPT services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& sm); | 18 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::ERPT | 20 | } // namespace Service::ERPT |
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index c2737a365..26d1e3306 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp | |||
| @@ -14,7 +14,7 @@ constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3}; | |||
| 14 | 14 | ||
| 15 | class ETicket final : public ServiceFramework<ETicket> { | 15 | class ETicket final : public ServiceFramework<ETicket> { |
| 16 | public: | 16 | public: |
| 17 | explicit ETicket() : ServiceFramework{"es"} { | 17 | explicit ETicket(Core::System& system_) : ServiceFramework{system_, "es"} { |
| 18 | // clang-format off | 18 | // clang-format off |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {1, &ETicket::ImportTicket, "ImportTicket"}, | 20 | {1, &ETicket::ImportTicket, "ImportTicket"}, |
| @@ -305,8 +305,8 @@ private: | |||
| 305 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); | 305 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 308 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 309 | std::make_shared<ETicket>()->InstallAsService(service_manager); | 309 | std::make_shared<ETicket>(system)->InstallAsService(service_manager); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | } // namespace Service::ES | 312 | } // namespace Service::ES |
diff --git a/src/core/hle/service/es/es.h b/src/core/hle/service/es/es.h index afe70465b..2a7b27d12 100644 --- a/src/core/hle/service/es/es.h +++ b/src/core/hle/service/es/es.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::ES { | 15 | namespace Service::ES { |
| 12 | 16 | ||
| 13 | /// Registers all ES services with the specified service manager. | 17 | /// Registers all ES services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::ES | 20 | } // namespace Service::ES |
diff --git a/src/core/hle/service/eupld/eupld.cpp b/src/core/hle/service/eupld/eupld.cpp index 0d6d244f4..2d650b1b7 100644 --- a/src/core/hle/service/eupld/eupld.cpp +++ b/src/core/hle/service/eupld/eupld.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::EUPLD { | |||
| 12 | 12 | ||
| 13 | class ErrorUploadContext final : public ServiceFramework<ErrorUploadContext> { | 13 | class ErrorUploadContext final : public ServiceFramework<ErrorUploadContext> { |
| 14 | public: | 14 | public: |
| 15 | explicit ErrorUploadContext() : ServiceFramework{"eupld:c"} { | 15 | explicit ErrorUploadContext(Core::System& system_) : ServiceFramework{system_, "eupld:c"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SetUrl"}, | 18 | {0, nullptr, "SetUrl"}, |
| @@ -29,7 +29,7 @@ public: | |||
| 29 | 29 | ||
| 30 | class ErrorUploadRequest final : public ServiceFramework<ErrorUploadRequest> { | 30 | class ErrorUploadRequest final : public ServiceFramework<ErrorUploadRequest> { |
| 31 | public: | 31 | public: |
| 32 | explicit ErrorUploadRequest() : ServiceFramework{"eupld:r"} { | 32 | explicit ErrorUploadRequest(Core::System& system_) : ServiceFramework{system_, "eupld:r"} { |
| 33 | // clang-format off | 33 | // clang-format off |
| 34 | static const FunctionInfo functions[] = { | 34 | static const FunctionInfo functions[] = { |
| 35 | {0, nullptr, "Initialize"}, | 35 | {0, nullptr, "Initialize"}, |
| @@ -45,9 +45,9 @@ public: | |||
| 45 | } | 45 | } |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | void InstallInterfaces(SM::ServiceManager& sm) { | 48 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 49 | std::make_shared<ErrorUploadContext>()->InstallAsService(sm); | 49 | std::make_shared<ErrorUploadContext>(system)->InstallAsService(sm); |
| 50 | std::make_shared<ErrorUploadRequest>()->InstallAsService(sm); | 50 | std::make_shared<ErrorUploadRequest>(system)->InstallAsService(sm); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | } // namespace Service::EUPLD | 53 | } // namespace Service::EUPLD |
diff --git a/src/core/hle/service/eupld/eupld.h b/src/core/hle/service/eupld/eupld.h index 6eef2c15f..539993a9d 100644 --- a/src/core/hle/service/eupld/eupld.h +++ b/src/core/hle/service/eupld/eupld.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::EUPLD { | 15 | namespace Service::EUPLD { |
| 12 | 16 | ||
| 13 | /// Registers all EUPLD services with the specified service manager. | 17 | /// Registers all EUPLD services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& sm); | 18 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::EUPLD | 20 | } // namespace Service::EUPLD |
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 2546d7595..13147472e 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -20,8 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | namespace Service::Fatal { | 21 | namespace Service::Fatal { |
| 22 | 22 | ||
| 23 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) | 23 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 24 | : ServiceFramework(name), module(std::move(module)), system(system) {} | 24 | const char* name) |
| 25 | : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||
| 25 | 26 | ||
| 26 | Module::Interface::~Interface() = default; | 27 | Module::Interface::~Interface() = default; |
| 27 | 28 | ||
| @@ -110,8 +111,9 @@ static void GenerateErrorReport(Core::System& system, ResultCode error_code, | |||
| 110 | 111 | ||
| 111 | static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type, | 112 | static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type, |
| 112 | const FatalInfo& info) { | 113 | const FatalInfo& info) { |
| 113 | LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", | 114 | LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", fatal_type, |
| 114 | static_cast<u32>(fatal_type), error_code.raw); | 115 | error_code.raw); |
| 116 | |||
| 115 | switch (fatal_type) { | 117 | switch (fatal_type) { |
| 116 | case FatalType::ErrorReportAndScreen: | 118 | case FatalType::ErrorReportAndScreen: |
| 117 | GenerateErrorReport(system, error_code, info); | 119 | GenerateErrorReport(system, error_code, info); |
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index bd9339dfc..2095bf89f 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h | |||
| @@ -16,7 +16,8 @@ class Module final { | |||
| 16 | public: | 16 | public: |
| 17 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 18 | public: | 18 | public: |
| 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 20 | const char* name); | ||
| 20 | ~Interface() override; | 21 | ~Interface() override; |
| 21 | 22 | ||
| 22 | void ThrowFatal(Kernel::HLERequestContext& ctx); | 23 | void ThrowFatal(Kernel::HLERequestContext& ctx); |
| @@ -25,7 +26,6 @@ public: | |||
| 25 | 26 | ||
| 26 | protected: | 27 | protected: |
| 27 | std::shared_ptr<Module> module; | 28 | std::shared_ptr<Module> module; |
| 28 | Core::System& system; | ||
| 29 | }; | 29 | }; |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp index 066ccf6b0..8672b85dc 100644 --- a/src/core/hle/service/fatal/fatal_p.cpp +++ b/src/core/hle/service/fatal/fatal_p.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Fatal { | 7 | namespace Service::Fatal { |
| 8 | 8 | ||
| 9 | Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system) | 9 | Fatal_P::Fatal_P(std::shared_ptr<Module> module_, Core::System& system_) |
| 10 | : Module::Interface(std::move(module), system, "fatal:p") {} | 10 | : Interface(std::move(module_), system_, "fatal:p") {} |
| 11 | 11 | ||
| 12 | Fatal_P::~Fatal_P() = default; | 12 | Fatal_P::~Fatal_P() = default; |
| 13 | 13 | ||
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h index c6d953cb5..ffa5b7b98 100644 --- a/src/core/hle/service/fatal/fatal_p.h +++ b/src/core/hle/service/fatal/fatal_p.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Fatal { | |||
| 10 | 10 | ||
| 11 | class Fatal_P final : public Module::Interface { | 11 | class Fatal_P final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system); | 13 | explicit Fatal_P(std::shared_ptr<Module> module_, Core::System& system_); |
| 14 | ~Fatal_P() override; | 14 | ~Fatal_P() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index 8d72ed485..82993938a 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Fatal { | 7 | namespace Service::Fatal { |
| 8 | 8 | ||
| 9 | Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system) | 9 | Fatal_U::Fatal_U(std::shared_ptr<Module> module_, Core::System& system_) |
| 10 | : Module::Interface(std::move(module), system, "fatal:u") { | 10 | : Interface(std::move(module_), system_, "fatal:u") { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, | 12 | {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, |
| 13 | {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, | 13 | {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, |
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h index 34c5c7f95..0b58c9112 100644 --- a/src/core/hle/service/fatal/fatal_u.h +++ b/src/core/hle/service/fatal/fatal_u.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Fatal { | |||
| 10 | 10 | ||
| 11 | class Fatal_U final : public Module::Interface { | 11 | class Fatal_U final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system); | 13 | explicit Fatal_U(std::shared_ptr<Module> module_, Core::System& system_); |
| 14 | ~Fatal_U() override; | 14 | ~Fatal_U() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp index e461274c1..9dc1bc52e 100644 --- a/src/core/hle/service/fgm/fgm.cpp +++ b/src/core/hle/service/fgm/fgm.cpp | |||
| @@ -14,7 +14,7 @@ namespace Service::FGM { | |||
| 14 | 14 | ||
| 15 | class IRequest final : public ServiceFramework<IRequest> { | 15 | class IRequest final : public ServiceFramework<IRequest> { |
| 16 | public: | 16 | public: |
| 17 | explicit IRequest() : ServiceFramework{"IRequest"} { | 17 | explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} { |
| 18 | // clang-format off | 18 | // clang-format off |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {0, nullptr, "Initialize"}, | 20 | {0, nullptr, "Initialize"}, |
| @@ -30,7 +30,7 @@ public: | |||
| 30 | 30 | ||
| 31 | class FGM final : public ServiceFramework<FGM> { | 31 | class FGM final : public ServiceFramework<FGM> { |
| 32 | public: | 32 | public: |
| 33 | explicit FGM(const char* name) : ServiceFramework{name} { | 33 | explicit FGM(Core::System& system_, const char* name) : ServiceFramework{system_, name} { |
| 34 | // clang-format off | 34 | // clang-format off |
| 35 | static const FunctionInfo functions[] = { | 35 | static const FunctionInfo functions[] = { |
| 36 | {0, &FGM::Initialize, "Initialize"}, | 36 | {0, &FGM::Initialize, "Initialize"}, |
| @@ -46,13 +46,13 @@ private: | |||
| 46 | 46 | ||
| 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 48 | rb.Push(RESULT_SUCCESS); | 48 | rb.Push(RESULT_SUCCESS); |
| 49 | rb.PushIpcInterface<IRequest>(); | 49 | rb.PushIpcInterface<IRequest>(system); |
| 50 | } | 50 | } |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | class FGM_DBG final : public ServiceFramework<FGM_DBG> { | 53 | class FGM_DBG final : public ServiceFramework<FGM_DBG> { |
| 54 | public: | 54 | public: |
| 55 | explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} { | 55 | explicit FGM_DBG(Core::System& system_) : ServiceFramework{system_, "fgm:dbg"} { |
| 56 | // clang-format off | 56 | // clang-format off |
| 57 | static const FunctionInfo functions[] = { | 57 | static const FunctionInfo functions[] = { |
| 58 | {0, nullptr, "Initialize"}, | 58 | {0, nullptr, "Initialize"}, |
| @@ -65,11 +65,11 @@ public: | |||
| 65 | } | 65 | } |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | void InstallInterfaces(SM::ServiceManager& sm) { | 68 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 69 | std::make_shared<FGM>("fgm")->InstallAsService(sm); | 69 | std::make_shared<FGM>(system, "fgm")->InstallAsService(sm); |
| 70 | std::make_shared<FGM>("fgm:0")->InstallAsService(sm); | 70 | std::make_shared<FGM>(system, "fgm:0")->InstallAsService(sm); |
| 71 | std::make_shared<FGM>("fgm:9")->InstallAsService(sm); | 71 | std::make_shared<FGM>(system, "fgm:9")->InstallAsService(sm); |
| 72 | std::make_shared<FGM_DBG>()->InstallAsService(sm); | 72 | std::make_shared<FGM_DBG>(system)->InstallAsService(sm); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | } // namespace Service::FGM | 75 | } // namespace Service::FGM |
diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h index e59691264..75978f2ed 100644 --- a/src/core/hle/service/fgm/fgm.h +++ b/src/core/hle/service/fgm/fgm.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::FGM { | 15 | namespace Service::FGM { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::FGM | 19 | } // namespace Service::FGM |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 54a5fb84b..b15c737e1 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); | 81 | auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); |
| 82 | if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { | 82 | if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { |
| 83 | return FileSys::ERROR_PATH_NOT_FOUND; | 83 | return FileSys::ERROR_PATH_NOT_FOUND; |
| 84 | } | 84 | } |
| 85 | if (!dir->DeleteFile(Common::FS::GetFilename(path))) { | 85 | if (!dir->DeleteFile(Common::FS::GetFilename(path))) { |
| @@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons | |||
| 93 | ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { | 93 | ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { |
| 94 | std::string path(Common::FS::SanitizePath(path_)); | 94 | std::string path(Common::FS::SanitizePath(path_)); |
| 95 | auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); | 95 | auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); |
| 96 | if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) | 96 | if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) { |
| 97 | dir = backing; | 97 | dir = backing; |
| 98 | } | ||
| 98 | auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); | 99 | auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); |
| 99 | if (new_dir == nullptr) { | 100 | if (new_dir == nullptr) { |
| 100 | // TODO(DarkLordZach): Find a better error code for this | 101 | // TODO(DarkLordZach): Find a better error code for this |
| @@ -297,10 +298,35 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() | |||
| 297 | return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); | 298 | return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); |
| 298 | } | 299 | } |
| 299 | 300 | ||
| 301 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS( | ||
| 302 | u64 title_id, FileSys::ContentRecordType type) const { | ||
| 303 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id); | ||
| 304 | |||
| 305 | if (romfs_factory == nullptr) { | ||
| 306 | // TODO: Find a better error code for this | ||
| 307 | return RESULT_UNKNOWN; | ||
| 308 | } | ||
| 309 | |||
| 310 | return romfs_factory->OpenPatchedRomFS(title_id, type); | ||
| 311 | } | ||
| 312 | |||
| 313 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFSWithProgramIndex( | ||
| 314 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) const { | ||
| 315 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id, | ||
| 316 | program_index); | ||
| 317 | |||
| 318 | if (romfs_factory == nullptr) { | ||
| 319 | // TODO: Find a better error code for this | ||
| 320 | return RESULT_UNKNOWN; | ||
| 321 | } | ||
| 322 | |||
| 323 | return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); | ||
| 324 | } | ||
| 325 | |||
| 300 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( | 326 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( |
| 301 | u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { | 327 | u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { |
| 302 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", | 328 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", |
| 303 | title_id, static_cast<u8>(storage_id), static_cast<u8>(type)); | 329 | title_id, storage_id, type); |
| 304 | 330 | ||
| 305 | if (romfs_factory == nullptr) { | 331 | if (romfs_factory == nullptr) { |
| 306 | // TODO(bunnei): Find a better error code for this | 332 | // TODO(bunnei): Find a better error code for this |
| @@ -312,8 +338,8 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( | |||
| 312 | 338 | ||
| 313 | ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData( | 339 | ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData( |
| 314 | FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const { | 340 | FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const { |
| 315 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", | 341 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, |
| 316 | static_cast<u8>(space), save_struct.DebugInfo()); | 342 | save_struct.DebugInfo()); |
| 317 | 343 | ||
| 318 | if (save_data_factory == nullptr) { | 344 | if (save_data_factory == nullptr) { |
| 319 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 345 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| @@ -324,8 +350,8 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData( | |||
| 324 | 350 | ||
| 325 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData( | 351 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData( |
| 326 | FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const { | 352 | FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const { |
| 327 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", | 353 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space, |
| 328 | static_cast<u8>(space), attribute.DebugInfo()); | 354 | attribute.DebugInfo()); |
| 329 | 355 | ||
| 330 | if (save_data_factory == nullptr) { | 356 | if (save_data_factory == nullptr) { |
| 331 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 357 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| @@ -336,7 +362,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData( | |||
| 336 | 362 | ||
| 337 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace( | 363 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace( |
| 338 | FileSys::SaveDataSpaceId space) const { | 364 | FileSys::SaveDataSpaceId space) const { |
| 339 | LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); | 365 | LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space); |
| 340 | 366 | ||
| 341 | if (save_data_factory == nullptr) { | 367 | if (save_data_factory == nullptr) { |
| 342 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 368 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| @@ -357,7 +383,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const { | |||
| 357 | 383 | ||
| 358 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition( | 384 | ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition( |
| 359 | FileSys::BisPartitionId id) const { | 385 | FileSys::BisPartitionId id) const { |
| 360 | LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id)); | 386 | LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id); |
| 361 | 387 | ||
| 362 | if (bis_factory == nullptr) { | 388 | if (bis_factory == nullptr) { |
| 363 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 389 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| @@ -373,7 +399,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition( | |||
| 373 | 399 | ||
| 374 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage( | 400 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage( |
| 375 | FileSys::BisPartitionId id) const { | 401 | FileSys::BisPartitionId id) const { |
| 376 | LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id)); | 402 | LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id); |
| 377 | 403 | ||
| 378 | if (bis_factory == nullptr) { | 404 | if (bis_factory == nullptr) { |
| 379 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 405 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| @@ -454,7 +480,9 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy | |||
| 454 | const auto res = system.GetAppLoader().ReadControlData(nacp); | 480 | const auto res = system.GetAppLoader().ReadControlData(nacp); |
| 455 | 481 | ||
| 456 | if (res != Loader::ResultStatus::Success) { | 482 | if (res != Loader::ResultStatus::Success) { |
| 457 | FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; | 483 | const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), |
| 484 | system.GetFileSystemController(), | ||
| 485 | system.GetContentProvider()}; | ||
| 458 | const auto metadata = pm.GetControlMetadata(); | 486 | const auto metadata = pm.GetControlMetadata(); |
| 459 | const auto& nacp_unique = metadata.first; | 487 | const auto& nacp_unique = metadata.first; |
| 460 | 488 | ||
| @@ -714,7 +742,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 714 | } | 742 | } |
| 715 | 743 | ||
| 716 | if (save_data_factory == nullptr) { | 744 | if (save_data_factory == nullptr) { |
| 717 | save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); | 745 | save_data_factory = |
| 746 | std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory)); | ||
| 718 | } | 747 | } |
| 719 | 748 | ||
| 720 | if (sdmc_factory == nullptr) { | 749 | if (sdmc_factory == nullptr) { |
| @@ -725,10 +754,9 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 725 | } | 754 | } |
| 726 | 755 | ||
| 727 | void InstallInterfaces(Core::System& system) { | 756 | void InstallInterfaces(Core::System& system) { |
| 728 | std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); | 757 | std::make_shared<FSP_LDR>(system)->InstallAsService(system.ServiceManager()); |
| 729 | std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); | 758 | std::make_shared<FSP_PR>(system)->InstallAsService(system.ServiceManager()); |
| 730 | std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter()) | 759 | std::make_shared<FSP_SRV>(system)->InstallAsService(system.ServiceManager()); |
| 731 | ->InstallAsService(system.ServiceManager()); | ||
| 732 | } | 760 | } |
| 733 | 761 | ||
| 734 | } // namespace Service::FileSystem | 762 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 6dbbf0b2b..7102d3f9a 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -66,6 +66,10 @@ public: | |||
| 66 | 66 | ||
| 67 | void SetPackedUpdate(FileSys::VirtualFile update_raw); | 67 | void SetPackedUpdate(FileSys::VirtualFile update_raw); |
| 68 | ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const; | 68 | ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const; |
| 69 | ResultVal<FileSys::VirtualFile> OpenPatchedRomFS(u64 title_id, | ||
| 70 | FileSys::ContentRecordType type) const; | ||
| 71 | ResultVal<FileSys::VirtualFile> OpenPatchedRomFSWithProgramIndex( | ||
| 72 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) const; | ||
| 69 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | 73 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, |
| 70 | FileSys::ContentRecordType type) const; | 74 | FileSys::ContentRecordType type) const; |
| 71 | ResultVal<FileSys::VirtualDir> CreateSaveData( | 75 | ResultVal<FileSys::VirtualDir> CreateSaveData( |
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp index fb487d5bc..1f6c17ba5 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.cpp +++ b/src/core/hle/service/filesystem/fsp_ldr.cpp | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | namespace Service::FileSystem { | 8 | namespace Service::FileSystem { |
| 9 | 9 | ||
| 10 | FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} { | 10 | FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} { |
| 11 | // clang-format off | 11 | // clang-format off |
| 12 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 13 | {0, nullptr, "OpenCodeFileSystem"}, | 13 | {0, nullptr, "OpenCodeFileSystem"}, |
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h index 8210b7729..d6432a0e1 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.h +++ b/src/core/hle/service/filesystem/fsp_ldr.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::FileSystem { | 13 | namespace Service::FileSystem { |
| 10 | 14 | ||
| 11 | class FSP_LDR final : public ServiceFramework<FSP_LDR> { | 15 | class FSP_LDR final : public ServiceFramework<FSP_LDR> { |
| 12 | public: | 16 | public: |
| 13 | explicit FSP_LDR(); | 17 | explicit FSP_LDR(Core::System& system_); |
| 14 | ~FSP_LDR() override; | 18 | ~FSP_LDR() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp index 378201610..00e4d1662 100644 --- a/src/core/hle/service/filesystem/fsp_pr.cpp +++ b/src/core/hle/service/filesystem/fsp_pr.cpp | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | namespace Service::FileSystem { | 8 | namespace Service::FileSystem { |
| 9 | 9 | ||
| 10 | FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} { | 10 | FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} { |
| 11 | // clang-format off | 11 | // clang-format off |
| 12 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 13 | {0, nullptr, "RegisterProgram"}, | 13 | {0, nullptr, "RegisterProgram"}, |
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h index 556ae5ce9..9e622518c 100644 --- a/src/core/hle/service/filesystem/fsp_pr.h +++ b/src/core/hle/service/filesystem/fsp_pr.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::FileSystem { | 13 | namespace Service::FileSystem { |
| 10 | 14 | ||
| 11 | class FSP_PR final : public ServiceFramework<FSP_PR> { | 15 | class FSP_PR final : public ServiceFramework<FSP_PR> { |
| 12 | public: | 16 | public: |
| 13 | explicit FSP_PR(); | 17 | explicit FSP_PR(Core::System& system_); |
| 14 | ~FSP_PR() override; | 18 | ~FSP_PR() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 649128be4..9cc260515 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/hex_util.h" | 14 | #include "common/hex_util.h" |
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/string_util.h" | 16 | #include "common/string_util.h" |
| 17 | #include "core/core.h" | ||
| 17 | #include "core/file_sys/directory.h" | 18 | #include "core/file_sys/directory.h" |
| 18 | #include "core/file_sys/errors.h" | 19 | #include "core/file_sys/errors.h" |
| 19 | #include "core/file_sys/mode.h" | 20 | #include "core/file_sys/mode.h" |
| @@ -56,8 +57,8 @@ enum class FileSystemType : u8 { | |||
| 56 | 57 | ||
| 57 | class IStorage final : public ServiceFramework<IStorage> { | 58 | class IStorage final : public ServiceFramework<IStorage> { |
| 58 | public: | 59 | public: |
| 59 | explicit IStorage(FileSys::VirtualFile backend_) | 60 | explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) |
| 60 | : ServiceFramework("IStorage"), backend(std::move(backend_)) { | 61 | : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { |
| 61 | static const FunctionInfo functions[] = { | 62 | static const FunctionInfo functions[] = { |
| 62 | {0, &IStorage::Read, "Read"}, | 63 | {0, &IStorage::Read, "Read"}, |
| 63 | {1, nullptr, "Write"}, | 64 | {1, nullptr, "Write"}, |
| @@ -114,8 +115,8 @@ private: | |||
| 114 | 115 | ||
| 115 | class IFile final : public ServiceFramework<IFile> { | 116 | class IFile final : public ServiceFramework<IFile> { |
| 116 | public: | 117 | public: |
| 117 | explicit IFile(FileSys::VirtualFile backend_) | 118 | explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) |
| 118 | : ServiceFramework("IFile"), backend(std::move(backend_)) { | 119 | : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { |
| 119 | static const FunctionInfo functions[] = { | 120 | static const FunctionInfo functions[] = { |
| 120 | {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, | 121 | {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, |
| 121 | {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, | 122 | {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, |
| @@ -246,8 +247,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec | |||
| 246 | 247 | ||
| 247 | class IDirectory final : public ServiceFramework<IDirectory> { | 248 | class IDirectory final : public ServiceFramework<IDirectory> { |
| 248 | public: | 249 | public: |
| 249 | explicit IDirectory(FileSys::VirtualDir backend_) | 250 | explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_) |
| 250 | : ServiceFramework("IDirectory"), backend(std::move(backend_)) { | 251 | : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { |
| 251 | static const FunctionInfo functions[] = { | 252 | static const FunctionInfo functions[] = { |
| 252 | {0, &IDirectory::Read, "Read"}, | 253 | {0, &IDirectory::Read, "Read"}, |
| 253 | {1, &IDirectory::GetEntryCount, "GetEntryCount"}, | 254 | {1, &IDirectory::GetEntryCount, "GetEntryCount"}, |
| @@ -302,8 +303,9 @@ private: | |||
| 302 | 303 | ||
| 303 | class IFileSystem final : public ServiceFramework<IFileSystem> { | 304 | class IFileSystem final : public ServiceFramework<IFileSystem> { |
| 304 | public: | 305 | public: |
| 305 | explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size) | 306 | explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) |
| 306 | : ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) { | 307 | : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( |
| 308 | size_)} { | ||
| 307 | static const FunctionInfo functions[] = { | 309 | static const FunctionInfo functions[] = { |
| 308 | {0, &IFileSystem::CreateFile, "CreateFile"}, | 310 | {0, &IFileSystem::CreateFile, "CreateFile"}, |
| 309 | {1, &IFileSystem::DeleteFile, "DeleteFile"}, | 311 | {1, &IFileSystem::DeleteFile, "DeleteFile"}, |
| @@ -411,7 +413,7 @@ public: | |||
| 411 | 413 | ||
| 412 | const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); | 414 | const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); |
| 413 | 415 | ||
| 414 | LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, static_cast<u32>(mode)); | 416 | LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); |
| 415 | 417 | ||
| 416 | auto result = backend.OpenFile(name, mode); | 418 | auto result = backend.OpenFile(name, mode); |
| 417 | if (result.Failed()) { | 419 | if (result.Failed()) { |
| @@ -420,7 +422,7 @@ public: | |||
| 420 | return; | 422 | return; |
| 421 | } | 423 | } |
| 422 | 424 | ||
| 423 | auto file = std::make_shared<IFile>(result.Unwrap()); | 425 | auto file = std::make_shared<IFile>(system, result.Unwrap()); |
| 424 | 426 | ||
| 425 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 427 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 426 | rb.Push(RESULT_SUCCESS); | 428 | rb.Push(RESULT_SUCCESS); |
| @@ -445,7 +447,7 @@ public: | |||
| 445 | return; | 447 | return; |
| 446 | } | 448 | } |
| 447 | 449 | ||
| 448 | auto directory = std::make_shared<IDirectory>(result.Unwrap()); | 450 | auto directory = std::make_shared<IDirectory>(system, result.Unwrap()); |
| 449 | 451 | ||
| 450 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 452 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 451 | rb.Push(RESULT_SUCCESS); | 453 | rb.Push(RESULT_SUCCESS); |
| @@ -500,8 +502,9 @@ private: | |||
| 500 | 502 | ||
| 501 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | 503 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { |
| 502 | public: | 504 | public: |
| 503 | explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc) | 505 | explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space, |
| 504 | : ServiceFramework("ISaveDataInfoReader"), fsc(fsc) { | 506 | FileSystemController& fsc_) |
| 507 | : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} { | ||
| 505 | static const FunctionInfo functions[] = { | 508 | static const FunctionInfo functions[] = { |
| 506 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, | 509 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, |
| 507 | }; | 510 | }; |
| @@ -550,8 +553,7 @@ private: | |||
| 550 | const auto save_root = fsc.OpenSaveDataSpace(space); | 553 | const auto save_root = fsc.OpenSaveDataSpace(space); |
| 551 | 554 | ||
| 552 | if (save_root.Failed() || *save_root == nullptr) { | 555 | if (save_root.Failed() || *save_root == nullptr) { |
| 553 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", | 556 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); |
| 554 | static_cast<u8>(space)); | ||
| 555 | return; | 557 | return; |
| 556 | } | 558 | } |
| 557 | 559 | ||
| @@ -650,8 +652,9 @@ private: | |||
| 650 | u64 next_entry_index = 0; | 652 | u64 next_entry_index = 0; |
| 651 | }; | 653 | }; |
| 652 | 654 | ||
| 653 | FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) | 655 | FSP_SRV::FSP_SRV(Core::System& system_) |
| 654 | : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) { | 656 | : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, |
| 657 | content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} { | ||
| 655 | // clang-format off | 658 | // clang-format off |
| 656 | static const FunctionInfo functions[] = { | 659 | static const FunctionInfo functions[] = { |
| 657 | {0, nullptr, "OpenFileSystem"}, | 660 | {0, nullptr, "OpenFileSystem"}, |
| @@ -714,7 +717,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) | |||
| 714 | {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, | 717 | {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, |
| 715 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, | 718 | {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, |
| 716 | {204, nullptr, "OpenDataFileSystemByProgramIndex"}, | 719 | {204, nullptr, "OpenDataFileSystemByProgramIndex"}, |
| 717 | {205, nullptr, "OpenDataStorageByProgramIndex"}, | 720 | {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, |
| 718 | {400, nullptr, "OpenDeviceOperator"}, | 721 | {400, nullptr, "OpenDeviceOperator"}, |
| 719 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, | 722 | {500, nullptr, "OpenSdCardDetectionEventNotifier"}, |
| 720 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, | 723 | {501, nullptr, "OpenGameCardDetectionEventNotifier"}, |
| @@ -791,8 +794,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { | |||
| 791 | 794 | ||
| 792 | const auto type = rp.PopRaw<FileSystemType>(); | 795 | const auto type = rp.PopRaw<FileSystemType>(); |
| 793 | const auto title_id = rp.PopRaw<u64>(); | 796 | const auto title_id = rp.PopRaw<u64>(); |
| 794 | LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", | 797 | LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); |
| 795 | static_cast<u8>(type), title_id); | ||
| 796 | 798 | ||
| 797 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 799 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 798 | rb.Push(RESULT_UNKNOWN); | 800 | rb.Push(RESULT_UNKNOWN); |
| @@ -801,8 +803,9 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { | |||
| 801 | void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { | 803 | void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { |
| 802 | LOG_DEBUG(Service_FS, "called"); | 804 | LOG_DEBUG(Service_FS, "called"); |
| 803 | 805 | ||
| 804 | auto filesystem = std::make_shared<IFileSystem>( | 806 | auto filesystem = |
| 805 | fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); | 807 | std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(), |
| 808 | SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); | ||
| 806 | 809 | ||
| 807 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 810 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 808 | rb.Push(RESULT_SUCCESS); | 811 | rb.Push(RESULT_SUCCESS); |
| @@ -862,8 +865,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 862 | UNREACHABLE(); | 865 | UNREACHABLE(); |
| 863 | } | 866 | } |
| 864 | 867 | ||
| 865 | auto filesystem = | 868 | auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()), |
| 866 | std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id)); | 869 | SizeGetter::FromStorageId(fsc, id)); |
| 867 | 870 | ||
| 868 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 871 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 869 | rb.Push(RESULT_SUCCESS); | 872 | rb.Push(RESULT_SUCCESS); |
| @@ -878,11 +881,12 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 878 | void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { | 881 | void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { |
| 879 | IPC::RequestParser rp{ctx}; | 882 | IPC::RequestParser rp{ctx}; |
| 880 | const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); | 883 | const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); |
| 881 | LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space)); | 884 | LOG_INFO(Service_FS, "called, space={}", space); |
| 882 | 885 | ||
| 883 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 886 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 884 | rb.Push(RESULT_SUCCESS); | 887 | rb.Push(RESULT_SUCCESS); |
| 885 | rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc)); | 888 | rb.PushIpcInterface<ISaveDataInfoReader>( |
| 889 | std::make_shared<ISaveDataInfoReader>(system, space, fsc)); | ||
| 886 | } | 890 | } |
| 887 | 891 | ||
| 888 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) { | 892 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) { |
| @@ -909,10 +913,10 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute( | |||
| 909 | "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" | 913 | "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" |
| 910 | "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" | 914 | "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" |
| 911 | "attribute.type={}, attribute.rank={}, attribute.index={}", | 915 | "attribute.type={}, attribute.rank={}, attribute.index={}", |
| 912 | flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id, | 916 | flags, parameters.space_id, parameters.attribute.title_id, |
| 913 | parameters.attribute.user_id[1], parameters.attribute.user_id[0], | 917 | parameters.attribute.user_id[1], parameters.attribute.user_id[0], |
| 914 | parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type), | 918 | parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, |
| 915 | static_cast<u32>(parameters.attribute.rank), parameters.attribute.index); | 919 | parameters.attribute.index); |
| 916 | 920 | ||
| 917 | IPC::ResponseBuilder rb{ctx, 3}; | 921 | IPC::ResponseBuilder rb{ctx, 3}; |
| 918 | rb.Push(RESULT_SUCCESS); | 922 | rb.Push(RESULT_SUCCESS); |
| @@ -931,7 +935,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | |||
| 931 | return; | 935 | return; |
| 932 | } | 936 | } |
| 933 | 937 | ||
| 934 | auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap())); | 938 | auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap())); |
| 935 | 939 | ||
| 936 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 940 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 937 | rb.Push(RESULT_SUCCESS); | 941 | rb.Push(RESULT_SUCCESS); |
| @@ -945,7 +949,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { | |||
| 945 | const auto title_id = rp.PopRaw<u64>(); | 949 | const auto title_id = rp.PopRaw<u64>(); |
| 946 | 950 | ||
| 947 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", | 951 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", |
| 948 | static_cast<u8>(storage_id), unknown, title_id); | 952 | storage_id, unknown, title_id); |
| 949 | 953 | ||
| 950 | auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); | 954 | auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); |
| 951 | 955 | ||
| @@ -955,23 +959,23 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { | |||
| 955 | if (archive != nullptr) { | 959 | if (archive != nullptr) { |
| 956 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 960 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 957 | rb.Push(RESULT_SUCCESS); | 961 | rb.Push(RESULT_SUCCESS); |
| 958 | rb.PushIpcInterface(std::make_shared<IStorage>(archive)); | 962 | rb.PushIpcInterface(std::make_shared<IStorage>(system, archive)); |
| 959 | return; | 963 | return; |
| 960 | } | 964 | } |
| 961 | 965 | ||
| 962 | // TODO(DarkLordZach): Find the right error code to use here | 966 | // TODO(DarkLordZach): Find the right error code to use here |
| 963 | LOG_ERROR(Service_FS, | 967 | LOG_ERROR(Service_FS, |
| 964 | "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, | 968 | "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, |
| 965 | static_cast<u8>(storage_id)); | 969 | storage_id); |
| 966 | IPC::ResponseBuilder rb{ctx, 2}; | 970 | IPC::ResponseBuilder rb{ctx, 2}; |
| 967 | rb.Push(RESULT_UNKNOWN); | 971 | rb.Push(RESULT_UNKNOWN); |
| 968 | return; | 972 | return; |
| 969 | } | 973 | } |
| 970 | 974 | ||
| 971 | FileSys::PatchManager pm{title_id}; | 975 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; |
| 972 | 976 | ||
| 973 | auto storage = std::make_shared<IStorage>( | 977 | auto storage = std::make_shared<IStorage>( |
| 974 | pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); | 978 | system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); |
| 975 | 979 | ||
| 976 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 980 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 977 | rb.Push(RESULT_SUCCESS); | 981 | rb.Push(RESULT_SUCCESS); |
| @@ -981,21 +985,46 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { | |||
| 981 | void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | 985 | void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { |
| 982 | IPC::RequestParser rp{ctx}; | 986 | IPC::RequestParser rp{ctx}; |
| 983 | 987 | ||
| 984 | auto storage_id = rp.PopRaw<FileSys::StorageId>(); | 988 | const auto storage_id = rp.PopRaw<FileSys::StorageId>(); |
| 985 | auto title_id = rp.PopRaw<u64>(); | 989 | const auto title_id = rp.PopRaw<u64>(); |
| 986 | 990 | ||
| 987 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", | 991 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); |
| 988 | static_cast<u8>(storage_id), title_id); | ||
| 989 | 992 | ||
| 990 | IPC::ResponseBuilder rb{ctx, 2}; | 993 | IPC::ResponseBuilder rb{ctx, 2}; |
| 991 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); | 994 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); |
| 992 | } | 995 | } |
| 993 | 996 | ||
| 997 | void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) { | ||
| 998 | IPC::RequestParser rp{ctx}; | ||
| 999 | |||
| 1000 | const auto program_index = rp.PopRaw<u8>(); | ||
| 1001 | |||
| 1002 | LOG_DEBUG(Service_FS, "called, program_index={}", program_index); | ||
| 1003 | |||
| 1004 | auto romfs = fsc.OpenPatchedRomFSWithProgramIndex( | ||
| 1005 | system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program); | ||
| 1006 | |||
| 1007 | if (romfs.Failed()) { | ||
| 1008 | // TODO: Find the right error code to use here | ||
| 1009 | LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); | ||
| 1010 | |||
| 1011 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1012 | rb.Push(RESULT_UNKNOWN); | ||
| 1013 | return; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap())); | ||
| 1017 | |||
| 1018 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1019 | rb.Push(RESULT_SUCCESS); | ||
| 1020 | rb.PushIpcInterface<IStorage>(std::move(storage)); | ||
| 1021 | } | ||
| 1022 | |||
| 994 | void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 1023 | void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| 995 | IPC::RequestParser rp{ctx}; | 1024 | IPC::RequestParser rp{ctx}; |
| 996 | log_mode = rp.PopEnum<LogMode>(); | 1025 | log_mode = rp.PopEnum<LogMode>(); |
| 997 | 1026 | ||
| 998 | LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode)); | 1027 | LOG_DEBUG(Service_FS, "called, log_mode={:08X}", log_mode); |
| 999 | 1028 | ||
| 1000 | IPC::ResponseBuilder rb{ctx, 2}; | 1029 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1001 | rb.Push(RESULT_SUCCESS); | 1030 | rb.Push(RESULT_SUCCESS); |
| @@ -1033,7 +1062,8 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { | |||
| 1033 | 1062 | ||
| 1034 | class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { | 1063 | class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { |
| 1035 | public: | 1064 | public: |
| 1036 | explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") { | 1065 | explicit IMultiCommitManager(Core::System& system_) |
| 1066 | : ServiceFramework{system_, "IMultiCommitManager"} { | ||
| 1037 | static const FunctionInfo functions[] = { | 1067 | static const FunctionInfo functions[] = { |
| 1038 | {1, &IMultiCommitManager::Add, "Add"}, | 1068 | {1, &IMultiCommitManager::Add, "Add"}, |
| 1039 | {2, &IMultiCommitManager::Commit, "Commit"}, | 1069 | {2, &IMultiCommitManager::Commit, "Commit"}, |
| @@ -1064,7 +1094,7 @@ void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) { | |||
| 1064 | 1094 | ||
| 1065 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1095 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1066 | rb.Push(RESULT_SUCCESS); | 1096 | rb.Push(RESULT_SUCCESS); |
| 1067 | rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>()); | 1097 | rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); |
| 1068 | } | 1098 | } |
| 1069 | 1099 | ||
| 1070 | } // namespace Service::FileSystem | 1100 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4964e874e..8ed933279 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -12,8 +12,9 @@ class Reporter; | |||
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace FileSys { | 14 | namespace FileSys { |
| 15 | class ContentProvider; | ||
| 15 | class FileSystemBackend; | 16 | class FileSystemBackend; |
| 16 | } | 17 | } // namespace FileSys |
| 17 | 18 | ||
| 18 | namespace Service::FileSystem { | 19 | namespace Service::FileSystem { |
| 19 | 20 | ||
| @@ -32,7 +33,7 @@ enum class LogMode : u32 { | |||
| 32 | 33 | ||
| 33 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { | 34 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { |
| 34 | public: | 35 | public: |
| 35 | explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter); | 36 | explicit FSP_SRV(Core::System& system_); |
| 36 | ~FSP_SRV() override; | 37 | ~FSP_SRV() override; |
| 37 | 38 | ||
| 38 | private: | 39 | private: |
| @@ -48,6 +49,7 @@ private: | |||
| 48 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 49 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 49 | void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); | 50 | void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); |
| 50 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 51 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 52 | void OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx); | ||
| 51 | void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); | 53 | void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); |
| 52 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); | 54 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); |
| 53 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); | 55 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); |
| @@ -55,6 +57,7 @@ private: | |||
| 55 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); | 57 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); |
| 56 | 58 | ||
| 57 | FileSystemController& fsc; | 59 | FileSystemController& fsc; |
| 60 | const FileSys::ContentProvider& content_provider; | ||
| 58 | 61 | ||
| 59 | FileSys::VirtualFile romfs; | 62 | FileSys::VirtualFile romfs; |
| 60 | u64 current_process_id = 0; | 63 | u64 current_process_id = 0; |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index b7adaffc7..c5b053c31 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <queue> | 5 | #include <queue> |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "common/uuid.h" | 7 | #include "common/uuid.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/readable_event.h" | 10 | #include "core/hle/kernel/readable_event.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/writable_event.h" |
| @@ -16,7 +17,7 @@ namespace Service::Friend { | |||
| 16 | 17 | ||
| 17 | class IFriendService final : public ServiceFramework<IFriendService> { | 18 | class IFriendService final : public ServiceFramework<IFriendService> { |
| 18 | public: | 19 | public: |
| 19 | IFriendService() : ServiceFramework("IFriendService") { | 20 | explicit IFriendService(Core::System& system_) : ServiceFramework{system_, "IFriendService"} { |
| 20 | // clang-format off | 21 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 22 | {0, nullptr, "GetCompletionEvent"}, | 23 | {0, nullptr, "GetCompletionEvent"}, |
| @@ -170,8 +171,8 @@ private: | |||
| 170 | 171 | ||
| 171 | class INotificationService final : public ServiceFramework<INotificationService> { | 172 | class INotificationService final : public ServiceFramework<INotificationService> { |
| 172 | public: | 173 | public: |
| 173 | INotificationService(Common::UUID uuid, Core::System& system) | 174 | explicit INotificationService(Common::UUID uuid_, Core::System& system_) |
| 174 | : ServiceFramework("INotificationService"), uuid(uuid) { | 175 | : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} { |
| 175 | // clang-format off | 176 | // clang-format off |
| 176 | static const FunctionInfo functions[] = { | 177 | static const FunctionInfo functions[] = { |
| 177 | {0, &INotificationService::GetEvent, "GetEvent"}, | 178 | {0, &INotificationService::GetEvent, "GetEvent"}, |
| @@ -228,8 +229,7 @@ private: | |||
| 228 | break; | 229 | break; |
| 229 | default: | 230 | default: |
| 230 | // HOS seems not have an error case for an unknown notification | 231 | // HOS seems not have an error case for an unknown notification |
| 231 | LOG_WARNING(Service_ACC, "Unknown notification {:08X}", | 232 | LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type); |
| 232 | static_cast<u32>(notification.notification_type)); | ||
| 233 | break; | 233 | break; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| @@ -266,7 +266,7 @@ private: | |||
| 266 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { | 266 | void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { |
| 267 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 267 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 268 | rb.Push(RESULT_SUCCESS); | 268 | rb.Push(RESULT_SUCCESS); |
| 269 | rb.PushIpcInterface<IFriendService>(); | 269 | rb.PushIpcInterface<IFriendService>(system); |
| 270 | LOG_DEBUG(Service_ACC, "called"); | 270 | LOG_DEBUG(Service_ACC, "called"); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| @@ -281,8 +281,9 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx | |||
| 281 | rb.PushIpcInterface<INotificationService>(uuid, system); | 281 | rb.PushIpcInterface<INotificationService>(uuid, system); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) | 284 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 285 | : ServiceFramework(name), module(std::move(module)), system(system) {} | 285 | const char* name) |
| 286 | : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||
| 286 | 287 | ||
| 287 | Module::Interface::~Interface() = default; | 288 | Module::Interface::~Interface() = default; |
| 288 | 289 | ||
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index 24f3fc969..8be3321db 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h | |||
| @@ -16,7 +16,8 @@ class Module final { | |||
| 16 | public: | 16 | public: |
| 17 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 18 | public: | 18 | public: |
| 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 20 | const char* name); | ||
| 20 | ~Interface() override; | 21 | ~Interface() override; |
| 21 | 22 | ||
| 22 | void CreateFriendService(Kernel::HLERequestContext& ctx); | 23 | void CreateFriendService(Kernel::HLERequestContext& ctx); |
| @@ -24,7 +25,6 @@ public: | |||
| 24 | 25 | ||
| 25 | protected: | 26 | protected: |
| 26 | std::shared_ptr<Module> module; | 27 | std::shared_ptr<Module> module; |
| 27 | Core::System& system; | ||
| 28 | }; | 28 | }; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 58155f652..7368ccec2 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Friend { | 7 | namespace Service::Friend { |
| 8 | 8 | ||
| 9 | Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name) | 9 | Friend::Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name) |
| 10 | : Interface(std::move(module), system, name) { | 10 | : Interface(std::move(module_), system_, name) { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &Friend::CreateFriendService, "CreateFriendService"}, | 12 | {0, &Friend::CreateFriendService, "CreateFriendService"}, |
| 13 | {1, &Friend::CreateNotificationService, "CreateNotificationService"}, | 13 | {1, &Friend::CreateNotificationService, "CreateNotificationService"}, |
diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h index 465a35770..43d914b32 100644 --- a/src/core/hle/service/friend/interface.h +++ b/src/core/hle/service/friend/interface.h | |||
| @@ -10,7 +10,7 @@ namespace Service::Friend { | |||
| 10 | 10 | ||
| 11 | class Friend final : public Module::Interface { | 11 | class Friend final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name); | 13 | explicit Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name); |
| 14 | ~Friend() override; | 14 | ~Friend() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index b591ce31b..fc77e7286 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/file_sys/control_metadata.h" | 9 | #include "core/file_sys/control_metadata.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/hle_ipc.h" | 11 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -32,8 +33,8 @@ std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 proces | |||
| 32 | } | 33 | } |
| 33 | } // Anonymous namespace | 34 | } // Anonymous namespace |
| 34 | 35 | ||
| 35 | ARP_R::ARP_R(const Core::System& system, const ARPManager& manager) | 36 | ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_) |
| 36 | : ServiceFramework{"arp:r"}, system(system), manager(manager) { | 37 | : ServiceFramework{system_, "arp:r"}, manager{manager_} { |
| 37 | // clang-format off | 38 | // clang-format off |
| 38 | static const FunctionInfo functions[] = { | 39 | static const FunctionInfo functions[] = { |
| 39 | {0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"}, | 40 | {0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"}, |
| @@ -151,8 +152,9 @@ class IRegistrar final : public ServiceFramework<IRegistrar> { | |||
| 151 | 152 | ||
| 152 | public: | 153 | public: |
| 153 | explicit IRegistrar( | 154 | explicit IRegistrar( |
| 155 | Core::System& system_, | ||
| 154 | std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer) | 156 | std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer) |
| 155 | : ServiceFramework{"IRegistrar"}, issue_process_id(std::move(issuer)) { | 157 | : ServiceFramework{system_, "IRegistrar"}, issue_process_id{std::move(issuer)} { |
| 156 | // clang-format off | 158 | // clang-format off |
| 157 | static const FunctionInfo functions[] = { | 159 | static const FunctionInfo functions[] = { |
| 158 | {0, &IRegistrar::Issue, "Issue"}, | 160 | {0, &IRegistrar::Issue, "Issue"}, |
| @@ -236,8 +238,8 @@ private: | |||
| 236 | std::vector<u8> control; | 238 | std::vector<u8> control; |
| 237 | }; | 239 | }; |
| 238 | 240 | ||
| 239 | ARP_W::ARP_W(const Core::System& system, ARPManager& manager) | 241 | ARP_W::ARP_W(Core::System& system_, ARPManager& manager_) |
| 240 | : ServiceFramework{"arp:w"}, system(system), manager(manager) { | 242 | : ServiceFramework{system_, "arp:w"}, manager{manager_} { |
| 241 | // clang-format off | 243 | // clang-format off |
| 242 | static const FunctionInfo functions[] = { | 244 | static const FunctionInfo functions[] = { |
| 243 | {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, | 245 | {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, |
| @@ -254,7 +256,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) { | |||
| 254 | LOG_DEBUG(Service_ARP, "called"); | 256 | LOG_DEBUG(Service_ARP, "called"); |
| 255 | 257 | ||
| 256 | registrar = std::make_shared<IRegistrar>( | 258 | registrar = std::make_shared<IRegistrar>( |
| 257 | [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) { | 259 | system, [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) { |
| 258 | const auto res = GetTitleIDForProcessID(system, process_id); | 260 | const auto res = GetTitleIDForProcessID(system, process_id); |
| 259 | if (!res.has_value()) { | 261 | if (!res.has_value()) { |
| 260 | return ERR_NOT_REGISTERED; | 262 | return ERR_NOT_REGISTERED; |
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h index d5f8a7e7a..34b412e26 100644 --- a/src/core/hle/service/glue/arp.h +++ b/src/core/hle/service/glue/arp.h | |||
| @@ -13,7 +13,7 @@ class IRegistrar; | |||
| 13 | 13 | ||
| 14 | class ARP_R final : public ServiceFramework<ARP_R> { | 14 | class ARP_R final : public ServiceFramework<ARP_R> { |
| 15 | public: | 15 | public: |
| 16 | explicit ARP_R(const Core::System& system, const ARPManager& manager); | 16 | explicit ARP_R(Core::System& system_, const ARPManager& manager_); |
| 17 | ~ARP_R() override; | 17 | ~ARP_R() override; |
| 18 | 18 | ||
| 19 | private: | 19 | private: |
| @@ -22,20 +22,18 @@ private: | |||
| 22 | void GetApplicationControlProperty(Kernel::HLERequestContext& ctx); | 22 | void GetApplicationControlProperty(Kernel::HLERequestContext& ctx); |
| 23 | void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx); | 23 | void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx); |
| 24 | 24 | ||
| 25 | const Core::System& system; | ||
| 26 | const ARPManager& manager; | 25 | const ARPManager& manager; |
| 27 | }; | 26 | }; |
| 28 | 27 | ||
| 29 | class ARP_W final : public ServiceFramework<ARP_W> { | 28 | class ARP_W final : public ServiceFramework<ARP_W> { |
| 30 | public: | 29 | public: |
| 31 | explicit ARP_W(const Core::System& system, ARPManager& manager); | 30 | explicit ARP_W(Core::System& system_, ARPManager& manager_); |
| 32 | ~ARP_W() override; | 31 | ~ARP_W() override; |
| 33 | 32 | ||
| 34 | private: | 33 | private: |
| 35 | void AcquireRegistrar(Kernel::HLERequestContext& ctx); | 34 | void AcquireRegistrar(Kernel::HLERequestContext& ctx); |
| 36 | void DeleteProperties(Kernel::HLERequestContext& ctx); | 35 | void DeleteProperties(Kernel::HLERequestContext& ctx); |
| 37 | 36 | ||
| 38 | const Core::System& system; | ||
| 39 | ARPManager& manager; | 37 | ARPManager& manager; |
| 40 | std::shared_ptr<IRegistrar> registrar; | 38 | std::shared_ptr<IRegistrar> registrar; |
| 41 | }; | 39 | }; |
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp index cd89d088f..a478b68e1 100644 --- a/src/core/hle/service/glue/bgtc.cpp +++ b/src/core/hle/service/glue/bgtc.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Glue { | 7 | namespace Service::Glue { |
| 8 | 8 | ||
| 9 | BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} { | 9 | BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {1, nullptr, "NotifyTaskStarting"}, | 12 | {1, nullptr, "NotifyTaskStarting"}, |
| @@ -31,7 +31,7 @@ BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} { | |||
| 31 | 31 | ||
| 32 | BGTC_T::~BGTC_T() = default; | 32 | BGTC_T::~BGTC_T() = default; |
| 33 | 33 | ||
| 34 | BGTC_SC::BGTC_SC() : ServiceFramework{"bgtc:sc"} { | 34 | BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} { |
| 35 | // clang-format off | 35 | // clang-format off |
| 36 | static const FunctionInfo functions[] = { | 36 | static const FunctionInfo functions[] = { |
| 37 | {1, nullptr, "GetState"}, | 37 | {1, nullptr, "GetState"}, |
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h index 81844f03e..906116ba6 100644 --- a/src/core/hle/service/glue/bgtc.h +++ b/src/core/hle/service/glue/bgtc.h | |||
| @@ -6,17 +6,21 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Glue { | 13 | namespace Service::Glue { |
| 10 | 14 | ||
| 11 | class BGTC_T final : public ServiceFramework<BGTC_T> { | 15 | class BGTC_T final : public ServiceFramework<BGTC_T> { |
| 12 | public: | 16 | public: |
| 13 | BGTC_T(); | 17 | explicit BGTC_T(Core::System& system_); |
| 14 | ~BGTC_T() override; | 18 | ~BGTC_T() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
| 17 | class BGTC_SC final : public ServiceFramework<BGTC_SC> { | 21 | class BGTC_SC final : public ServiceFramework<BGTC_SC> { |
| 18 | public: | 22 | public: |
| 19 | BGTC_SC(); | 23 | explicit BGTC_SC(Core::System& system_); |
| 20 | ~BGTC_SC() override; | 24 | ~BGTC_SC() override; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index c728e815c..4eafbe5fa 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp | |||
| @@ -18,8 +18,8 @@ void InstallInterfaces(Core::System& system) { | |||
| 18 | ->InstallAsService(system.ServiceManager()); | 18 | ->InstallAsService(system.ServiceManager()); |
| 19 | 19 | ||
| 20 | // BackGround Task Controller | 20 | // BackGround Task Controller |
| 21 | std::make_shared<BGTC_T>()->InstallAsService(system.ServiceManager()); | 21 | std::make_shared<BGTC_T>(system)->InstallAsService(system.ServiceManager()); |
| 22 | std::make_shared<BGTC_SC>()->InstallAsService(system.ServiceManager()); | 22 | std::make_shared<BGTC_SC>(system)->InstallAsService(system.ServiceManager()); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | } // namespace Service::Glue | 25 | } // namespace Service::Glue |
diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp index 401e0b208..a502ab47f 100644 --- a/src/core/hle/service/grc/grc.cpp +++ b/src/core/hle/service/grc/grc.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::GRC { | |||
| 12 | 12 | ||
| 13 | class GRC final : public ServiceFramework<GRC> { | 13 | class GRC final : public ServiceFramework<GRC> { |
| 14 | public: | 14 | public: |
| 15 | explicit GRC() : ServiceFramework{"grc:c"} { | 15 | explicit GRC(Core::System& system) : ServiceFramework{system, "grc:c"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {1, nullptr, "OpenContinuousRecorder"}, | 18 | {1, nullptr, "OpenContinuousRecorder"}, |
| @@ -27,8 +27,8 @@ public: | |||
| 27 | } | 27 | } |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | void InstallInterfaces(SM::ServiceManager& sm) { | 30 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 31 | std::make_shared<GRC>()->InstallAsService(sm); | 31 | std::make_shared<GRC>(system)->InstallAsService(sm); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | } // namespace Service::GRC | 34 | } // namespace Service::GRC |
diff --git a/src/core/hle/service/grc/grc.h b/src/core/hle/service/grc/grc.h index e0d29e70d..9069fe756 100644 --- a/src/core/hle/service/grc/grc.h +++ b/src/core/hle/service/grc/grc.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::GRC { | 15 | namespace Service::GRC { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::GRC | 19 | } // namespace Service::GRC |
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 8bc69c372..f47a9e61c 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h | |||
| @@ -31,6 +31,10 @@ public: | |||
| 31 | virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 31 | virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 32 | std::size_t size) = 0; | 32 | std::size_t size) = 0; |
| 33 | 33 | ||
| 34 | // When the controller is requesting a motion update for the shared memory | ||
| 35 | virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||
| 36 | std::size_t size) {} | ||
| 37 | |||
| 34 | // Called when input devices should be loaded | 38 | // Called when input devices should be loaded |
| 35 | virtual void OnLoadInputDevices() = 0; | 39 | virtual void OnLoadInputDevices() = 0; |
| 36 | 40 | ||
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 0b896d5ad..59b694cd4 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -42,8 +42,8 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, | |||
| 42 | cur_entry.modifier = 0; | 42 | cur_entry.modifier = 0; |
| 43 | if (Settings::values.keyboard_enabled) { | 43 | if (Settings::values.keyboard_enabled) { |
| 44 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { | 44 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { |
| 45 | cur_entry.key[i / KEYS_PER_BYTE] |= | 45 | auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; |
| 46 | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)); | 46 | entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { | 49 | for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 620386cd1..d280e7caf 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -116,8 +116,36 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) { | |||
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | bool Controller_NPad::IsNpadIdValid(u32 npad_id) { | ||
| 120 | switch (npad_id) { | ||
| 121 | case 0: | ||
| 122 | case 1: | ||
| 123 | case 2: | ||
| 124 | case 3: | ||
| 125 | case 4: | ||
| 126 | case 5: | ||
| 127 | case 6: | ||
| 128 | case 7: | ||
| 129 | case NPAD_UNKNOWN: | ||
| 130 | case NPAD_HANDHELD: | ||
| 131 | return true; | ||
| 132 | default: | ||
| 133 | LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); | ||
| 134 | return false; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { | ||
| 139 | return IsNpadIdValid(device_handle.npad_id) && | ||
| 140 | device_handle.npad_type < NpadType::MaxNpadType && | ||
| 141 | device_handle.device_index < DeviceIndex::MaxDeviceIndex; | ||
| 142 | } | ||
| 143 | |||
| 119 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} | 144 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} |
| 120 | Controller_NPad::~Controller_NPad() = default; | 145 | |
| 146 | Controller_NPad::~Controller_NPad() { | ||
| 147 | OnRelease(); | ||
| 148 | } | ||
| 121 | 149 | ||
| 122 | void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | 150 | void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { |
| 123 | const auto controller_type = connected_controllers[controller_idx].type; | 151 | const auto controller_type = connected_controllers[controller_idx].type; |
| @@ -139,7 +167,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 139 | controller.properties.is_vertical.Assign(1); | 167 | controller.properties.is_vertical.Assign(1); |
| 140 | controller.properties.use_plus.Assign(1); | 168 | controller.properties.use_plus.Assign(1); |
| 141 | controller.properties.use_minus.Assign(1); | 169 | controller.properties.use_minus.Assign(1); |
| 142 | controller.pad_assignment = NPadAssignments::Single; | 170 | controller.pad_assignment = NpadAssignments::Single; |
| 143 | break; | 171 | break; |
| 144 | case NPadControllerType::Handheld: | 172 | case NPadControllerType::Handheld: |
| 145 | controller.joy_styles.handheld.Assign(1); | 173 | controller.joy_styles.handheld.Assign(1); |
| @@ -147,7 +175,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 147 | controller.properties.is_vertical.Assign(1); | 175 | controller.properties.is_vertical.Assign(1); |
| 148 | controller.properties.use_plus.Assign(1); | 176 | controller.properties.use_plus.Assign(1); |
| 149 | controller.properties.use_minus.Assign(1); | 177 | controller.properties.use_minus.Assign(1); |
| 150 | controller.pad_assignment = NPadAssignments::Dual; | 178 | controller.pad_assignment = NpadAssignments::Dual; |
| 151 | break; | 179 | break; |
| 152 | case NPadControllerType::JoyDual: | 180 | case NPadControllerType::JoyDual: |
| 153 | controller.joy_styles.joycon_dual.Assign(1); | 181 | controller.joy_styles.joycon_dual.Assign(1); |
| @@ -156,26 +184,26 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 156 | controller.properties.is_vertical.Assign(1); | 184 | controller.properties.is_vertical.Assign(1); |
| 157 | controller.properties.use_plus.Assign(1); | 185 | controller.properties.use_plus.Assign(1); |
| 158 | controller.properties.use_minus.Assign(1); | 186 | controller.properties.use_minus.Assign(1); |
| 159 | controller.pad_assignment = NPadAssignments::Dual; | 187 | controller.pad_assignment = NpadAssignments::Dual; |
| 160 | break; | 188 | break; |
| 161 | case NPadControllerType::JoyLeft: | 189 | case NPadControllerType::JoyLeft: |
| 162 | controller.joy_styles.joycon_left.Assign(1); | 190 | controller.joy_styles.joycon_left.Assign(1); |
| 163 | controller.device_type.joycon_left.Assign(1); | 191 | controller.device_type.joycon_left.Assign(1); |
| 164 | controller.properties.is_horizontal.Assign(1); | 192 | controller.properties.is_horizontal.Assign(1); |
| 165 | controller.properties.use_minus.Assign(1); | 193 | controller.properties.use_minus.Assign(1); |
| 166 | controller.pad_assignment = NPadAssignments::Single; | 194 | controller.pad_assignment = NpadAssignments::Single; |
| 167 | break; | 195 | break; |
| 168 | case NPadControllerType::JoyRight: | 196 | case NPadControllerType::JoyRight: |
| 169 | controller.joy_styles.joycon_right.Assign(1); | 197 | controller.joy_styles.joycon_right.Assign(1); |
| 170 | controller.device_type.joycon_right.Assign(1); | 198 | controller.device_type.joycon_right.Assign(1); |
| 171 | controller.properties.is_horizontal.Assign(1); | 199 | controller.properties.is_horizontal.Assign(1); |
| 172 | controller.properties.use_plus.Assign(1); | 200 | controller.properties.use_plus.Assign(1); |
| 173 | controller.pad_assignment = NPadAssignments::Single; | 201 | controller.pad_assignment = NpadAssignments::Single; |
| 174 | break; | 202 | break; |
| 175 | case NPadControllerType::Pokeball: | 203 | case NPadControllerType::Pokeball: |
| 176 | controller.joy_styles.pokeball.Assign(1); | 204 | controller.joy_styles.pokeball.Assign(1); |
| 177 | controller.device_type.pokeball.Assign(1); | 205 | controller.device_type.pokeball.Assign(1); |
| 178 | controller.pad_assignment = NPadAssignments::Single; | 206 | controller.pad_assignment = NpadAssignments::Single; |
| 179 | break; | 207 | break; |
| 180 | } | 208 | } |
| 181 | 209 | ||
| @@ -184,11 +212,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 184 | controller.single_color.button_color = 0; | 212 | controller.single_color.button_color = 0; |
| 185 | 213 | ||
| 186 | controller.dual_color_error = ColorReadError::ReadOk; | 214 | controller.dual_color_error = ColorReadError::ReadOk; |
| 187 | controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left; | 215 | controller.left_color.body_color = |
| 188 | controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left; | 216 | Settings::values.players.GetValue()[controller_idx].body_color_left; |
| 189 | controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right; | 217 | controller.left_color.button_color = |
| 218 | Settings::values.players.GetValue()[controller_idx].button_color_left; | ||
| 219 | controller.right_color.body_color = | ||
| 220 | Settings::values.players.GetValue()[controller_idx].body_color_right; | ||
| 190 | controller.right_color.button_color = | 221 | controller.right_color.button_color = |
| 191 | Settings::values.players[controller_idx].button_color_right; | 222 | Settings::values.players.GetValue()[controller_idx].button_color_right; |
| 192 | 223 | ||
| 193 | controller.battery_level[0] = BATTERY_FULL; | 224 | controller.battery_level[0] = BATTERY_FULL; |
| 194 | controller.battery_level[1] = BATTERY_FULL; | 225 | controller.battery_level[1] = BATTERY_FULL; |
| @@ -199,7 +230,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | |||
| 199 | 230 | ||
| 200 | void Controller_NPad::OnInit() { | 231 | void Controller_NPad::OnInit() { |
| 201 | auto& kernel = system.Kernel(); | 232 | auto& kernel = system.Kernel(); |
| 202 | for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { | 233 | for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { |
| 203 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( | 234 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( |
| 204 | kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); | 235 | kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); |
| 205 | } | 236 | } |
| @@ -208,6 +239,8 @@ void Controller_NPad::OnInit() { | |||
| 208 | return; | 239 | return; |
| 209 | } | 240 | } |
| 210 | 241 | ||
| 242 | OnLoadInputDevices(); | ||
| 243 | |||
| 211 | if (style.raw == 0) { | 244 | if (style.raw == 0) { |
| 212 | // We want to support all controllers | 245 | // We want to support all controllers |
| 213 | style.handheld.Assign(1); | 246 | style.handheld.Assign(1); |
| @@ -218,12 +251,27 @@ void Controller_NPad::OnInit() { | |||
| 218 | style.pokeball.Assign(1); | 251 | style.pokeball.Assign(1); |
| 219 | } | 252 | } |
| 220 | 253 | ||
| 221 | std::transform(Settings::values.players.begin(), Settings::values.players.end(), | 254 | std::transform(Settings::values.players.GetValue().begin(), |
| 222 | connected_controllers.begin(), [](const Settings::PlayerInput& player) { | 255 | Settings::values.players.GetValue().end(), connected_controllers.begin(), |
| 256 | [](const Settings::PlayerInput& player) { | ||
| 223 | return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), | 257 | return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), |
| 224 | player.connected}; | 258 | player.connected}; |
| 225 | }); | 259 | }); |
| 226 | 260 | ||
| 261 | // Connect the Player 1 or Handheld controller if none are connected. | ||
| 262 | if (std::none_of(connected_controllers.begin(), connected_controllers.end(), | ||
| 263 | [](const ControllerHolder& controller) { return controller.is_connected; })) { | ||
| 264 | const auto controller = | ||
| 265 | MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type); | ||
| 266 | if (controller == NPadControllerType::Handheld) { | ||
| 267 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; | ||
| 268 | connected_controllers[HANDHELD_INDEX] = {controller, true}; | ||
| 269 | } else { | ||
| 270 | Settings::values.players.GetValue()[0].connected = true; | ||
| 271 | connected_controllers[0] = {controller, true}; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 227 | // Account for handheld | 275 | // Account for handheld |
| 228 | if (connected_controllers[HANDHELD_INDEX].is_connected) { | 276 | if (connected_controllers[HANDHELD_INDEX].is_connected) { |
| 229 | connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; | 277 | connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; |
| @@ -242,7 +290,7 @@ void Controller_NPad::OnInit() { | |||
| 242 | } | 290 | } |
| 243 | 291 | ||
| 244 | void Controller_NPad::OnLoadInputDevices() { | 292 | void Controller_NPad::OnLoadInputDevices() { |
| 245 | const auto& players = Settings::values.players; | 293 | const auto& players = Settings::values.players.GetValue(); |
| 246 | for (std::size_t i = 0; i < players.size(); ++i) { | 294 | for (std::size_t i = 0; i < players.size(); ++i) { |
| 247 | std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | 295 | std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, |
| 248 | players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | 296 | players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, |
| @@ -250,17 +298,30 @@ void Controller_NPad::OnLoadInputDevices() { | |||
| 250 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | 298 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, |
| 251 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | 299 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, |
| 252 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); | 300 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); |
| 301 | std::transform(players[i].vibrations.begin() + | ||
| 302 | Settings::NativeVibration::VIBRATION_HID_BEGIN, | ||
| 303 | players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, | ||
| 304 | vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>); | ||
| 253 | std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, | 305 | std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, |
| 254 | players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, | 306 | players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, |
| 255 | motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); | 307 | motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); |
| 308 | for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) { | ||
| 309 | InitializeVibrationDeviceAtIndex(i, device_idx); | ||
| 310 | } | ||
| 256 | } | 311 | } |
| 257 | } | 312 | } |
| 258 | 313 | ||
| 259 | void Controller_NPad::OnRelease() {} | 314 | void Controller_NPad::OnRelease() { |
| 315 | for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { | ||
| 316 | for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { | ||
| 317 | VibrateControllerAtIndex(npad_idx, device_idx, {}); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 260 | 321 | ||
| 261 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | 322 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { |
| 262 | const auto controller_idx = NPadIdToIndex(npad_id); | 323 | const auto controller_idx = NPadIdToIndex(npad_id); |
| 263 | [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type; | 324 | const auto controller_type = connected_controllers[controller_idx].type; |
| 264 | if (!connected_controllers[controller_idx].is_connected) { | 325 | if (!connected_controllers[controller_idx].is_connected) { |
| 265 | return; | 326 | return; |
| 266 | } | 327 | } |
| @@ -269,61 +330,69 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | |||
| 269 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; | 330 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; |
| 270 | const auto& button_state = buttons[controller_idx]; | 331 | const auto& button_state = buttons[controller_idx]; |
| 271 | const auto& analog_state = sticks[controller_idx]; | 332 | const auto& analog_state = sticks[controller_idx]; |
| 272 | const auto& motion_state = motions[controller_idx]; | ||
| 273 | const auto [stick_l_x_f, stick_l_y_f] = | 333 | const auto [stick_l_x_f, stick_l_y_f] = |
| 274 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | 334 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); |
| 275 | const auto [stick_r_x_f, stick_r_y_f] = | 335 | const auto [stick_r_x_f, stick_r_y_f] = |
| 276 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | 336 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); |
| 277 | 337 | ||
| 278 | using namespace Settings::NativeButton; | 338 | using namespace Settings::NativeButton; |
| 279 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); | 339 | if (controller_type != NPadControllerType::JoyLeft) { |
| 280 | pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); | 340 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); |
| 281 | pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); | 341 | pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); |
| 282 | pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); | 342 | pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); |
| 283 | pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); | 343 | pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); |
| 284 | pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); | 344 | pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); |
| 285 | pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); | 345 | pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); |
| 286 | pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); | 346 | pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); |
| 287 | pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); | 347 | pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); |
| 288 | pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); | 348 | |
| 289 | pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); | 349 | pad_state.r_stick_right.Assign( |
| 290 | pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); | 350 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 291 | 351 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | |
| 292 | pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | 352 | pad_state.r_stick_left.Assign( |
| 293 | pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); | 353 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 294 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); | 354 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); |
| 295 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | 355 | pad_state.r_stick_up.Assign( |
| 296 | 356 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | |
| 297 | pad_state.l_stick_right.Assign( | 357 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); |
| 298 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 358 | pad_state.r_stick_down.Assign( |
| 299 | Input::AnalogDirection::RIGHT)); | 359 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 300 | pad_state.l_stick_left.Assign( | 360 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); |
| 301 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 361 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); |
| 302 | Input::AnalogDirection::LEFT)); | 362 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); |
| 303 | pad_state.l_stick_up.Assign( | 363 | } |
| 304 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 364 | |
| 305 | Input::AnalogDirection::UP)); | 365 | if (controller_type != NPadControllerType::JoyRight) { |
| 306 | pad_state.l_stick_down.Assign( | 366 | pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); |
| 307 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 367 | pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); |
| 308 | Input::AnalogDirection::DOWN)); | 368 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); |
| 309 | 369 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | |
| 310 | pad_state.r_stick_right.Assign( | 370 | pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); |
| 311 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 371 | pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); |
| 312 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | 372 | pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); |
| 313 | pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 373 | pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); |
| 314 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); | 374 | |
| 315 | pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 375 | pad_state.l_stick_right.Assign( |
| 316 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); | 376 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] |
| 317 | pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 377 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); |
| 318 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); | 378 | pad_state.l_stick_left.Assign( |
| 319 | 379 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | |
| 320 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | 380 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); |
| 321 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | 381 | pad_state.l_stick_up.Assign( |
| 322 | 382 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | |
| 323 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | 383 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); |
| 324 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | 384 | pad_state.l_stick_down.Assign( |
| 325 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | 385 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] |
| 326 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | 386 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); |
| 387 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 388 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 389 | } | ||
| 390 | |||
| 391 | if (controller_type == NPadControllerType::JoyLeft || | ||
| 392 | controller_type == NPadControllerType::JoyRight) { | ||
| 393 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 394 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 395 | } | ||
| 327 | } | 396 | } |
| 328 | 397 | ||
| 329 | void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 398 | void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| @@ -331,7 +400,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 331 | if (!IsControllerActivated()) { | 400 | if (!IsControllerActivated()) { |
| 332 | return; | 401 | return; |
| 333 | } | 402 | } |
| 334 | for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { | 403 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { |
| 335 | auto& npad = shared_memory_entries[i]; | 404 | auto& npad = shared_memory_entries[i]; |
| 336 | const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, | 405 | const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, |
| 337 | &npad.handheld_states, | 406 | &npad.handheld_states, |
| @@ -365,6 +434,123 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 365 | } | 434 | } |
| 366 | const u32 npad_index = static_cast<u32>(i); | 435 | const u32 npad_index = static_cast<u32>(i); |
| 367 | 436 | ||
| 437 | RequestPadStateUpdate(npad_index); | ||
| 438 | auto& pad_state = npad_pad_states[npad_index]; | ||
| 439 | |||
| 440 | auto& main_controller = | ||
| 441 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; | ||
| 442 | auto& handheld_entry = | ||
| 443 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; | ||
| 444 | auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; | ||
| 445 | auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; | ||
| 446 | auto& right_entry = | ||
| 447 | npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; | ||
| 448 | auto& pokeball_entry = | ||
| 449 | npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; | ||
| 450 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; | ||
| 451 | |||
| 452 | libnx_entry.connection_status.raw = 0; | ||
| 453 | libnx_entry.connection_status.IsConnected.Assign(1); | ||
| 454 | |||
| 455 | switch (controller_type) { | ||
| 456 | case NPadControllerType::None: | ||
| 457 | UNREACHABLE(); | ||
| 458 | break; | ||
| 459 | case NPadControllerType::ProController: | ||
| 460 | main_controller.connection_status.raw = 0; | ||
| 461 | main_controller.connection_status.IsConnected.Assign(1); | ||
| 462 | main_controller.connection_status.IsWired.Assign(1); | ||
| 463 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 464 | main_controller.pad.l_stick = pad_state.l_stick; | ||
| 465 | main_controller.pad.r_stick = pad_state.r_stick; | ||
| 466 | |||
| 467 | libnx_entry.connection_status.IsWired.Assign(1); | ||
| 468 | break; | ||
| 469 | case NPadControllerType::Handheld: | ||
| 470 | handheld_entry.connection_status.raw = 0; | ||
| 471 | handheld_entry.connection_status.IsConnected.Assign(1); | ||
| 472 | handheld_entry.connection_status.IsWired.Assign(1); | ||
| 473 | handheld_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 474 | handheld_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 475 | handheld_entry.connection_status.IsLeftJoyWired.Assign(1); | ||
| 476 | handheld_entry.connection_status.IsRightJoyWired.Assign(1); | ||
| 477 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 478 | handheld_entry.pad.l_stick = pad_state.l_stick; | ||
| 479 | handheld_entry.pad.r_stick = pad_state.r_stick; | ||
| 480 | |||
| 481 | libnx_entry.connection_status.IsWired.Assign(1); | ||
| 482 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 483 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 484 | libnx_entry.connection_status.IsLeftJoyWired.Assign(1); | ||
| 485 | libnx_entry.connection_status.IsRightJoyWired.Assign(1); | ||
| 486 | break; | ||
| 487 | case NPadControllerType::JoyDual: | ||
| 488 | dual_entry.connection_status.raw = 0; | ||
| 489 | dual_entry.connection_status.IsConnected.Assign(1); | ||
| 490 | dual_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 491 | dual_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 492 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 493 | dual_entry.pad.l_stick = pad_state.l_stick; | ||
| 494 | dual_entry.pad.r_stick = pad_state.r_stick; | ||
| 495 | |||
| 496 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 497 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 498 | break; | ||
| 499 | case NPadControllerType::JoyLeft: | ||
| 500 | left_entry.connection_status.raw = 0; | ||
| 501 | left_entry.connection_status.IsConnected.Assign(1); | ||
| 502 | left_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 503 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 504 | left_entry.pad.l_stick = pad_state.l_stick; | ||
| 505 | left_entry.pad.r_stick = pad_state.r_stick; | ||
| 506 | |||
| 507 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 508 | break; | ||
| 509 | case NPadControllerType::JoyRight: | ||
| 510 | right_entry.connection_status.raw = 0; | ||
| 511 | right_entry.connection_status.IsConnected.Assign(1); | ||
| 512 | right_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 513 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 514 | right_entry.pad.l_stick = pad_state.l_stick; | ||
| 515 | right_entry.pad.r_stick = pad_state.r_stick; | ||
| 516 | |||
| 517 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 518 | break; | ||
| 519 | case NPadControllerType::Pokeball: | ||
| 520 | pokeball_entry.connection_status.raw = 0; | ||
| 521 | pokeball_entry.connection_status.IsConnected.Assign(1); | ||
| 522 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 523 | pokeball_entry.pad.l_stick = pad_state.l_stick; | ||
| 524 | pokeball_entry.pad.r_stick = pad_state.r_stick; | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | |||
| 528 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | ||
| 529 | // any controllers. | ||
| 530 | libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 531 | libnx_entry.pad.l_stick = pad_state.l_stick; | ||
| 532 | libnx_entry.pad.r_stick = pad_state.r_stick; | ||
| 533 | |||
| 534 | press_state |= static_cast<u32>(pad_state.pad_states.raw); | ||
| 535 | } | ||
| 536 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | ||
| 537 | shared_memory_entries.size() * sizeof(NPadEntry)); | ||
| 538 | } | ||
| 539 | |||
| 540 | void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||
| 541 | std::size_t data_len) { | ||
| 542 | if (!IsControllerActivated()) { | ||
| 543 | return; | ||
| 544 | } | ||
| 545 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { | ||
| 546 | auto& npad = shared_memory_entries[i]; | ||
| 547 | |||
| 548 | const auto& controller_type = connected_controllers[i].type; | ||
| 549 | |||
| 550 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { | ||
| 551 | continue; | ||
| 552 | } | ||
| 553 | |||
| 368 | const std::array<SixAxisGeneric*, 6> controller_sixaxes{ | 554 | const std::array<SixAxisGeneric*, 6> controller_sixaxes{ |
| 369 | &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, | 555 | &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, |
| 370 | &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, | 556 | &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, |
| @@ -390,7 +576,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 390 | // Try to read sixaxis sensor states | 576 | // Try to read sixaxis sensor states |
| 391 | std::array<MotionDevice, 2> motion_devices; | 577 | std::array<MotionDevice, 2> motion_devices; |
| 392 | 578 | ||
| 393 | if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { | 579 | if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) { |
| 394 | sixaxis_at_rest = true; | 580 | sixaxis_at_rest = true; |
| 395 | for (std::size_t e = 0; e < motion_devices.size(); ++e) { | 581 | for (std::size_t e = 0; e < motion_devices.size(); ++e) { |
| 396 | const auto& device = motions[i][e]; | 582 | const auto& device = motions[i][e]; |
| @@ -403,23 +589,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 403 | } | 589 | } |
| 404 | } | 590 | } |
| 405 | 591 | ||
| 406 | RequestPadStateUpdate(npad_index); | ||
| 407 | auto& pad_state = npad_pad_states[npad_index]; | ||
| 408 | |||
| 409 | auto& main_controller = | ||
| 410 | npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; | ||
| 411 | auto& handheld_entry = | ||
| 412 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; | ||
| 413 | auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index]; | ||
| 414 | auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index]; | ||
| 415 | auto& right_entry = | ||
| 416 | npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index]; | ||
| 417 | auto& pokeball_entry = | ||
| 418 | npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; | ||
| 419 | auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; | ||
| 420 | |||
| 421 | libnx_entry.connection_status.raw = 0; | ||
| 422 | libnx_entry.connection_status.IsConnected.Assign(1); | ||
| 423 | auto& full_sixaxis_entry = | 592 | auto& full_sixaxis_entry = |
| 424 | npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; | 593 | npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; |
| 425 | auto& handheld_sixaxis_entry = | 594 | auto& handheld_sixaxis_entry = |
| @@ -438,15 +607,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 438 | UNREACHABLE(); | 607 | UNREACHABLE(); |
| 439 | break; | 608 | break; |
| 440 | case NPadControllerType::ProController: | 609 | case NPadControllerType::ProController: |
| 441 | main_controller.connection_status.raw = 0; | ||
| 442 | main_controller.connection_status.IsConnected.Assign(1); | ||
| 443 | main_controller.connection_status.IsWired.Assign(1); | ||
| 444 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 445 | main_controller.pad.l_stick = pad_state.l_stick; | ||
| 446 | main_controller.pad.r_stick = pad_state.r_stick; | ||
| 447 | |||
| 448 | libnx_entry.connection_status.IsWired.Assign(1); | ||
| 449 | |||
| 450 | if (sixaxis_sensors_enabled && motions[i][0]) { | 610 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 451 | full_sixaxis_entry.accel = motion_devices[0].accel; | 611 | full_sixaxis_entry.accel = motion_devices[0].accel; |
| 452 | full_sixaxis_entry.gyro = motion_devices[0].gyro; | 612 | full_sixaxis_entry.gyro = motion_devices[0].gyro; |
| @@ -455,23 +615,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 455 | } | 615 | } |
| 456 | break; | 616 | break; |
| 457 | case NPadControllerType::Handheld: | 617 | case NPadControllerType::Handheld: |
| 458 | handheld_entry.connection_status.raw = 0; | ||
| 459 | handheld_entry.connection_status.IsConnected.Assign(1); | ||
| 460 | handheld_entry.connection_status.IsWired.Assign(1); | ||
| 461 | handheld_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 462 | handheld_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 463 | handheld_entry.connection_status.IsLeftJoyWired.Assign(1); | ||
| 464 | handheld_entry.connection_status.IsRightJoyWired.Assign(1); | ||
| 465 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 466 | handheld_entry.pad.l_stick = pad_state.l_stick; | ||
| 467 | handheld_entry.pad.r_stick = pad_state.r_stick; | ||
| 468 | |||
| 469 | libnx_entry.connection_status.IsWired.Assign(1); | ||
| 470 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 471 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 472 | libnx_entry.connection_status.IsLeftJoyWired.Assign(1); | ||
| 473 | libnx_entry.connection_status.IsRightJoyWired.Assign(1); | ||
| 474 | |||
| 475 | if (sixaxis_sensors_enabled && motions[i][0]) { | 618 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 476 | handheld_sixaxis_entry.accel = motion_devices[0].accel; | 619 | handheld_sixaxis_entry.accel = motion_devices[0].accel; |
| 477 | handheld_sixaxis_entry.gyro = motion_devices[0].gyro; | 620 | handheld_sixaxis_entry.gyro = motion_devices[0].gyro; |
| @@ -480,17 +623,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 480 | } | 623 | } |
| 481 | break; | 624 | break; |
| 482 | case NPadControllerType::JoyDual: | 625 | case NPadControllerType::JoyDual: |
| 483 | dual_entry.connection_status.raw = 0; | ||
| 484 | dual_entry.connection_status.IsConnected.Assign(1); | ||
| 485 | dual_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 486 | dual_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 487 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 488 | dual_entry.pad.l_stick = pad_state.l_stick; | ||
| 489 | dual_entry.pad.r_stick = pad_state.r_stick; | ||
| 490 | |||
| 491 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 492 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 493 | |||
| 494 | if (sixaxis_sensors_enabled && motions[i][0]) { | 626 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 495 | // Set motion for the left joycon | 627 | // Set motion for the left joycon |
| 496 | dual_left_sixaxis_entry.accel = motion_devices[0].accel; | 628 | dual_left_sixaxis_entry.accel = motion_devices[0].accel; |
| @@ -507,15 +639,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 507 | } | 639 | } |
| 508 | break; | 640 | break; |
| 509 | case NPadControllerType::JoyLeft: | 641 | case NPadControllerType::JoyLeft: |
| 510 | left_entry.connection_status.raw = 0; | ||
| 511 | left_entry.connection_status.IsConnected.Assign(1); | ||
| 512 | left_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 513 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 514 | left_entry.pad.l_stick = pad_state.l_stick; | ||
| 515 | left_entry.pad.r_stick = pad_state.r_stick; | ||
| 516 | |||
| 517 | libnx_entry.connection_status.IsLeftJoyConnected.Assign(1); | ||
| 518 | |||
| 519 | if (sixaxis_sensors_enabled && motions[i][0]) { | 642 | if (sixaxis_sensors_enabled && motions[i][0]) { |
| 520 | left_sixaxis_entry.accel = motion_devices[0].accel; | 643 | left_sixaxis_entry.accel = motion_devices[0].accel; |
| 521 | left_sixaxis_entry.gyro = motion_devices[0].gyro; | 644 | left_sixaxis_entry.gyro = motion_devices[0].gyro; |
| @@ -524,15 +647,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 524 | } | 647 | } |
| 525 | break; | 648 | break; |
| 526 | case NPadControllerType::JoyRight: | 649 | case NPadControllerType::JoyRight: |
| 527 | right_entry.connection_status.raw = 0; | ||
| 528 | right_entry.connection_status.IsConnected.Assign(1); | ||
| 529 | right_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 530 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 531 | right_entry.pad.l_stick = pad_state.l_stick; | ||
| 532 | right_entry.pad.r_stick = pad_state.r_stick; | ||
| 533 | |||
| 534 | libnx_entry.connection_status.IsRightJoyConnected.Assign(1); | ||
| 535 | |||
| 536 | if (sixaxis_sensors_enabled && motions[i][1]) { | 650 | if (sixaxis_sensors_enabled && motions[i][1]) { |
| 537 | right_sixaxis_entry.accel = motion_devices[1].accel; | 651 | right_sixaxis_entry.accel = motion_devices[1].accel; |
| 538 | right_sixaxis_entry.gyro = motion_devices[1].gyro; | 652 | right_sixaxis_entry.gyro = motion_devices[1].gyro; |
| @@ -541,35 +655,22 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 541 | } | 655 | } |
| 542 | break; | 656 | break; |
| 543 | case NPadControllerType::Pokeball: | 657 | case NPadControllerType::Pokeball: |
| 544 | pokeball_entry.connection_status.raw = 0; | ||
| 545 | pokeball_entry.connection_status.IsConnected.Assign(1); | ||
| 546 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 547 | pokeball_entry.pad.l_stick = pad_state.l_stick; | ||
| 548 | pokeball_entry.pad.r_stick = pad_state.r_stick; | ||
| 549 | break; | 658 | break; |
| 550 | } | 659 | } |
| 551 | |||
| 552 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | ||
| 553 | // any controllers. | ||
| 554 | libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; | ||
| 555 | libnx_entry.pad.l_stick = pad_state.l_stick; | ||
| 556 | libnx_entry.pad.r_stick = pad_state.r_stick; | ||
| 557 | |||
| 558 | press_state |= static_cast<u32>(pad_state.pad_states.raw); | ||
| 559 | } | 660 | } |
| 560 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | 661 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), |
| 561 | shared_memory_entries.size() * sizeof(NPadEntry)); | 662 | shared_memory_entries.size() * sizeof(NPadEntry)); |
| 562 | } | 663 | } |
| 563 | 664 | ||
| 564 | void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { | 665 | void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) { |
| 565 | style.raw = style_set.raw; | 666 | style.raw = style_set.raw; |
| 566 | } | 667 | } |
| 567 | 668 | ||
| 568 | Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { | 669 | Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const { |
| 569 | return style; | 670 | return style; |
| 570 | } | 671 | } |
| 571 | 672 | ||
| 572 | void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | 673 | void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { |
| 573 | ASSERT(length > 0 && (length % sizeof(u32)) == 0); | 674 | ASSERT(length > 0 && (length % sizeof(u32)) == 0); |
| 574 | supported_npad_id_types.clear(); | 675 | supported_npad_id_types.clear(); |
| 575 | supported_npad_id_types.resize(length / sizeof(u32)); | 676 | supported_npad_id_types.resize(length / sizeof(u32)); |
| @@ -581,7 +682,7 @@ void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) | |||
| 581 | std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); | 682 | std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); |
| 582 | } | 683 | } |
| 583 | 684 | ||
| 584 | std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { | 685 | std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { |
| 585 | return supported_npad_id_types.size(); | 686 | return supported_npad_id_types.size(); |
| 586 | } | 687 | } |
| 587 | 688 | ||
| @@ -601,7 +702,15 @@ Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActi | |||
| 601 | return handheld_activation_mode; | 702 | return handheld_activation_mode; |
| 602 | } | 703 | } |
| 603 | 704 | ||
| 604 | void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { | 705 | void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { |
| 706 | communication_mode = communication_mode_; | ||
| 707 | } | ||
| 708 | |||
| 709 | Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const { | ||
| 710 | return communication_mode; | ||
| 711 | } | ||
| 712 | |||
| 713 | void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { | ||
| 605 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 714 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 606 | ASSERT(npad_index < shared_memory_entries.size()); | 715 | ASSERT(npad_index < shared_memory_entries.size()); |
| 607 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { | 716 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { |
| @@ -609,24 +718,156 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) | |||
| 609 | } | 718 | } |
| 610 | } | 719 | } |
| 611 | 720 | ||
| 612 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 721 | bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, |
| 613 | const std::vector<Vibration>& vibrations) { | 722 | const VibrationValue& vibration_value) { |
| 614 | LOG_DEBUG(Service_HID, "(STUBBED) called"); | 723 | if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { |
| 724 | return false; | ||
| 725 | } | ||
| 615 | 726 | ||
| 616 | if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { | 727 | const auto& player = Settings::values.players.GetValue()[npad_index]; |
| 617 | return; | 728 | |
| 729 | if (!player.vibration_enabled) { | ||
| 730 | if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || | ||
| 731 | latest_vibration_values[npad_index][device_index].amp_high != 0.0f) { | ||
| 732 | // Send an empty vibration to stop any vibrations. | ||
| 733 | vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); | ||
| 734 | // Then reset the vibration value to its default value. | ||
| 735 | latest_vibration_values[npad_index][device_index] = {}; | ||
| 736 | } | ||
| 737 | |||
| 738 | return false; | ||
| 618 | } | 739 | } |
| 619 | for (std::size_t i = 0; i < controller_ids.size(); i++) { | 740 | |
| 620 | std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); | 741 | if (!Settings::values.enable_accurate_vibrations.GetValue()) { |
| 621 | if (connected_controllers[controller_pos].is_connected) { | 742 | using std::chrono::duration_cast; |
| 622 | // TODO(ogniK): Vibrate the physical controller | 743 | using std::chrono::milliseconds; |
| 744 | using std::chrono::steady_clock; | ||
| 745 | |||
| 746 | const auto now = steady_clock::now(); | ||
| 747 | |||
| 748 | // Filter out non-zero vibrations that are within 10ms of each other. | ||
| 749 | if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && | ||
| 750 | duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) < | ||
| 751 | milliseconds(10)) { | ||
| 752 | return false; | ||
| 623 | } | 753 | } |
| 754 | |||
| 755 | last_vibration_timepoints[npad_index][device_index] = now; | ||
| 756 | } | ||
| 757 | |||
| 758 | auto& vibration = vibrations[npad_index][device_index]; | ||
| 759 | const auto player_vibration_strength = static_cast<f32>(player.vibration_strength); | ||
| 760 | const auto amp_low = | ||
| 761 | std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f); | ||
| 762 | const auto amp_high = | ||
| 763 | std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f); | ||
| 764 | return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high, | ||
| 765 | vibration_value.freq_high); | ||
| 766 | } | ||
| 767 | |||
| 768 | void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, | ||
| 769 | const VibrationValue& vibration_value) { | ||
| 770 | if (!IsDeviceHandleValid(vibration_device_handle)) { | ||
| 771 | return; | ||
| 772 | } | ||
| 773 | |||
| 774 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | ||
| 775 | return; | ||
| 776 | } | ||
| 777 | |||
| 778 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | ||
| 779 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 780 | |||
| 781 | if (!vibration_devices_mounted[npad_index][device_index] || | ||
| 782 | !connected_controllers[npad_index].is_connected) { | ||
| 783 | return; | ||
| 784 | } | ||
| 785 | |||
| 786 | if (vibration_device_handle.device_index == DeviceIndex::None) { | ||
| 787 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | ||
| 788 | return; | ||
| 789 | } | ||
| 790 | |||
| 791 | // Some games try to send mismatched parameters in the device handle, block these. | ||
| 792 | if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && | ||
| 793 | (vibration_device_handle.npad_type == NpadType::JoyconRight || | ||
| 794 | vibration_device_handle.device_index == DeviceIndex::Right)) || | ||
| 795 | (connected_controllers[npad_index].type == NPadControllerType::JoyRight && | ||
| 796 | (vibration_device_handle.npad_type == NpadType::JoyconLeft || | ||
| 797 | vibration_device_handle.device_index == DeviceIndex::Left))) { | ||
| 798 | return; | ||
| 799 | } | ||
| 800 | |||
| 801 | // Filter out vibrations with equivalent values to reduce unnecessary state changes. | ||
| 802 | if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low && | ||
| 803 | vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) { | ||
| 804 | return; | ||
| 805 | } | ||
| 806 | |||
| 807 | if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { | ||
| 808 | latest_vibration_values[npad_index][device_index] = vibration_value; | ||
| 624 | } | 809 | } |
| 625 | last_processed_vibration = vibrations.back(); | ||
| 626 | } | 810 | } |
| 627 | 811 | ||
| 628 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 812 | void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, |
| 629 | return last_processed_vibration; | 813 | const std::vector<VibrationValue>& vibration_values) { |
| 814 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | ||
| 815 | return; | ||
| 816 | } | ||
| 817 | |||
| 818 | ASSERT_OR_EXECUTE_MSG( | ||
| 819 | vibration_device_handles.size() == vibration_values.size(), { return; }, | ||
| 820 | "The amount of device handles does not match with the amount of vibration values," | ||
| 821 | "this is undefined behavior!"); | ||
| 822 | |||
| 823 | for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { | ||
| 824 | VibrateController(vibration_device_handles[i], vibration_values[i]); | ||
| 825 | } | ||
| 826 | } | ||
| 827 | |||
| 828 | Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( | ||
| 829 | const DeviceHandle& vibration_device_handle) const { | ||
| 830 | if (!IsDeviceHandleValid(vibration_device_handle)) { | ||
| 831 | return {}; | ||
| 832 | } | ||
| 833 | |||
| 834 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | ||
| 835 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 836 | return latest_vibration_values[npad_index][device_index]; | ||
| 837 | } | ||
| 838 | |||
| 839 | void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { | ||
| 840 | if (!IsDeviceHandleValid(vibration_device_handle)) { | ||
| 841 | return; | ||
| 842 | } | ||
| 843 | |||
| 844 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | ||
| 845 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 846 | InitializeVibrationDeviceAtIndex(npad_index, device_index); | ||
| 847 | } | ||
| 848 | |||
| 849 | void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, | ||
| 850 | std::size_t device_index) { | ||
| 851 | if (vibrations[npad_index][device_index]) { | ||
| 852 | vibration_devices_mounted[npad_index][device_index] = | ||
| 853 | vibrations[npad_index][device_index]->GetStatus() == 1; | ||
| 854 | } else { | ||
| 855 | vibration_devices_mounted[npad_index][device_index] = false; | ||
| 856 | } | ||
| 857 | } | ||
| 858 | |||
| 859 | void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { | ||
| 860 | permit_vibration_session_enabled = permit_vibration_session; | ||
| 861 | } | ||
| 862 | |||
| 863 | bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { | ||
| 864 | if (!IsDeviceHandleValid(vibration_device_handle)) { | ||
| 865 | return false; | ||
| 866 | } | ||
| 867 | |||
| 868 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | ||
| 869 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 870 | return vibration_devices_mounted[npad_index][device_index]; | ||
| 630 | } | 871 | } |
| 631 | 872 | ||
| 632 | std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { | 873 | std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { |
| @@ -645,31 +886,38 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz | |||
| 645 | void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, | 886 | void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, |
| 646 | bool connected) { | 887 | bool connected) { |
| 647 | if (!connected) { | 888 | if (!connected) { |
| 648 | DisconnectNPadAtIndex(npad_index); | 889 | DisconnectNpadAtIndex(npad_index); |
| 649 | return; | 890 | return; |
| 650 | } | 891 | } |
| 651 | 892 | ||
| 652 | if (controller == NPadControllerType::Handheld) { | 893 | if (controller == NPadControllerType::Handheld) { |
| 653 | Settings::values.players[HANDHELD_INDEX].controller_type = | 894 | Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = |
| 654 | MapNPadToSettingsType(controller); | 895 | MapNPadToSettingsType(controller); |
| 655 | Settings::values.players[HANDHELD_INDEX].connected = true; | 896 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; |
| 656 | connected_controllers[HANDHELD_INDEX] = {controller, true}; | 897 | connected_controllers[HANDHELD_INDEX] = {controller, true}; |
| 657 | InitNewlyAddedController(HANDHELD_INDEX); | 898 | InitNewlyAddedController(HANDHELD_INDEX); |
| 658 | return; | 899 | return; |
| 659 | } | 900 | } |
| 660 | 901 | ||
| 661 | Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller); | 902 | Settings::values.players.GetValue()[npad_index].controller_type = |
| 662 | Settings::values.players[npad_index].connected = true; | 903 | MapNPadToSettingsType(controller); |
| 904 | Settings::values.players.GetValue()[npad_index].connected = true; | ||
| 663 | connected_controllers[npad_index] = {controller, true}; | 905 | connected_controllers[npad_index] = {controller, true}; |
| 664 | InitNewlyAddedController(npad_index); | 906 | InitNewlyAddedController(npad_index); |
| 665 | } | 907 | } |
| 666 | 908 | ||
| 667 | void Controller_NPad::DisconnectNPad(u32 npad_id) { | 909 | void Controller_NPad::DisconnectNpad(u32 npad_id) { |
| 668 | DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); | 910 | DisconnectNpadAtIndex(NPadIdToIndex(npad_id)); |
| 669 | } | 911 | } |
| 670 | 912 | ||
| 671 | void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { | 913 | void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { |
| 672 | Settings::values.players[npad_index].connected = false; | 914 | for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { |
| 915 | // Send an empty vibration to stop any vibrations. | ||
| 916 | VibrateControllerAtIndex(npad_index, device_idx, {}); | ||
| 917 | vibration_devices_mounted[npad_index][device_idx] = false; | ||
| 918 | } | ||
| 919 | |||
| 920 | Settings::values.players.GetValue()[npad_index].connected = false; | ||
| 673 | connected_controllers[npad_index].is_connected = false; | 921 | connected_controllers[npad_index].is_connected = false; |
| 674 | 922 | ||
| 675 | auto& controller = shared_memory_entries[npad_index]; | 923 | auto& controller = shared_memory_entries[npad_index]; |
| @@ -707,7 +955,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { | |||
| 707 | (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && | 955 | (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && |
| 708 | connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { | 956 | connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { |
| 709 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. | 957 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. |
| 710 | DisconnectNPad(npad_id_2); | 958 | DisconnectNpad(npad_id_2); |
| 711 | AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); | 959 | AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); |
| 712 | } | 960 | } |
| 713 | } | 961 | } |
| @@ -770,12 +1018,13 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { | |||
| 770 | } | 1018 | } |
| 771 | } | 1019 | } |
| 772 | 1020 | ||
| 773 | void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { | 1021 | bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { |
| 774 | can_controllers_vibrate = can_vibrate; | 1022 | return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; |
| 775 | } | 1023 | } |
| 776 | 1024 | ||
| 777 | bool Controller_NPad::IsVibrationEnabled() const { | 1025 | void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, |
| 778 | return can_controllers_vibrate; | 1026 | u32 npad_id) { |
| 1027 | unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; | ||
| 779 | } | 1028 | } |
| 780 | 1029 | ||
| 781 | void Controller_NPad::ClearAllConnectedControllers() { | 1030 | void Controller_NPad::ClearAllConnectedControllers() { |
| @@ -809,7 +1058,7 @@ void Controller_NPad::ClearAllControllers() { | |||
| 809 | } | 1058 | } |
| 810 | 1059 | ||
| 811 | u32 Controller_NPad::GetAndResetPressState() { | 1060 | u32 Controller_NPad::GetAndResetPressState() { |
| 812 | return std::exchange(press_state, 0); | 1061 | return press_state.exchange(0); |
| 813 | } | 1062 | } |
| 814 | 1063 | ||
| 815 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { | 1064 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { |
| @@ -822,7 +1071,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const | |||
| 822 | return false; | 1071 | return false; |
| 823 | } | 1072 | } |
| 824 | // Handheld should not be supported in docked mode | 1073 | // Handheld should not be supported in docked mode |
| 825 | if (Settings::values.use_docked_mode) { | 1074 | if (Settings::values.use_docked_mode.GetValue()) { |
| 826 | return false; | 1075 | return false; |
| 827 | } | 1076 | } |
| 828 | 1077 | ||
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 654d97c3f..e2e826623 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <atomic> | ||
| 8 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "core/frontend/input.h" | 11 | #include "core/frontend/input.h" |
| @@ -32,31 +33,39 @@ public: | |||
| 32 | // When the controller is requesting an update for the shared memory | 33 | // When the controller is requesting an update for the shared memory |
| 33 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 34 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 34 | 35 | ||
| 36 | // When the controller is requesting a motion update for the shared memory | ||
| 37 | void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | ||
| 38 | std::size_t size) override; | ||
| 39 | |||
| 35 | // Called when input devices should be loaded | 40 | // Called when input devices should be loaded |
| 36 | void OnLoadInputDevices() override; | 41 | void OnLoadInputDevices() override; |
| 37 | 42 | ||
| 38 | struct NPadType { | 43 | enum class NPadControllerType { |
| 39 | union { | 44 | None, |
| 40 | u32_le raw{}; | 45 | ProController, |
| 41 | 46 | Handheld, | |
| 42 | BitField<0, 1, u32> pro_controller; | 47 | JoyDual, |
| 43 | BitField<1, 1, u32> handheld; | 48 | JoyLeft, |
| 44 | BitField<2, 1, u32> joycon_dual; | 49 | JoyRight, |
| 45 | BitField<3, 1, u32> joycon_left; | 50 | Pokeball, |
| 46 | BitField<4, 1, u32> joycon_right; | 51 | }; |
| 47 | 52 | ||
| 48 | BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible | 53 | enum class NpadType : u8 { |
| 49 | }; | 54 | ProController = 3, |
| 55 | Handheld = 4, | ||
| 56 | JoyconDual = 5, | ||
| 57 | JoyconLeft = 6, | ||
| 58 | JoyconRight = 7, | ||
| 59 | Pokeball = 9, | ||
| 60 | MaxNpadType = 10, | ||
| 50 | }; | 61 | }; |
| 51 | static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); | ||
| 52 | 62 | ||
| 53 | struct Vibration { | 63 | enum class DeviceIndex : u8 { |
| 54 | f32 amp_low; | 64 | Left = 0, |
| 55 | f32 freq_low; | 65 | Right = 1, |
| 56 | f32 amp_high; | 66 | None = 2, |
| 57 | f32 freq_high; | 67 | MaxDeviceIndex = 3, |
| 58 | }; | 68 | }; |
| 59 | static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size"); | ||
| 60 | 69 | ||
| 61 | enum class GyroscopeZeroDriftMode : u32 { | 70 | enum class GyroscopeZeroDriftMode : u32 { |
| 62 | Loose = 0, | 71 | Loose = 0, |
| @@ -69,7 +78,7 @@ public: | |||
| 69 | Horizontal = 1, | 78 | Horizontal = 1, |
| 70 | }; | 79 | }; |
| 71 | 80 | ||
| 72 | enum class NPadAssignments : u32_le { | 81 | enum class NpadAssignments : u32 { |
| 73 | Dual = 0, | 82 | Dual = 0, |
| 74 | Single = 1, | 83 | Single = 1, |
| 75 | }; | 84 | }; |
| @@ -80,15 +89,43 @@ public: | |||
| 80 | None = 2, | 89 | None = 2, |
| 81 | }; | 90 | }; |
| 82 | 91 | ||
| 83 | enum class NPadControllerType { | 92 | enum class NpadCommunicationMode : u64 { |
| 84 | None, | 93 | Unknown0 = 0, |
| 85 | ProController, | 94 | Unknown1 = 1, |
| 86 | Handheld, | 95 | Unknown2 = 2, |
| 87 | JoyDual, | 96 | Unknown3 = 3, |
| 88 | JoyLeft, | 97 | }; |
| 89 | JoyRight, | 98 | |
| 90 | Pokeball, | 99 | struct DeviceHandle { |
| 100 | NpadType npad_type{}; | ||
| 101 | u8 npad_id{}; | ||
| 102 | DeviceIndex device_index{}; | ||
| 103 | INSERT_PADDING_BYTES(1); | ||
| 104 | }; | ||
| 105 | static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); | ||
| 106 | |||
| 107 | struct NpadStyleSet { | ||
| 108 | union { | ||
| 109 | u32_le raw{}; | ||
| 110 | |||
| 111 | BitField<0, 1, u32> pro_controller; | ||
| 112 | BitField<1, 1, u32> handheld; | ||
| 113 | BitField<2, 1, u32> joycon_dual; | ||
| 114 | BitField<3, 1, u32> joycon_left; | ||
| 115 | BitField<4, 1, u32> joycon_right; | ||
| 116 | |||
| 117 | BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible | ||
| 118 | }; | ||
| 91 | }; | 119 | }; |
| 120 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); | ||
| 121 | |||
| 122 | struct VibrationValue { | ||
| 123 | f32 amp_low{0.0f}; | ||
| 124 | f32 freq_low{160.0f}; | ||
| 125 | f32 amp_high{0.0f}; | ||
| 126 | f32 freq_high{320.0f}; | ||
| 127 | }; | ||
| 128 | static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); | ||
| 92 | 129 | ||
| 93 | struct LedPattern { | 130 | struct LedPattern { |
| 94 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | 131 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { |
| @@ -106,12 +143,12 @@ public: | |||
| 106 | }; | 143 | }; |
| 107 | }; | 144 | }; |
| 108 | 145 | ||
| 109 | void SetSupportedStyleSet(NPadType style_set); | 146 | void SetSupportedStyleSet(NpadStyleSet style_set); |
| 110 | NPadType GetSupportedStyleSet() const; | 147 | NpadStyleSet GetSupportedStyleSet() const; |
| 111 | 148 | ||
| 112 | void SetSupportedNPadIdTypes(u8* data, std::size_t length); | 149 | void SetSupportedNpadIdTypes(u8* data, std::size_t length); |
| 113 | void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); | 150 | void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); |
| 114 | std::size_t GetSupportedNPadIdTypesSize() const; | 151 | std::size_t GetSupportedNpadIdTypesSize() const; |
| 115 | 152 | ||
| 116 | void SetHoldType(NpadHoldType joy_hold_type); | 153 | void SetHoldType(NpadHoldType joy_hold_type); |
| 117 | NpadHoldType GetHoldType() const; | 154 | NpadHoldType GetHoldType() const; |
| @@ -119,12 +156,29 @@ public: | |||
| 119 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); | 156 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); |
| 120 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; | 157 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; |
| 121 | 158 | ||
| 122 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); | 159 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); |
| 160 | NpadCommunicationMode GetNpadCommunicationMode() const; | ||
| 161 | |||
| 162 | void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); | ||
| 163 | |||
| 164 | bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, | ||
| 165 | const VibrationValue& vibration_value); | ||
| 166 | |||
| 167 | void VibrateController(const DeviceHandle& vibration_device_handle, | ||
| 168 | const VibrationValue& vibration_value); | ||
| 169 | |||
| 170 | void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, | ||
| 171 | const std::vector<VibrationValue>& vibration_values); | ||
| 172 | |||
| 173 | VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; | ||
| 174 | |||
| 175 | void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); | ||
| 176 | |||
| 177 | void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); | ||
| 123 | 178 | ||
| 124 | void VibrateController(const std::vector<u32>& controller_ids, | 179 | void SetPermitVibrationSession(bool permit_vibration_session); |
| 125 | const std::vector<Vibration>& vibrations); | ||
| 126 | 180 | ||
| 127 | Vibration GetLastVibration() const; | 181 | bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; |
| 128 | 182 | ||
| 129 | std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; | 183 | std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; |
| 130 | void SignalStyleSetChangedEvent(u32 npad_id) const; | 184 | void SignalStyleSetChangedEvent(u32 npad_id) const; |
| @@ -134,16 +188,16 @@ public: | |||
| 134 | // Adds a new controller at an index with connection status. | 188 | // Adds a new controller at an index with connection status. |
| 135 | void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); | 189 | void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); |
| 136 | 190 | ||
| 137 | void DisconnectNPad(u32 npad_id); | 191 | void DisconnectNpad(u32 npad_id); |
| 138 | void DisconnectNPadAtIndex(std::size_t index); | 192 | void DisconnectNpadAtIndex(std::size_t index); |
| 139 | 193 | ||
| 140 | void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); | 194 | void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); |
| 141 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; | 195 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; |
| 142 | bool IsSixAxisSensorAtRest() const; | 196 | bool IsSixAxisSensorAtRest() const; |
| 143 | void SetSixAxisEnabled(bool six_axis_status); | 197 | void SetSixAxisEnabled(bool six_axis_status); |
| 144 | LedPattern GetLedPattern(u32 npad_id); | 198 | LedPattern GetLedPattern(u32 npad_id); |
| 145 | void SetVibrationEnabled(bool can_vibrate); | 199 | bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; |
| 146 | bool IsVibrationEnabled() const; | 200 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); |
| 147 | void ClearAllConnectedControllers(); | 201 | void ClearAllConnectedControllers(); |
| 148 | void DisconnectAllConnectedControllers(); | 202 | void DisconnectAllConnectedControllers(); |
| 149 | void ConnectAllDisconnectedControllers(); | 203 | void ConnectAllDisconnectedControllers(); |
| @@ -162,6 +216,8 @@ public: | |||
| 162 | static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); | 216 | static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); |
| 163 | static std::size_t NPadIdToIndex(u32 npad_id); | 217 | static std::size_t NPadIdToIndex(u32 npad_id); |
| 164 | static u32 IndexToNPad(std::size_t index); | 218 | static u32 IndexToNPad(std::size_t index); |
| 219 | static bool IsNpadIdValid(u32 npad_id); | ||
| 220 | static bool IsDeviceHandleValid(const DeviceHandle& device_handle); | ||
| 165 | 221 | ||
| 166 | private: | 222 | private: |
| 167 | struct CommonHeader { | 223 | struct CommonHeader { |
| @@ -318,8 +374,8 @@ private: | |||
| 318 | }; | 374 | }; |
| 319 | 375 | ||
| 320 | struct NPadEntry { | 376 | struct NPadEntry { |
| 321 | NPadType joy_styles; | 377 | NpadStyleSet joy_styles; |
| 322 | NPadAssignments pad_assignment; | 378 | NpadAssignments pad_assignment; |
| 323 | 379 | ||
| 324 | ColorReadError single_color_error; | 380 | ColorReadError single_color_error; |
| 325 | ControllerColor single_color; | 381 | ControllerColor single_color; |
| @@ -360,9 +416,9 @@ private: | |||
| 360 | bool IsControllerSupported(NPadControllerType controller) const; | 416 | bool IsControllerSupported(NPadControllerType controller) const; |
| 361 | void RequestPadStateUpdate(u32 npad_id); | 417 | void RequestPadStateUpdate(u32 npad_id); |
| 362 | 418 | ||
| 363 | u32 press_state{}; | 419 | std::atomic<u32> press_state{}; |
| 364 | 420 | ||
| 365 | NPadType style{}; | 421 | NpadStyleSet style{}; |
| 366 | std::array<NPadEntry, 10> shared_memory_entries{}; | 422 | std::array<NPadEntry, 10> shared_memory_entries{}; |
| 367 | using ButtonArray = std::array< | 423 | using ButtonArray = std::array< |
| 368 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, | 424 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, |
| @@ -370,21 +426,30 @@ private: | |||
| 370 | using StickArray = std::array< | 426 | using StickArray = std::array< |
| 371 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, | 427 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, |
| 372 | 10>; | 428 | 10>; |
| 429 | using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>, | ||
| 430 | Settings::NativeVibration::NUM_VIBRATIONS_HID>, | ||
| 431 | 10>; | ||
| 373 | using MotionArray = std::array< | 432 | using MotionArray = std::array< |
| 374 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, | 433 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, |
| 375 | 10>; | 434 | 10>; |
| 376 | ButtonArray buttons; | 435 | ButtonArray buttons; |
| 377 | StickArray sticks; | 436 | StickArray sticks; |
| 437 | VibrationArray vibrations; | ||
| 378 | MotionArray motions; | 438 | MotionArray motions; |
| 379 | std::vector<u32> supported_npad_id_types{}; | 439 | std::vector<u32> supported_npad_id_types{}; |
| 380 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 440 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 381 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | 441 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; |
| 442 | // NpadCommunicationMode is unknown, default value is 1 | ||
| 443 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Unknown1}; | ||
| 382 | // Each controller should have their own styleset changed event | 444 | // Each controller should have their own styleset changed event |
| 383 | std::array<Kernel::EventPair, 10> styleset_changed_events; | 445 | std::array<Kernel::EventPair, 10> styleset_changed_events; |
| 384 | Vibration last_processed_vibration{}; | 446 | std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; |
| 447 | std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; | ||
| 448 | bool permit_vibration_session_enabled{false}; | ||
| 449 | std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; | ||
| 385 | std::array<ControllerHolder, 10> connected_controllers{}; | 450 | std::array<ControllerHolder, 10> connected_controllers{}; |
| 451 | std::array<bool, 10> unintended_home_button_input_protection{}; | ||
| 386 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | 452 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; |
| 387 | bool can_controllers_vibrate{true}; | ||
| 388 | bool sixaxis_sensors_enabled{true}; | 453 | bool sixaxis_sensors_enabled{true}; |
| 389 | bool sixaxis_at_rest{true}; | 454 | bool sixaxis_at_rest{true}; |
| 390 | std::array<ControllerPad, 10> npad_pad_states{}; | 455 | std::array<ControllerPad, 10> npad_pad_states{}; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 395e83b3f..8d95f74e6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -40,11 +40,12 @@ namespace Service::HID { | |||
| 40 | // Updating period for each HID device. | 40 | // Updating period for each HID device. |
| 41 | // HID is polled every 15ms, this value was derived from | 41 | // HID is polled every 15ms, this value was derived from |
| 42 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet | 42 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet |
| 43 | constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) | 43 | constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) |
| 44 | constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) | ||
| 44 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 45 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 45 | 46 | ||
| 46 | IAppletResource::IAppletResource(Core::System& system) | 47 | IAppletResource::IAppletResource(Core::System& system_) |
| 47 | : ServiceFramework("IAppletResource"), system(system) { | 48 | : ServiceFramework{system_, "IAppletResource"} { |
| 48 | static const FunctionInfo functions[] = { | 49 | static const FunctionInfo functions[] = { |
| 49 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, | 50 | {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, |
| 50 | }; | 51 | }; |
| @@ -77,12 +78,18 @@ IAppletResource::IAppletResource(Core::System& system) | |||
| 77 | pad_update_event = Core::Timing::CreateEvent( | 78 | pad_update_event = Core::Timing::CreateEvent( |
| 78 | "HID::UpdatePadCallback", | 79 | "HID::UpdatePadCallback", |
| 79 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 80 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { |
| 81 | const auto guard = LockService(); | ||
| 80 | UpdateControllers(user_data, ns_late); | 82 | UpdateControllers(user_data, ns_late); |
| 81 | }); | 83 | }); |
| 82 | 84 | motion_update_event = Core::Timing::CreateEvent( | |
| 83 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) | 85 | "HID::MotionPadCallback", |
| 86 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||
| 87 | const auto guard = LockService(); | ||
| 88 | UpdateMotion(user_data, ns_late); | ||
| 89 | }); | ||
| 84 | 90 | ||
| 85 | system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); | 91 | system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); |
| 92 | system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); | ||
| 86 | 93 | ||
| 87 | ReloadInputDevices(); | 94 | ReloadInputDevices(); |
| 88 | } | 95 | } |
| @@ -122,22 +129,50 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | |||
| 122 | core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); | 129 | core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); |
| 123 | } | 130 | } |
| 124 | 131 | ||
| 132 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||
| 133 | auto& core_timing = system.CoreTiming(); | ||
| 134 | |||
| 135 | for (const auto& controller : controllers) { | ||
| 136 | controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); | ||
| 137 | } | ||
| 138 | |||
| 139 | core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event); | ||
| 140 | } | ||
| 141 | |||
| 125 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 142 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { |
| 126 | public: | 143 | public: |
| 127 | IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") { | 144 | explicit IActiveVibrationDeviceList(Core::System& system_, |
| 145 | std::shared_ptr<IAppletResource> applet_resource_) | ||
| 146 | : ServiceFramework{system_, "IActiveVibrationDeviceList"}, | ||
| 147 | applet_resource(applet_resource_) { | ||
| 148 | // clang-format off | ||
| 128 | static const FunctionInfo functions[] = { | 149 | static const FunctionInfo functions[] = { |
| 129 | {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, | 150 | {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"}, |
| 130 | }; | 151 | }; |
| 152 | // clang-format on | ||
| 153 | |||
| 131 | RegisterHandlers(functions); | 154 | RegisterHandlers(functions); |
| 132 | } | 155 | } |
| 133 | 156 | ||
| 134 | private: | 157 | private: |
| 135 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { | 158 | void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { |
| 136 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 159 | IPC::RequestParser rp{ctx}; |
| 160 | const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; | ||
| 161 | |||
| 162 | if (applet_resource != nullptr) { | ||
| 163 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 164 | .InitializeVibrationDevice(vibration_device_handle); | ||
| 165 | } | ||
| 166 | |||
| 167 | LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", | ||
| 168 | vibration_device_handle.npad_type, vibration_device_handle.npad_id, | ||
| 169 | vibration_device_handle.device_index); | ||
| 137 | 170 | ||
| 138 | IPC::ResponseBuilder rb{ctx, 2}; | 171 | IPC::ResponseBuilder rb{ctx, 2}; |
| 139 | rb.Push(RESULT_SUCCESS); | 172 | rb.Push(RESULT_SUCCESS); |
| 140 | } | 173 | } |
| 174 | |||
| 175 | std::shared_ptr<IAppletResource> applet_resource; | ||
| 141 | }; | 176 | }; |
| 142 | 177 | ||
| 143 | std::shared_ptr<IAppletResource> Hid::GetAppletResource() { | 178 | std::shared_ptr<IAppletResource> Hid::GetAppletResource() { |
| @@ -148,7 +183,7 @@ std::shared_ptr<IAppletResource> Hid::GetAppletResource() { | |||
| 148 | return applet_resource; | 183 | return applet_resource; |
| 149 | } | 184 | } |
| 150 | 185 | ||
| 151 | Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | 186 | Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} { |
| 152 | // clang-format off | 187 | // clang-format off |
| 153 | static const FunctionInfo functions[] = { | 188 | static const FunctionInfo functions[] = { |
| 154 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, | 189 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, |
| @@ -173,7 +208,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 173 | {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, | 208 | {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, |
| 174 | {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, | 209 | {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, |
| 175 | {68, nullptr, "IsSixAxisSensorFusionEnabled"}, | 210 | {68, nullptr, "IsSixAxisSensorFusionEnabled"}, |
| 176 | {69, nullptr, "EnableSixAxisSensorFusion"}, | 211 | {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"}, |
| 177 | {70, nullptr, "SetSixAxisSensorFusionParameters"}, | 212 | {70, nullptr, "SetSixAxisSensorFusionParameters"}, |
| 178 | {71, nullptr, "GetSixAxisSensorFusionParameters"}, | 213 | {71, nullptr, "GetSixAxisSensorFusionParameters"}, |
| 179 | {72, nullptr, "ResetSixAxisSensorFusionParameters"}, | 214 | {72, nullptr, "ResetSixAxisSensorFusionParameters"}, |
| @@ -209,8 +244,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 209 | {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, | 244 | {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, |
| 210 | {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"}, | 245 | {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"}, |
| 211 | {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, | 246 | {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, |
| 212 | {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, | 247 | {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, |
| 213 | {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, | 248 | {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, |
| 214 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, | 249 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, |
| 215 | {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, | 250 | {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, |
| 216 | {135, nullptr, "SetNpadCaptureButtonAssignment"}, | 251 | {135, nullptr, "SetNpadCaptureButtonAssignment"}, |
| @@ -226,7 +261,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 226 | {208, nullptr, "GetActualVibrationGcErmCommand"}, | 261 | {208, nullptr, "GetActualVibrationGcErmCommand"}, |
| 227 | {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, | 262 | {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, |
| 228 | {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, | 263 | {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, |
| 229 | {211, nullptr, "IsVibrationDeviceMounted"}, | 264 | {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, |
| 230 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, | 265 | {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, |
| 231 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, | 266 | {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, |
| 232 | {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, | 267 | {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, |
| @@ -245,7 +280,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 245 | {404, nullptr, "HasLeftRightBattery"}, | 280 | {404, nullptr, "HasLeftRightBattery"}, |
| 246 | {405, nullptr, "GetNpadInterfaceType"}, | 281 | {405, nullptr, "GetNpadInterfaceType"}, |
| 247 | {406, nullptr, "GetNpadLeftRightInterfaceType"}, | 282 | {406, nullptr, "GetNpadLeftRightInterfaceType"}, |
| 248 | {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"}, | 283 | {407, nullptr, "GetNpadOfHighestBatteryLevel"}, |
| 249 | {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"}, | 284 | {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"}, |
| 250 | {500, nullptr, "GetPalmaConnectionHandle"}, | 285 | {500, nullptr, "GetPalmaConnectionHandle"}, |
| 251 | {501, nullptr, "InitializePalma"}, | 286 | {501, nullptr, "InitializePalma"}, |
| @@ -277,8 +312,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 277 | {527, nullptr, "EnablePalmaBoostMode"}, | 312 | {527, nullptr, "EnablePalmaBoostMode"}, |
| 278 | {528, nullptr, "GetPalmaBluetoothAddress"}, | 313 | {528, nullptr, "GetPalmaBluetoothAddress"}, |
| 279 | {529, nullptr, "SetDisallowedPalmaConnection"}, | 314 | {529, nullptr, "SetDisallowedPalmaConnection"}, |
| 280 | {1000, nullptr, "SetNpadCommunicationMode"}, | 315 | {1000, &Hid::SetNpadCommunicationMode, "SetNpadCommunicationMode"}, |
| 281 | {1001, nullptr, "GetNpadCommunicationMode"}, | 316 | {1001, &Hid::GetNpadCommunicationMode, "GetNpadCommunicationMode"}, |
| 282 | {1002, nullptr, "SetTouchScreenConfiguration"}, | 317 | {1002, nullptr, "SetTouchScreenConfiguration"}, |
| 283 | {1003, nullptr, "IsFirmwareUpdateNeededForNotification"}, | 318 | {1003, nullptr, "IsFirmwareUpdateNeededForNotification"}, |
| 284 | {2000, nullptr, "ActivateDigitizer"}, | 319 | {2000, nullptr, "ActivateDigitizer"}, |
| @@ -305,154 +340,195 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { | |||
| 305 | rb.PushIpcInterface<IAppletResource>(applet_resource); | 340 | rb.PushIpcInterface<IAppletResource>(applet_resource); |
| 306 | } | 341 | } |
| 307 | 342 | ||
| 308 | void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { | 343 | void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { |
| 309 | IPC::RequestParser rp{ctx}; | 344 | IPC::RequestParser rp{ctx}; |
| 310 | const auto basic_xpad_id{rp.Pop<u32>()}; | ||
| 311 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 345 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 312 | 346 | ||
| 313 | LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, | 347 | applet_resource->ActivateController(HidController::DebugPad); |
| 314 | applet_resource_user_id); | 348 | |
| 349 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 315 | 350 | ||
| 316 | applet_resource->ActivateController(HidController::XPad); | ||
| 317 | IPC::ResponseBuilder rb{ctx, 2}; | 351 | IPC::ResponseBuilder rb{ctx, 2}; |
| 318 | rb.Push(RESULT_SUCCESS); | 352 | rb.Push(RESULT_SUCCESS); |
| 319 | } | 353 | } |
| 320 | 354 | ||
| 321 | void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { | 355 | void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { |
| 322 | IPC::RequestParser rp{ctx}; | 356 | IPC::RequestParser rp{ctx}; |
| 323 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 357 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 324 | 358 | ||
| 325 | LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); | 359 | applet_resource->ActivateController(HidController::Touchscreen); |
| 326 | |||
| 327 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 328 | rb.Push(RESULT_SUCCESS); | ||
| 329 | rb.Push(0); | ||
| 330 | } | ||
| 331 | 360 | ||
| 332 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 361 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 333 | IPC::RequestParser rp{ctx}; | ||
| 334 | const auto handle{rp.Pop<u32>()}; | ||
| 335 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 336 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); | ||
| 337 | LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, | ||
| 338 | applet_resource_user_id); | ||
| 339 | 362 | ||
| 340 | IPC::ResponseBuilder rb{ctx, 2}; | 363 | IPC::ResponseBuilder rb{ctx, 2}; |
| 341 | rb.Push(RESULT_SUCCESS); | 364 | rb.Push(RESULT_SUCCESS); |
| 342 | } | 365 | } |
| 343 | 366 | ||
| 344 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 367 | void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { |
| 345 | IPC::RequestParser rp{ctx}; | 368 | IPC::RequestParser rp{ctx}; |
| 346 | const auto handle{rp.Pop<u32>()}; | ||
| 347 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 369 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 348 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); | ||
| 349 | 370 | ||
| 350 | LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, | 371 | applet_resource->ActivateController(HidController::Mouse); |
| 351 | applet_resource_user_id); | 372 | |
| 373 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 352 | 374 | ||
| 353 | IPC::ResponseBuilder rb{ctx, 2}; | 375 | IPC::ResponseBuilder rb{ctx, 2}; |
| 354 | rb.Push(RESULT_SUCCESS); | 376 | rb.Push(RESULT_SUCCESS); |
| 355 | } | 377 | } |
| 356 | 378 | ||
| 357 | void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { | 379 | void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { |
| 358 | IPC::RequestParser rp{ctx}; | 380 | IPC::RequestParser rp{ctx}; |
| 359 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 381 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 360 | 382 | ||
| 383 | applet_resource->ActivateController(HidController::Keyboard); | ||
| 384 | |||
| 361 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 385 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 362 | 386 | ||
| 363 | applet_resource->ActivateController(HidController::DebugPad); | ||
| 364 | IPC::ResponseBuilder rb{ctx, 2}; | 387 | IPC::ResponseBuilder rb{ctx, 2}; |
| 365 | rb.Push(RESULT_SUCCESS); | 388 | rb.Push(RESULT_SUCCESS); |
| 366 | } | 389 | } |
| 367 | 390 | ||
| 368 | void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { | 391 | void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { |
| 369 | IPC::RequestParser rp{ctx}; | 392 | IPC::RequestParser rp{ctx}; |
| 370 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 393 | const auto flags{rp.Pop<u32>()}; |
| 371 | 394 | ||
| 372 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 395 | LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); |
| 373 | 396 | ||
| 374 | applet_resource->ActivateController(HidController::Touchscreen); | ||
| 375 | IPC::ResponseBuilder rb{ctx, 2}; | 397 | IPC::ResponseBuilder rb{ctx, 2}; |
| 376 | rb.Push(RESULT_SUCCESS); | 398 | rb.Push(RESULT_SUCCESS); |
| 377 | } | 399 | } |
| 378 | 400 | ||
| 379 | void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { | 401 | void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { |
| 380 | IPC::RequestParser rp{ctx}; | 402 | IPC::RequestParser rp{ctx}; |
| 381 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 403 | struct Parameters { |
| 404 | u32 basic_xpad_id{}; | ||
| 405 | INSERT_PADDING_WORDS(1); | ||
| 406 | u64 applet_resource_user_id{}; | ||
| 407 | }; | ||
| 382 | 408 | ||
| 383 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 409 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 410 | |||
| 411 | applet_resource->ActivateController(HidController::XPad); | ||
| 412 | |||
| 413 | LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", | ||
| 414 | parameters.basic_xpad_id, parameters.applet_resource_user_id); | ||
| 384 | 415 | ||
| 385 | applet_resource->ActivateController(HidController::Mouse); | ||
| 386 | IPC::ResponseBuilder rb{ctx, 2}; | 416 | IPC::ResponseBuilder rb{ctx, 2}; |
| 387 | rb.Push(RESULT_SUCCESS); | 417 | rb.Push(RESULT_SUCCESS); |
| 388 | } | 418 | } |
| 389 | 419 | ||
| 390 | void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { | 420 | void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { |
| 391 | IPC::RequestParser rp{ctx}; | 421 | IPC::RequestParser rp{ctx}; |
| 392 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 422 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 393 | 423 | ||
| 394 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 424 | LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); |
| 395 | 425 | ||
| 396 | applet_resource->ActivateController(HidController::Keyboard); | 426 | IPC::ResponseBuilder rb{ctx, 3}; |
| 397 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 398 | rb.Push(RESULT_SUCCESS); | 427 | rb.Push(RESULT_SUCCESS); |
| 428 | rb.Push(0); | ||
| 399 | } | 429 | } |
| 400 | 430 | ||
| 401 | void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { | 431 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 402 | IPC::RequestParser rp{ctx}; | 432 | IPC::RequestParser rp{ctx}; |
| 403 | const auto flags{rp.Pop<u32>()}; | 433 | struct Parameters { |
| 404 | LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); | 434 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 435 | INSERT_PADDING_WORDS(1); | ||
| 436 | u64 applet_resource_user_id{}; | ||
| 437 | }; | ||
| 438 | |||
| 439 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 440 | |||
| 441 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); | ||
| 442 | |||
| 443 | LOG_DEBUG(Service_HID, | ||
| 444 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 445 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 446 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 405 | 447 | ||
| 406 | IPC::ResponseBuilder rb{ctx, 2}; | 448 | IPC::ResponseBuilder rb{ctx, 2}; |
| 407 | rb.Push(RESULT_SUCCESS); | 449 | rb.Push(RESULT_SUCCESS); |
| 408 | } | 450 | } |
| 409 | 451 | ||
| 410 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | 452 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 411 | IPC::RequestParser rp{ctx}; | 453 | IPC::RequestParser rp{ctx}; |
| 412 | const auto unknown{rp.Pop<u32>()}; | 454 | struct Parameters { |
| 413 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 455 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 456 | INSERT_PADDING_WORDS(1); | ||
| 457 | u64 applet_resource_user_id{}; | ||
| 458 | }; | ||
| 414 | 459 | ||
| 415 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, | 460 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 416 | applet_resource_user_id); | 461 | |
| 462 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); | ||
| 463 | |||
| 464 | LOG_DEBUG(Service_HID, | ||
| 465 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 466 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 467 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 417 | 468 | ||
| 418 | applet_resource->ActivateController(HidController::Gesture); | ||
| 419 | IPC::ResponseBuilder rb{ctx, 2}; | 469 | IPC::ResponseBuilder rb{ctx, 2}; |
| 420 | rb.Push(RESULT_SUCCESS); | 470 | rb.Push(RESULT_SUCCESS); |
| 421 | } | 471 | } |
| 422 | 472 | ||
| 423 | void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | 473 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 424 | // Should have no effect with how our npad sets up the data | ||
| 425 | IPC::RequestParser rp{ctx}; | 474 | IPC::RequestParser rp{ctx}; |
| 426 | const auto unknown{rp.Pop<u32>()}; | 475 | struct Parameters { |
| 427 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 476 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 477 | INSERT_PADDING_WORDS(1); | ||
| 478 | u64 applet_resource_user_id{}; | ||
| 479 | }; | ||
| 428 | 480 | ||
| 429 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, | 481 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 430 | applet_resource_user_id); | 482 | |
| 483 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); | ||
| 484 | |||
| 485 | LOG_DEBUG(Service_HID, | ||
| 486 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 487 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 488 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 431 | 489 | ||
| 432 | applet_resource->ActivateController(HidController::NPad); | ||
| 433 | IPC::ResponseBuilder rb{ctx, 2}; | 490 | IPC::ResponseBuilder rb{ctx, 2}; |
| 434 | rb.Push(RESULT_SUCCESS); | 491 | rb.Push(RESULT_SUCCESS); |
| 435 | } | 492 | } |
| 436 | 493 | ||
| 437 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 494 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 438 | IPC::RequestParser rp{ctx}; | 495 | IPC::RequestParser rp{ctx}; |
| 439 | const auto handle{rp.Pop<u32>()}; | 496 | struct Parameters { |
| 440 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 497 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 498 | INSERT_PADDING_WORDS(1); | ||
| 499 | u64 applet_resource_user_id{}; | ||
| 500 | }; | ||
| 441 | 501 | ||
| 442 | LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, | 502 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 443 | applet_resource_user_id); | 503 | |
| 504 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); | ||
| 505 | |||
| 506 | LOG_DEBUG(Service_HID, | ||
| 507 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 508 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 509 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 444 | 510 | ||
| 445 | IPC::ResponseBuilder rb{ctx, 2}; | 511 | IPC::ResponseBuilder rb{ctx, 2}; |
| 446 | rb.Push(RESULT_SUCCESS); | 512 | rb.Push(RESULT_SUCCESS); |
| 447 | } | 513 | } |
| 448 | 514 | ||
| 449 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | 515 | void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { |
| 450 | IPC::RequestParser rp{ctx}; | 516 | IPC::RequestParser rp{ctx}; |
| 451 | const auto handle{rp.Pop<u32>()}; | 517 | struct Parameters { |
| 452 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 518 | bool enable_sixaxis_sensor_fusion{}; |
| 519 | INSERT_PADDING_BYTES(3); | ||
| 520 | Controller_NPad::DeviceHandle sixaxis_handle{}; | ||
| 521 | u64 applet_resource_user_id{}; | ||
| 522 | }; | ||
| 453 | 523 | ||
| 454 | LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, | 524 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 455 | applet_resource_user_id); | 525 | |
| 526 | LOG_WARNING(Service_HID, | ||
| 527 | "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " | ||
| 528 | "device_index={}, applet_resource_user_id={}", | ||
| 529 | parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, | ||
| 530 | parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, | ||
| 531 | parameters.applet_resource_user_id); | ||
| 456 | 532 | ||
| 457 | IPC::ResponseBuilder rb{ctx, 2}; | 533 | IPC::ResponseBuilder rb{ctx, 2}; |
| 458 | rb.Push(RESULT_SUCCESS); | 534 | rb.Push(RESULT_SUCCESS); |
| @@ -460,14 +536,17 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 460 | 536 | ||
| 461 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 537 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 462 | IPC::RequestParser rp{ctx}; | 538 | IPC::RequestParser rp{ctx}; |
| 463 | const auto handle{rp.Pop<u32>()}; | 539 | const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; |
| 464 | const auto drift_mode{rp.Pop<u32>()}; | 540 | const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; |
| 465 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 541 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 466 | 542 | ||
| 467 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 543 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 468 | .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode}); | 544 | .SetGyroscopeZeroDriftMode(drift_mode); |
| 469 | 545 | ||
| 470 | LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, | 546 | LOG_DEBUG(Service_HID, |
| 547 | "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " | ||
| 548 | "applet_resource_user_id={}", | ||
| 549 | sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index, | ||
| 471 | drift_mode, applet_resource_user_id); | 550 | drift_mode, applet_resource_user_id); |
| 472 | 551 | ||
| 473 | IPC::ResponseBuilder rb{ctx, 2}; | 552 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -476,29 +555,42 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 476 | 555 | ||
| 477 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 556 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 478 | IPC::RequestParser rp{ctx}; | 557 | IPC::RequestParser rp{ctx}; |
| 479 | const auto handle{rp.Pop<u32>()}; | 558 | struct Parameters { |
| 480 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 559 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 560 | INSERT_PADDING_WORDS(1); | ||
| 561 | u64 applet_resource_user_id{}; | ||
| 562 | }; | ||
| 563 | |||
| 564 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 481 | 565 | ||
| 482 | LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, | 566 | LOG_DEBUG(Service_HID, |
| 483 | applet_resource_user_id); | 567 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 568 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 569 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 484 | 570 | ||
| 485 | IPC::ResponseBuilder rb{ctx, 3}; | 571 | IPC::ResponseBuilder rb{ctx, 3}; |
| 486 | rb.Push(RESULT_SUCCESS); | 572 | rb.Push(RESULT_SUCCESS); |
| 487 | rb.Push<u32>( | 573 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 488 | static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 574 | .GetGyroscopeZeroDriftMode()); |
| 489 | .GetGyroscopeZeroDriftMode())); | ||
| 490 | } | 575 | } |
| 491 | 576 | ||
| 492 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 577 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 493 | IPC::RequestParser rp{ctx}; | 578 | IPC::RequestParser rp{ctx}; |
| 494 | const auto handle{rp.Pop<u32>()}; | 579 | struct Parameters { |
| 495 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 580 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 581 | INSERT_PADDING_WORDS(1); | ||
| 582 | u64 applet_resource_user_id{}; | ||
| 583 | }; | ||
| 584 | |||
| 585 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 496 | 586 | ||
| 497 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 587 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 498 | .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); | 588 | .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); |
| 499 | 589 | ||
| 500 | LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, | 590 | LOG_DEBUG(Service_HID, |
| 501 | applet_resource_user_id); | 591 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 592 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 593 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 502 | 594 | ||
| 503 | IPC::ResponseBuilder rb{ctx, 2}; | 595 | IPC::ResponseBuilder rb{ctx, 2}; |
| 504 | rb.Push(RESULT_SUCCESS); | 596 | rb.Push(RESULT_SUCCESS); |
| @@ -506,11 +598,18 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 506 | 598 | ||
| 507 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | 599 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { |
| 508 | IPC::RequestParser rp{ctx}; | 600 | IPC::RequestParser rp{ctx}; |
| 509 | const auto handle{rp.Pop<u32>()}; | 601 | struct Parameters { |
| 510 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 602 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 603 | INSERT_PADDING_WORDS(1); | ||
| 604 | u64 applet_resource_user_id{}; | ||
| 605 | }; | ||
| 606 | |||
| 607 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 511 | 608 | ||
| 512 | LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, | 609 | LOG_DEBUG(Service_HID, |
| 513 | applet_resource_user_id); | 610 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 611 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 612 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 514 | 613 | ||
| 515 | IPC::ResponseBuilder rb{ctx, 3}; | 614 | IPC::ResponseBuilder rb{ctx, 3}; |
| 516 | rb.Push(RESULT_SUCCESS); | 615 | rb.Push(RESULT_SUCCESS); |
| @@ -518,15 +617,34 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | |||
| 518 | .IsSixAxisSensorAtRest()); | 617 | .IsSixAxisSensorAtRest()); |
| 519 | } | 618 | } |
| 520 | 619 | ||
| 620 | void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | ||
| 621 | IPC::RequestParser rp{ctx}; | ||
| 622 | struct Parameters { | ||
| 623 | u32 unknown{}; | ||
| 624 | INSERT_PADDING_WORDS(1); | ||
| 625 | u64 applet_resource_user_id{}; | ||
| 626 | }; | ||
| 627 | |||
| 628 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 629 | |||
| 630 | applet_resource->ActivateController(HidController::Gesture); | ||
| 631 | |||
| 632 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, | ||
| 633 | parameters.applet_resource_user_id); | ||
| 634 | |||
| 635 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 636 | rb.Push(RESULT_SUCCESS); | ||
| 637 | } | ||
| 638 | |||
| 521 | void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 639 | void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 522 | IPC::RequestParser rp{ctx}; | 640 | IPC::RequestParser rp{ctx}; |
| 523 | const auto supported_styleset{rp.Pop<u32>()}; | 641 | const auto supported_styleset{rp.Pop<u32>()}; |
| 524 | 642 | ||
| 525 | LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); | ||
| 526 | |||
| 527 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 643 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 528 | .SetSupportedStyleSet({supported_styleset}); | 644 | .SetSupportedStyleSet({supported_styleset}); |
| 529 | 645 | ||
| 646 | LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); | ||
| 647 | |||
| 530 | IPC::ResponseBuilder rb{ctx, 2}; | 648 | IPC::ResponseBuilder rb{ctx, 2}; |
| 531 | rb.Push(RESULT_SUCCESS); | 649 | rb.Push(RESULT_SUCCESS); |
| 532 | } | 650 | } |
| @@ -537,21 +655,22 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | |||
| 537 | 655 | ||
| 538 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 656 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 539 | 657 | ||
| 540 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 541 | |||
| 542 | IPC::ResponseBuilder rb{ctx, 3}; | 658 | IPC::ResponseBuilder rb{ctx, 3}; |
| 543 | rb.Push(RESULT_SUCCESS); | 659 | rb.Push(RESULT_SUCCESS); |
| 544 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); | 660 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 661 | .GetSupportedStyleSet() | ||
| 662 | .raw); | ||
| 545 | } | 663 | } |
| 546 | 664 | ||
| 547 | void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 665 | void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| 548 | IPC::RequestParser rp{ctx}; | 666 | IPC::RequestParser rp{ctx}; |
| 549 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 667 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 550 | 668 | ||
| 669 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 670 | .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); | ||
| 671 | |||
| 551 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 672 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 552 | 673 | ||
| 553 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 554 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); | ||
| 555 | IPC::ResponseBuilder rb{ctx, 2}; | 674 | IPC::ResponseBuilder rb{ctx, 2}; |
| 556 | rb.Push(RESULT_SUCCESS); | 675 | rb.Push(RESULT_SUCCESS); |
| 557 | } | 676 | } |
| @@ -560,48 +679,62 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { | |||
| 560 | IPC::RequestParser rp{ctx}; | 679 | IPC::RequestParser rp{ctx}; |
| 561 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 680 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 562 | 681 | ||
| 682 | applet_resource->ActivateController(HidController::NPad); | ||
| 683 | |||
| 563 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 684 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 564 | 685 | ||
| 565 | IPC::ResponseBuilder rb{ctx, 2}; | 686 | IPC::ResponseBuilder rb{ctx, 2}; |
| 566 | rb.Push(RESULT_SUCCESS); | 687 | rb.Push(RESULT_SUCCESS); |
| 567 | applet_resource->ActivateController(HidController::NPad); | ||
| 568 | } | 688 | } |
| 569 | 689 | ||
| 570 | void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { | 690 | void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { |
| 571 | IPC::RequestParser rp{ctx}; | 691 | IPC::RequestParser rp{ctx}; |
| 572 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 692 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 573 | 693 | ||
| 694 | applet_resource->DeactivateController(HidController::NPad); | ||
| 695 | |||
| 574 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 696 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 575 | 697 | ||
| 576 | IPC::ResponseBuilder rb{ctx, 2}; | 698 | IPC::ResponseBuilder rb{ctx, 2}; |
| 577 | rb.Push(RESULT_SUCCESS); | 699 | rb.Push(RESULT_SUCCESS); |
| 578 | applet_resource->DeactivateController(HidController::NPad); | ||
| 579 | } | 700 | } |
| 580 | 701 | ||
| 581 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 702 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 582 | IPC::RequestParser rp{ctx}; | 703 | IPC::RequestParser rp{ctx}; |
| 583 | const auto npad_id{rp.Pop<u32>()}; | 704 | struct Parameters { |
| 584 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 705 | u32 npad_id{}; |
| 585 | const auto unknown{rp.Pop<u64>()}; | 706 | INSERT_PADDING_WORDS(1); |
| 707 | u64 applet_resource_user_id{}; | ||
| 708 | u64 unknown{}; | ||
| 709 | }; | ||
| 586 | 710 | ||
| 587 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, | 711 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 588 | applet_resource_user_id, unknown); | 712 | |
| 713 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", | ||
| 714 | parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); | ||
| 589 | 715 | ||
| 590 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 716 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 591 | rb.Push(RESULT_SUCCESS); | 717 | rb.Push(RESULT_SUCCESS); |
| 592 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 718 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 593 | .GetStyleSetChangedEvent(npad_id)); | 719 | .GetStyleSetChangedEvent(parameters.npad_id)); |
| 594 | } | 720 | } |
| 595 | 721 | ||
| 596 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | 722 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 597 | IPC::RequestParser rp{ctx}; | 723 | IPC::RequestParser rp{ctx}; |
| 598 | const auto npad_id{rp.Pop<u32>()}; | 724 | struct Parameters { |
| 599 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 725 | u32 npad_id{}; |
| 726 | INSERT_PADDING_WORDS(1); | ||
| 727 | u64 applet_resource_user_id{}; | ||
| 728 | }; | ||
| 729 | |||
| 730 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 731 | |||
| 732 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 733 | .DisconnectNpad(parameters.npad_id); | ||
| 600 | 734 | ||
| 601 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, | 735 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 602 | applet_resource_user_id); | 736 | parameters.applet_resource_user_id); |
| 603 | 737 | ||
| 604 | applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id); | ||
| 605 | IPC::ResponseBuilder rb{ctx, 2}; | 738 | IPC::ResponseBuilder rb{ctx, 2}; |
| 606 | rb.Push(RESULT_SUCCESS); | 739 | rb.Push(RESULT_SUCCESS); |
| 607 | } | 740 | } |
| @@ -614,22 +747,41 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | |||
| 614 | 747 | ||
| 615 | IPC::ResponseBuilder rb{ctx, 4}; | 748 | IPC::ResponseBuilder rb{ctx, 4}; |
| 616 | rb.Push(RESULT_SUCCESS); | 749 | rb.Push(RESULT_SUCCESS); |
| 617 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 750 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 618 | .GetLedPattern(npad_id) | 751 | .GetLedPattern(npad_id) |
| 619 | .raw); | 752 | .raw); |
| 753 | } | ||
| 754 | |||
| 755 | void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | ||
| 756 | // Should have no effect with how our npad sets up the data | ||
| 757 | IPC::RequestParser rp{ctx}; | ||
| 758 | struct Parameters { | ||
| 759 | u32 unknown{}; | ||
| 760 | INSERT_PADDING_WORDS(1); | ||
| 761 | u64 applet_resource_user_id{}; | ||
| 762 | }; | ||
| 763 | |||
| 764 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 765 | |||
| 766 | applet_resource->ActivateController(HidController::NPad); | ||
| 767 | |||
| 768 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, | ||
| 769 | parameters.applet_resource_user_id); | ||
| 770 | |||
| 771 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 772 | rb.Push(RESULT_SUCCESS); | ||
| 620 | } | 773 | } |
| 621 | 774 | ||
| 622 | void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 775 | void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 623 | IPC::RequestParser rp{ctx}; | 776 | IPC::RequestParser rp{ctx}; |
| 624 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 777 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 625 | const auto hold_type{rp.Pop<u64>()}; | 778 | const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()}; |
| 779 | |||
| 780 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type); | ||
| 626 | 781 | ||
| 627 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", | 782 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", |
| 628 | applet_resource_user_id, hold_type); | 783 | applet_resource_user_id, hold_type); |
| 629 | 784 | ||
| 630 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 631 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); | ||
| 632 | |||
| 633 | IPC::ResponseBuilder rb{ctx, 2}; | 785 | IPC::ResponseBuilder rb{ctx, 2}; |
| 634 | rb.Push(RESULT_SUCCESS); | 786 | rb.Push(RESULT_SUCCESS); |
| 635 | } | 787 | } |
| @@ -640,22 +792,26 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | |||
| 640 | 792 | ||
| 641 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 793 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 642 | 794 | ||
| 643 | const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 644 | IPC::ResponseBuilder rb{ctx, 4}; | 795 | IPC::ResponseBuilder rb{ctx, 4}; |
| 645 | rb.Push(RESULT_SUCCESS); | 796 | rb.Push(RESULT_SUCCESS); |
| 646 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); | 797 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType()); |
| 647 | } | 798 | } |
| 648 | 799 | ||
| 649 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 800 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 650 | IPC::RequestParser rp{ctx}; | 801 | IPC::RequestParser rp{ctx}; |
| 651 | const auto npad_id{rp.Pop<u32>()}; | 802 | struct Parameters { |
| 652 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 803 | u32 npad_id{}; |
| 804 | INSERT_PADDING_WORDS(1); | ||
| 805 | u64 applet_resource_user_id{}; | ||
| 806 | }; | ||
| 653 | 807 | ||
| 654 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, | 808 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 655 | applet_resource_user_id); | 809 | |
| 810 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 811 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); | ||
| 656 | 812 | ||
| 657 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 813 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", |
| 658 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); | 814 | parameters.npad_id, parameters.applet_resource_user_id); |
| 659 | 815 | ||
| 660 | IPC::ResponseBuilder rb{ctx, 2}; | 816 | IPC::ResponseBuilder rb{ctx, 2}; |
| 661 | rb.Push(RESULT_SUCCESS); | 817 | rb.Push(RESULT_SUCCESS); |
| @@ -664,16 +820,22 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx | |||
| 664 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | 820 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { |
| 665 | // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault | 821 | // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault |
| 666 | IPC::RequestParser rp{ctx}; | 822 | IPC::RequestParser rp{ctx}; |
| 667 | const auto npad_id{rp.Pop<u32>()}; | 823 | struct Parameters { |
| 668 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 824 | u32 npad_id{}; |
| 669 | const auto npad_joy_device_type{rp.Pop<u64>()}; | 825 | INSERT_PADDING_WORDS(1); |
| 826 | u64 applet_resource_user_id{}; | ||
| 827 | u64 npad_joy_device_type{}; | ||
| 828 | }; | ||
| 829 | |||
| 830 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 831 | |||
| 832 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 833 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); | ||
| 670 | 834 | ||
| 671 | LOG_WARNING(Service_HID, | 835 | LOG_WARNING(Service_HID, |
| 672 | "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 836 | "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| 673 | npad_id, applet_resource_user_id, npad_joy_device_type); | 837 | parameters.npad_id, parameters.applet_resource_user_id, |
| 674 | 838 | parameters.npad_joy_device_type); | |
| 675 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 676 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); | ||
| 677 | 839 | ||
| 678 | IPC::ResponseBuilder rb{ctx, 2}; | 840 | IPC::ResponseBuilder rb{ctx, 2}; |
| 679 | rb.Push(RESULT_SUCCESS); | 841 | rb.Push(RESULT_SUCCESS); |
| @@ -681,14 +843,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | |||
| 681 | 843 | ||
| 682 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 844 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 683 | IPC::RequestParser rp{ctx}; | 845 | IPC::RequestParser rp{ctx}; |
| 684 | const auto npad_id{rp.Pop<u32>()}; | 846 | struct Parameters { |
| 685 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 847 | u32 npad_id{}; |
| 848 | INSERT_PADDING_WORDS(1); | ||
| 849 | u64 applet_resource_user_id{}; | ||
| 850 | }; | ||
| 851 | |||
| 852 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 686 | 853 | ||
| 687 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, | 854 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 688 | applet_resource_user_id); | 855 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); |
| 689 | 856 | ||
| 690 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 857 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", |
| 691 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); | 858 | parameters.npad_id, parameters.applet_resource_user_id); |
| 692 | 859 | ||
| 693 | IPC::ResponseBuilder rb{ctx, 2}; | 860 | IPC::ResponseBuilder rb{ctx, 2}; |
| 694 | rb.Push(RESULT_SUCCESS); | 861 | rb.Push(RESULT_SUCCESS); |
| @@ -700,12 +867,12 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | |||
| 700 | const auto npad_id_2{rp.Pop<u32>()}; | 867 | const auto npad_id_2{rp.Pop<u32>()}; |
| 701 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 868 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 702 | 869 | ||
| 870 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 871 | .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); | ||
| 872 | |||
| 703 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | 873 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 704 | npad_id_1, npad_id_2, applet_resource_user_id); | 874 | npad_id_1, npad_id_2, applet_resource_user_id); |
| 705 | 875 | ||
| 706 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 707 | controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); | ||
| 708 | |||
| 709 | IPC::ResponseBuilder rb{ctx, 2}; | 876 | IPC::ResponseBuilder rb{ctx, 2}; |
| 710 | rb.Push(RESULT_SUCCESS); | 877 | rb.Push(RESULT_SUCCESS); |
| 711 | } | 878 | } |
| @@ -714,9 +881,9 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { | |||
| 714 | IPC::RequestParser rp{ctx}; | 881 | IPC::RequestParser rp{ctx}; |
| 715 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 882 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 716 | 883 | ||
| 884 | applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode(); | ||
| 885 | |||
| 717 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 886 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 718 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 719 | controller.StartLRAssignmentMode(); | ||
| 720 | 887 | ||
| 721 | IPC::ResponseBuilder rb{ctx, 2}; | 888 | IPC::ResponseBuilder rb{ctx, 2}; |
| 722 | rb.Push(RESULT_SUCCESS); | 889 | rb.Push(RESULT_SUCCESS); |
| @@ -726,9 +893,9 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { | |||
| 726 | IPC::RequestParser rp{ctx}; | 893 | IPC::RequestParser rp{ctx}; |
| 727 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 894 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 728 | 895 | ||
| 896 | applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode(); | ||
| 897 | |||
| 729 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 898 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 730 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 731 | controller.StopLRAssignmentMode(); | ||
| 732 | 899 | ||
| 733 | IPC::ResponseBuilder rb{ctx, 2}; | 900 | IPC::ResponseBuilder rb{ctx, 2}; |
| 734 | rb.Push(RESULT_SUCCESS); | 901 | rb.Push(RESULT_SUCCESS); |
| @@ -737,13 +904,13 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { | |||
| 737 | void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 904 | void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 738 | IPC::RequestParser rp{ctx}; | 905 | IPC::RequestParser rp{ctx}; |
| 739 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 906 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 740 | const auto mode{rp.Pop<u64>()}; | 907 | const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()}; |
| 741 | |||
| 742 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id, | ||
| 743 | mode); | ||
| 744 | 908 | ||
| 745 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 909 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 746 | .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode}); | 910 | .SetNpadHandheldActivationMode(activation_mode); |
| 911 | |||
| 912 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", | ||
| 913 | applet_resource_user_id, activation_mode); | ||
| 747 | 914 | ||
| 748 | IPC::ResponseBuilder rb{ctx, 2}; | 915 | IPC::ResponseBuilder rb{ctx, 2}; |
| 749 | rb.Push(RESULT_SUCCESS); | 916 | rb.Push(RESULT_SUCCESS); |
| @@ -757,23 +924,24 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | |||
| 757 | 924 | ||
| 758 | IPC::ResponseBuilder rb{ctx, 4}; | 925 | IPC::ResponseBuilder rb{ctx, 4}; |
| 759 | rb.Push(RESULT_SUCCESS); | 926 | rb.Push(RESULT_SUCCESS); |
| 760 | rb.Push<u64>( | 927 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 761 | static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 928 | .GetNpadHandheldActivationMode()); |
| 762 | .GetNpadHandheldActivationMode())); | ||
| 763 | } | 929 | } |
| 764 | 930 | ||
| 765 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | 931 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { |
| 766 | IPC::RequestParser rp{ctx}; | 932 | IPC::RequestParser rp{ctx}; |
| 767 | const auto npad_1{rp.Pop<u32>()}; | 933 | const auto npad_id_1{rp.Pop<u32>()}; |
| 768 | const auto npad_2{rp.Pop<u32>()}; | 934 | const auto npad_id_2{rp.Pop<u32>()}; |
| 769 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 935 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 770 | 936 | ||
| 771 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", | 937 | const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 772 | applet_resource_user_id, npad_1, npad_2); | 938 | .SwapNpadAssignment(npad_id_1, npad_id_2); |
| 939 | |||
| 940 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | ||
| 941 | npad_id_1, npad_id_2, applet_resource_user_id); | ||
| 773 | 942 | ||
| 774 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 775 | IPC::ResponseBuilder rb{ctx, 2}; | 943 | IPC::ResponseBuilder rb{ctx, 2}; |
| 776 | if (controller.SwapNpadAssignment(npad_1, npad_2)) { | 944 | if (res) { |
| 777 | rb.Push(RESULT_SUCCESS); | 945 | rb.Push(RESULT_SUCCESS); |
| 778 | } else { | 946 | } else { |
| 779 | LOG_ERROR(Service_HID, "Npads are not connected!"); | 947 | LOG_ERROR(Service_HID, "Npads are not connected!"); |
| @@ -781,61 +949,99 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | |||
| 781 | } | 949 | } |
| 782 | } | 950 | } |
| 783 | 951 | ||
| 784 | void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 952 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { |
| 785 | IPC::RequestParser rp{ctx}; | 953 | IPC::RequestParser rp{ctx}; |
| 786 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 954 | struct Parameters { |
| 787 | 955 | u32 npad_id{}; | |
| 788 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 956 | INSERT_PADDING_WORDS(1); |
| 957 | u64 applet_resource_user_id{}; | ||
| 958 | }; | ||
| 789 | 959 | ||
| 790 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true); | 960 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 791 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 792 | rb.Push(RESULT_SUCCESS); | ||
| 793 | } | ||
| 794 | 961 | ||
| 795 | void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 962 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", |
| 796 | LOG_DEBUG(Service_HID, "called"); | 963 | parameters.npad_id, parameters.applet_resource_user_id); |
| 797 | 964 | ||
| 798 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); | 965 | IPC::ResponseBuilder rb{ctx, 3}; |
| 799 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 800 | rb.Push(RESULT_SUCCESS); | 966 | rb.Push(RESULT_SUCCESS); |
| 967 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 968 | .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id)); | ||
| 801 | } | 969 | } |
| 802 | 970 | ||
| 803 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | 971 | void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { |
| 804 | IPC::RequestParser rp{ctx}; | 972 | IPC::RequestParser rp{ctx}; |
| 805 | const auto controller_id{rp.Pop<u32>()}; | 973 | struct Parameters { |
| 806 | const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; | 974 | bool unintended_home_button_input_protection{}; |
| 807 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 975 | INSERT_PADDING_BYTES(3); |
| 976 | u32 npad_id{}; | ||
| 977 | u64 applet_resource_user_id{}; | ||
| 978 | }; | ||
| 979 | |||
| 980 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 808 | 981 | ||
| 809 | LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, | 982 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 810 | applet_resource_user_id); | 983 | .SetUnintendedHomeButtonInputProtectionEnabled( |
| 984 | parameters.unintended_home_button_input_protection, parameters.npad_id); | ||
| 985 | |||
| 986 | LOG_WARNING(Service_HID, | ||
| 987 | "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," | ||
| 988 | "applet_resource_user_id={}", | ||
| 989 | parameters.unintended_home_button_input_protection, parameters.npad_id, | ||
| 990 | parameters.applet_resource_user_id); | ||
| 811 | 991 | ||
| 812 | IPC::ResponseBuilder rb{ctx, 2}; | 992 | IPC::ResponseBuilder rb{ctx, 2}; |
| 813 | rb.Push(RESULT_SUCCESS); | 993 | rb.Push(RESULT_SUCCESS); |
| 814 | |||
| 815 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 816 | .VibrateController({controller_id}, {vibration_values}); | ||
| 817 | } | 994 | } |
| 818 | 995 | ||
| 819 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | 996 | void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 820 | IPC::RequestParser rp{ctx}; | 997 | IPC::RequestParser rp{ctx}; |
| 821 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 998 | const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; |
| 999 | |||
| 1000 | VibrationDeviceInfo vibration_device_info; | ||
| 1001 | |||
| 1002 | vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; | ||
| 1003 | |||
| 1004 | switch (vibration_device_handle.device_index) { | ||
| 1005 | case Controller_NPad::DeviceIndex::Left: | ||
| 1006 | vibration_device_info.position = VibrationDevicePosition::Left; | ||
| 1007 | break; | ||
| 1008 | case Controller_NPad::DeviceIndex::Right: | ||
| 1009 | vibration_device_info.position = VibrationDevicePosition::Right; | ||
| 1010 | break; | ||
| 1011 | case Controller_NPad::DeviceIndex::None: | ||
| 1012 | default: | ||
| 1013 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | ||
| 1014 | vibration_device_info.position = VibrationDevicePosition::None; | ||
| 1015 | break; | ||
| 1016 | } | ||
| 822 | 1017 | ||
| 823 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1018 | LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", |
| 1019 | vibration_device_info.type, vibration_device_info.position); | ||
| 824 | 1020 | ||
| 825 | const auto controllers = ctx.ReadBuffer(0); | 1021 | IPC::ResponseBuilder rb{ctx, 4}; |
| 826 | const auto vibrations = ctx.ReadBuffer(1); | 1022 | rb.Push(RESULT_SUCCESS); |
| 1023 | rb.PushRaw(vibration_device_info); | ||
| 1024 | } | ||
| 827 | 1025 | ||
| 828 | std::vector<u32> controller_list(controllers.size() / sizeof(u32)); | 1026 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 829 | std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / | 1027 | IPC::RequestParser rp{ctx}; |
| 830 | sizeof(Controller_NPad::Vibration)); | 1028 | struct Parameters { |
| 1029 | Controller_NPad::DeviceHandle vibration_device_handle{}; | ||
| 1030 | Controller_NPad::VibrationValue vibration_value{}; | ||
| 1031 | INSERT_PADDING_WORDS(1); | ||
| 1032 | u64 applet_resource_user_id{}; | ||
| 1033 | }; | ||
| 831 | 1034 | ||
| 832 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); | 1035 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 833 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); | ||
| 834 | std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), | ||
| 835 | [](u32 controller_id) { return controller_id - 3; }); | ||
| 836 | 1036 | ||
| 837 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1037 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 838 | .VibrateController(controller_list, vibration_list); | 1038 | .VibrateController(parameters.vibration_device_handle, parameters.vibration_value); |
| 1039 | |||
| 1040 | LOG_DEBUG(Service_HID, | ||
| 1041 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 1042 | parameters.vibration_device_handle.npad_type, | ||
| 1043 | parameters.vibration_device_handle.npad_id, | ||
| 1044 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | ||
| 839 | 1045 | ||
| 840 | IPC::ResponseBuilder rb{ctx, 2}; | 1046 | IPC::ResponseBuilder rb{ctx, 2}; |
| 841 | rb.Push(RESULT_SUCCESS); | 1047 | rb.Push(RESULT_SUCCESS); |
| @@ -843,25 +1049,24 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | |||
| 843 | 1049 | ||
| 844 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 1050 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 845 | IPC::RequestParser rp{ctx}; | 1051 | IPC::RequestParser rp{ctx}; |
| 846 | const auto controller_id{rp.Pop<u32>()}; | 1052 | struct Parameters { |
| 847 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1053 | Controller_NPad::DeviceHandle vibration_device_handle{}; |
| 848 | 1054 | INSERT_PADDING_WORDS(1); | |
| 849 | LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, | 1055 | u64 applet_resource_user_id{}; |
| 850 | applet_resource_user_id); | 1056 | }; |
| 851 | 1057 | ||
| 852 | IPC::ResponseBuilder rb{ctx, 6}; | 1058 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 853 | rb.Push(RESULT_SUCCESS); | ||
| 854 | rb.PushRaw<Controller_NPad::Vibration>( | ||
| 855 | applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); | ||
| 856 | } | ||
| 857 | 1059 | ||
| 858 | void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 1060 | LOG_DEBUG(Service_HID, |
| 859 | LOG_DEBUG(Service_HID, "called"); | 1061 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 1062 | parameters.vibration_device_handle.npad_type, | ||
| 1063 | parameters.vibration_device_handle.npad_id, | ||
| 1064 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | ||
| 860 | 1065 | ||
| 861 | IPC::ResponseBuilder rb{ctx, 4}; | 1066 | IPC::ResponseBuilder rb{ctx, 6}; |
| 862 | rb.Push(RESULT_SUCCESS); | 1067 | rb.Push(RESULT_SUCCESS); |
| 863 | rb.Push<u32>(1); | 1068 | rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 864 | rb.Push<u32>(0); | 1069 | .GetLastVibration(parameters.vibration_device_handle)); |
| 865 | } | 1070 | } |
| 866 | 1071 | ||
| 867 | void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 1072 | void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| @@ -869,13 +1074,14 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | |||
| 869 | 1074 | ||
| 870 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1075 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 871 | rb.Push(RESULT_SUCCESS); | 1076 | rb.Push(RESULT_SUCCESS); |
| 872 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); | 1077 | rb.PushIpcInterface<IActiveVibrationDeviceList>(system, applet_resource); |
| 873 | } | 1078 | } |
| 874 | 1079 | ||
| 875 | void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { | 1080 | void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { |
| 876 | IPC::RequestParser rp{ctx}; | 1081 | IPC::RequestParser rp{ctx}; |
| 877 | const auto can_vibrate{rp.Pop<bool>()}; | 1082 | const auto can_vibrate{rp.Pop<bool>()}; |
| 878 | Settings::values.vibration_enabled = can_vibrate; | 1083 | |
| 1084 | Settings::values.vibration_enabled.SetValue(can_vibrate); | ||
| 879 | 1085 | ||
| 880 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); | 1086 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); |
| 881 | 1087 | ||
| @@ -888,7 +1094,76 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { | |||
| 888 | 1094 | ||
| 889 | IPC::ResponseBuilder rb{ctx, 3}; | 1095 | IPC::ResponseBuilder rb{ctx, 3}; |
| 890 | rb.Push(RESULT_SUCCESS); | 1096 | rb.Push(RESULT_SUCCESS); |
| 891 | rb.Push(Settings::values.vibration_enabled); | 1097 | rb.Push(Settings::values.vibration_enabled.GetValue()); |
| 1098 | } | ||
| 1099 | |||
| 1100 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | ||
| 1101 | IPC::RequestParser rp{ctx}; | ||
| 1102 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1103 | |||
| 1104 | const auto handles = ctx.ReadBuffer(0); | ||
| 1105 | const auto vibrations = ctx.ReadBuffer(1); | ||
| 1106 | |||
| 1107 | std::vector<Controller_NPad::DeviceHandle> vibration_device_handles( | ||
| 1108 | handles.size() / sizeof(Controller_NPad::DeviceHandle)); | ||
| 1109 | std::vector<Controller_NPad::VibrationValue> vibration_values( | ||
| 1110 | vibrations.size() / sizeof(Controller_NPad::VibrationValue)); | ||
| 1111 | |||
| 1112 | std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); | ||
| 1113 | std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); | ||
| 1114 | |||
| 1115 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1116 | .VibrateControllers(vibration_device_handles, vibration_values); | ||
| 1117 | |||
| 1118 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 1119 | |||
| 1120 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1121 | rb.Push(RESULT_SUCCESS); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | ||
| 1125 | IPC::RequestParser rp{ctx}; | ||
| 1126 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1127 | |||
| 1128 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1129 | .SetPermitVibrationSession(true); | ||
| 1130 | |||
| 1131 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 1132 | |||
| 1133 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1134 | rb.Push(RESULT_SUCCESS); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | ||
| 1138 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1139 | .SetPermitVibrationSession(false); | ||
| 1140 | |||
| 1141 | LOG_DEBUG(Service_HID, "called"); | ||
| 1142 | |||
| 1143 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1144 | rb.Push(RESULT_SUCCESS); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { | ||
| 1148 | IPC::RequestParser rp{ctx}; | ||
| 1149 | struct Parameters { | ||
| 1150 | Controller_NPad::DeviceHandle vibration_device_handle{}; | ||
| 1151 | INSERT_PADDING_WORDS(1); | ||
| 1152 | u64 applet_resource_user_id{}; | ||
| 1153 | }; | ||
| 1154 | |||
| 1155 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1156 | |||
| 1157 | LOG_DEBUG(Service_HID, | ||
| 1158 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 1159 | parameters.vibration_device_handle.npad_type, | ||
| 1160 | parameters.vibration_device_handle.npad_id, | ||
| 1161 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | ||
| 1162 | |||
| 1163 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 1164 | rb.Push(RESULT_SUCCESS); | ||
| 1165 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1166 | .IsVibrationDeviceMounted(parameters.vibration_device_handle)); | ||
| 892 | } | 1167 | } |
| 893 | 1168 | ||
| 894 | void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1169 | void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| @@ -904,11 +1179,19 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 904 | 1179 | ||
| 905 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1180 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 906 | IPC::RequestParser rp{ctx}; | 1181 | IPC::RequestParser rp{ctx}; |
| 907 | const auto handle{rp.Pop<u32>()}; | 1182 | struct Parameters { |
| 908 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1183 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 1184 | INSERT_PADDING_WORDS(1); | ||
| 1185 | u64 applet_resource_user_id{}; | ||
| 1186 | }; | ||
| 909 | 1187 | ||
| 910 | LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, | 1188 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 911 | applet_resource_user_id); | 1189 | |
| 1190 | LOG_WARNING( | ||
| 1191 | Service_HID, | ||
| 1192 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 1193 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 1194 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 912 | 1195 | ||
| 913 | IPC::ResponseBuilder rb{ctx, 2}; | 1196 | IPC::ResponseBuilder rb{ctx, 2}; |
| 914 | rb.Push(RESULT_SUCCESS); | 1197 | rb.Push(RESULT_SUCCESS); |
| @@ -916,11 +1199,19 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 916 | 1199 | ||
| 917 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1200 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 918 | IPC::RequestParser rp{ctx}; | 1201 | IPC::RequestParser rp{ctx}; |
| 919 | const auto handle{rp.Pop<u32>()}; | 1202 | struct Parameters { |
| 920 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1203 | Controller_NPad::DeviceHandle sixaxis_handle{}; |
| 1204 | INSERT_PADDING_WORDS(1); | ||
| 1205 | u64 applet_resource_user_id{}; | ||
| 1206 | }; | ||
| 921 | 1207 | ||
| 922 | LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, | 1208 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 923 | applet_resource_user_id); | 1209 | |
| 1210 | LOG_WARNING( | ||
| 1211 | Service_HID, | ||
| 1212 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | ||
| 1213 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 1214 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 924 | 1215 | ||
| 925 | IPC::ResponseBuilder rb{ctx, 2}; | 1216 | IPC::ResponseBuilder rb{ctx, 2}; |
| 926 | rb.Push(RESULT_SUCCESS); | 1217 | rb.Push(RESULT_SUCCESS); |
| @@ -1011,9 +1302,37 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { | |||
| 1011 | rb.Push(RESULT_SUCCESS); | 1302 | rb.Push(RESULT_SUCCESS); |
| 1012 | } | 1303 | } |
| 1013 | 1304 | ||
| 1305 | void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { | ||
| 1306 | IPC::RequestParser rp{ctx}; | ||
| 1307 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1308 | const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()}; | ||
| 1309 | |||
| 1310 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1311 | .SetNpadCommunicationMode(communication_mode); | ||
| 1312 | |||
| 1313 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}", | ||
| 1314 | applet_resource_user_id, communication_mode); | ||
| 1315 | |||
| 1316 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1317 | rb.Push(RESULT_SUCCESS); | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { | ||
| 1321 | IPC::RequestParser rp{ctx}; | ||
| 1322 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1323 | |||
| 1324 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 1325 | applet_resource_user_id); | ||
| 1326 | |||
| 1327 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 1328 | rb.Push(RESULT_SUCCESS); | ||
| 1329 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) | ||
| 1330 | .GetNpadCommunicationMode()); | ||
| 1331 | } | ||
| 1332 | |||
| 1014 | class HidDbg final : public ServiceFramework<HidDbg> { | 1333 | class HidDbg final : public ServiceFramework<HidDbg> { |
| 1015 | public: | 1334 | public: |
| 1016 | explicit HidDbg() : ServiceFramework{"hid:dbg"} { | 1335 | explicit HidDbg(Core::System& system_) : ServiceFramework{system_, "hid:dbg"} { |
| 1017 | // clang-format off | 1336 | // clang-format off |
| 1018 | static const FunctionInfo functions[] = { | 1337 | static const FunctionInfo functions[] = { |
| 1019 | {0, nullptr, "DeactivateDebugPad"}, | 1338 | {0, nullptr, "DeactivateDebugPad"}, |
| @@ -1140,7 +1459,7 @@ public: | |||
| 1140 | 1459 | ||
| 1141 | class HidSys final : public ServiceFramework<HidSys> { | 1460 | class HidSys final : public ServiceFramework<HidSys> { |
| 1142 | public: | 1461 | public: |
| 1143 | explicit HidSys() : ServiceFramework{"hid:sys"} { | 1462 | explicit HidSys(Core::System& system_) : ServiceFramework{system_, "hid:sys"} { |
| 1144 | // clang-format off | 1463 | // clang-format off |
| 1145 | static const FunctionInfo functions[] = { | 1464 | static const FunctionInfo functions[] = { |
| 1146 | {31, nullptr, "SendKeyboardLockKeyEvent"}, | 1465 | {31, nullptr, "SendKeyboardLockKeyEvent"}, |
| @@ -1274,7 +1593,7 @@ public: | |||
| 1274 | 1593 | ||
| 1275 | class HidTmp final : public ServiceFramework<HidTmp> { | 1594 | class HidTmp final : public ServiceFramework<HidTmp> { |
| 1276 | public: | 1595 | public: |
| 1277 | explicit HidTmp() : ServiceFramework{"hid:tmp"} { | 1596 | explicit HidTmp(Core::System& system_) : ServiceFramework{system_, "hid:tmp"} { |
| 1278 | // clang-format off | 1597 | // clang-format off |
| 1279 | static const FunctionInfo functions[] = { | 1598 | static const FunctionInfo functions[] = { |
| 1280 | {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"}, | 1599 | {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"}, |
| @@ -1287,7 +1606,7 @@ public: | |||
| 1287 | 1606 | ||
| 1288 | class HidBus final : public ServiceFramework<HidBus> { | 1607 | class HidBus final : public ServiceFramework<HidBus> { |
| 1289 | public: | 1608 | public: |
| 1290 | explicit HidBus() : ServiceFramework{"hidbus"} { | 1609 | explicit HidBus(Core::System& system_) : ServiceFramework{system_, "hidbus"} { |
| 1291 | // clang-format off | 1610 | // clang-format off |
| 1292 | static const FunctionInfo functions[] = { | 1611 | static const FunctionInfo functions[] = { |
| 1293 | {1, nullptr, "GetBusHandle"}, | 1612 | {1, nullptr, "GetBusHandle"}, |
| @@ -1317,15 +1636,15 @@ void ReloadInputDevices() { | |||
| 1317 | 1636 | ||
| 1318 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 1637 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 1319 | std::make_shared<Hid>(system)->InstallAsService(service_manager); | 1638 | std::make_shared<Hid>(system)->InstallAsService(service_manager); |
| 1320 | std::make_shared<HidBus>()->InstallAsService(service_manager); | 1639 | std::make_shared<HidBus>(system)->InstallAsService(service_manager); |
| 1321 | std::make_shared<HidDbg>()->InstallAsService(service_manager); | 1640 | std::make_shared<HidDbg>(system)->InstallAsService(service_manager); |
| 1322 | std::make_shared<HidSys>()->InstallAsService(service_manager); | 1641 | std::make_shared<HidSys>(system)->InstallAsService(service_manager); |
| 1323 | std::make_shared<HidTmp>()->InstallAsService(service_manager); | 1642 | std::make_shared<HidTmp>(system)->InstallAsService(service_manager); |
| 1324 | 1643 | ||
| 1325 | std::make_shared<IRS>(system)->InstallAsService(service_manager); | 1644 | std::make_shared<IRS>(system)->InstallAsService(service_manager); |
| 1326 | std::make_shared<IRS_SYS>()->InstallAsService(service_manager); | 1645 | std::make_shared<IRS_SYS>(system)->InstallAsService(service_manager); |
| 1327 | 1646 | ||
| 1328 | std::make_shared<XCD_SYS>()->InstallAsService(service_manager); | 1647 | std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager); |
| 1329 | } | 1648 | } |
| 1330 | 1649 | ||
| 1331 | } // namespace Service::HID | 1650 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index e04aaf1e9..b87bfdde1 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -41,7 +41,7 @@ enum class HidController : std::size_t { | |||
| 41 | 41 | ||
| 42 | class IAppletResource final : public ServiceFramework<IAppletResource> { | 42 | class IAppletResource final : public ServiceFramework<IAppletResource> { |
| 43 | public: | 43 | public: |
| 44 | explicit IAppletResource(Core::System& system); | 44 | explicit IAppletResource(Core::System& system_); |
| 45 | ~IAppletResource() override; | 45 | ~IAppletResource() override; |
| 46 | 46 | ||
| 47 | void ActivateController(HidController controller); | 47 | void ActivateController(HidController controller); |
| @@ -65,11 +65,12 @@ private: | |||
| 65 | 65 | ||
| 66 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 66 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| 67 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 67 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 68 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | ||
| 68 | 69 | ||
| 69 | std::shared_ptr<Kernel::SharedMemory> shared_mem; | 70 | std::shared_ptr<Kernel::SharedMemory> shared_mem; |
| 70 | 71 | ||
| 71 | std::shared_ptr<Core::Timing::EventType> pad_update_event; | 72 | std::shared_ptr<Core::Timing::EventType> pad_update_event; |
| 72 | Core::System& system; | 73 | std::shared_ptr<Core::Timing::EventType> motion_update_event; |
| 73 | 74 | ||
| 74 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | 75 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
| 75 | controllers{}; | 76 | controllers{}; |
| @@ -77,30 +78,30 @@ private: | |||
| 77 | 78 | ||
| 78 | class Hid final : public ServiceFramework<Hid> { | 79 | class Hid final : public ServiceFramework<Hid> { |
| 79 | public: | 80 | public: |
| 80 | explicit Hid(Core::System& system); | 81 | explicit Hid(Core::System& system_); |
| 81 | ~Hid() override; | 82 | ~Hid() override; |
| 82 | 83 | ||
| 83 | std::shared_ptr<IAppletResource> GetAppletResource(); | 84 | std::shared_ptr<IAppletResource> GetAppletResource(); |
| 84 | 85 | ||
| 85 | private: | 86 | private: |
| 86 | void CreateAppletResource(Kernel::HLERequestContext& ctx); | 87 | void CreateAppletResource(Kernel::HLERequestContext& ctx); |
| 87 | void ActivateXpad(Kernel::HLERequestContext& ctx); | ||
| 88 | void GetXpadIDs(Kernel::HLERequestContext& ctx); | ||
| 89 | void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx); | ||
| 90 | void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx); | ||
| 91 | void ActivateDebugPad(Kernel::HLERequestContext& ctx); | 88 | void ActivateDebugPad(Kernel::HLERequestContext& ctx); |
| 92 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx); | 89 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx); |
| 93 | void ActivateMouse(Kernel::HLERequestContext& ctx); | 90 | void ActivateMouse(Kernel::HLERequestContext& ctx); |
| 94 | void ActivateKeyboard(Kernel::HLERequestContext& ctx); | 91 | void ActivateKeyboard(Kernel::HLERequestContext& ctx); |
| 95 | void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); | 92 | void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); |
| 96 | void ActivateGesture(Kernel::HLERequestContext& ctx); | 93 | void ActivateXpad(Kernel::HLERequestContext& ctx); |
| 97 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); | 94 | void GetXpadIDs(Kernel::HLERequestContext& ctx); |
| 95 | void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx); | ||
| 96 | void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx); | ||
| 98 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx); | 97 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 99 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); | 98 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 99 | void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx); | ||
| 100 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 100 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 101 | void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 101 | void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 102 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); | 102 | void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); |
| 103 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); | 103 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); |
| 104 | void ActivateGesture(Kernel::HLERequestContext& ctx); | ||
| 104 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | 105 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); |
| 105 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | 106 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); |
| 106 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); | 107 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); |
| @@ -109,6 +110,7 @@ private: | |||
| 109 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); | 110 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); |
| 110 | void DisconnectNpad(Kernel::HLERequestContext& ctx); | 111 | void DisconnectNpad(Kernel::HLERequestContext& ctx); |
| 111 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); | 112 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); |
| 113 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); | ||
| 112 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); | 114 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); |
| 113 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); | 115 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); |
| 114 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); | 116 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); |
| @@ -120,15 +122,18 @@ private: | |||
| 120 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); | 122 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); |
| 121 | void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); | 123 | void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); |
| 122 | void SwapNpadAssignment(Kernel::HLERequestContext& ctx); | 124 | void SwapNpadAssignment(Kernel::HLERequestContext& ctx); |
| 123 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); | 125 | void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); |
| 124 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); | 126 | void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); |
| 127 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); | ||
| 125 | void SendVibrationValue(Kernel::HLERequestContext& ctx); | 128 | void SendVibrationValue(Kernel::HLERequestContext& ctx); |
| 126 | void SendVibrationValues(Kernel::HLERequestContext& ctx); | ||
| 127 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx); | 129 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx); |
| 128 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); | ||
| 129 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); | 130 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); |
| 130 | void PermitVibration(Kernel::HLERequestContext& ctx); | 131 | void PermitVibration(Kernel::HLERequestContext& ctx); |
| 131 | void IsVibrationPermitted(Kernel::HLERequestContext& ctx); | 132 | void IsVibrationPermitted(Kernel::HLERequestContext& ctx); |
| 133 | void SendVibrationValues(Kernel::HLERequestContext& ctx); | ||
| 134 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); | ||
| 135 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); | ||
| 136 | void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx); | ||
| 132 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); | 137 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 133 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); | 138 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 134 | void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); | 139 | void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); |
| @@ -140,9 +145,26 @@ private: | |||
| 140 | void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx); | 145 | void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx); |
| 141 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); | 146 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); |
| 142 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); | 147 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); |
| 148 | void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx); | ||
| 149 | void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); | ||
| 150 | |||
| 151 | enum class VibrationDeviceType : u32 { | ||
| 152 | LinearResonantActuator = 1, | ||
| 153 | }; | ||
| 154 | |||
| 155 | enum class VibrationDevicePosition : u32 { | ||
| 156 | None = 0, | ||
| 157 | Left = 1, | ||
| 158 | Right = 2, | ||
| 159 | }; | ||
| 160 | |||
| 161 | struct VibrationDeviceInfo { | ||
| 162 | VibrationDeviceType type{}; | ||
| 163 | VibrationDevicePosition position{}; | ||
| 164 | }; | ||
| 165 | static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); | ||
| 143 | 166 | ||
| 144 | std::shared_ptr<IAppletResource> applet_resource; | 167 | std::shared_ptr<IAppletResource> applet_resource; |
| 145 | Core::System& system; | ||
| 146 | }; | 168 | }; |
| 147 | 169 | ||
| 148 | /// Reload input devices. Used when input configuration changed | 170 | /// Reload input devices. Used when input configuration changed |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index e82fd031b..c8413099f 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::HID { | 13 | namespace Service::HID { |
| 14 | 14 | ||
| 15 | IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) { | 15 | IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, | 18 | {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, |
| @@ -175,7 +175,7 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | |||
| 175 | 175 | ||
| 176 | IRS::~IRS() = default; | 176 | IRS::~IRS() = default; |
| 177 | 177 | ||
| 178 | IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { | 178 | IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} { |
| 179 | // clang-format off | 179 | // clang-format off |
| 180 | static const FunctionInfo functions[] = { | 180 | static const FunctionInfo functions[] = { |
| 181 | {500, nullptr, "SetAppletResourceUserId"}, | 181 | {500, nullptr, "SetAppletResourceUserId"}, |
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index 8918ad6ca..be0c486ba 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include "core/hle/kernel/object.h" | 7 | #include "core/hle/kernel/object.h" |
| 8 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 9 | 9 | ||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Kernel { | 14 | namespace Kernel { |
| 11 | class SharedMemory; | 15 | class SharedMemory; |
| 12 | } | 16 | } |
| @@ -15,7 +19,7 @@ namespace Service::HID { | |||
| 15 | 19 | ||
| 16 | class IRS final : public ServiceFramework<IRS> { | 20 | class IRS final : public ServiceFramework<IRS> { |
| 17 | public: | 21 | public: |
| 18 | explicit IRS(Core::System& system); | 22 | explicit IRS(Core::System& system_); |
| 19 | ~IRS() override; | 23 | ~IRS() override; |
| 20 | 24 | ||
| 21 | private: | 25 | private: |
| @@ -37,14 +41,14 @@ private: | |||
| 37 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); | 41 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); |
| 38 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); | 42 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); |
| 39 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); | 43 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); |
| 44 | |||
| 40 | std::shared_ptr<Kernel::SharedMemory> shared_mem; | 45 | std::shared_ptr<Kernel::SharedMemory> shared_mem; |
| 41 | const u32 device_handle{0xABCD}; | 46 | const u32 device_handle{0xABCD}; |
| 42 | Core::System& system; | ||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { | 49 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { |
| 46 | public: | 50 | public: |
| 47 | explicit IRS_SYS(); | 51 | explicit IRS_SYS(Core::System& system); |
| 48 | ~IRS_SYS() override; | 52 | ~IRS_SYS() override; |
| 49 | }; | 53 | }; |
| 50 | 54 | ||
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp index c8e9125f6..43a8840d0 100644 --- a/src/core/hle/service/hid/xcd.cpp +++ b/src/core/hle/service/hid/xcd.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::HID { | 7 | namespace Service::HID { |
| 8 | 8 | ||
| 9 | XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} { | 9 | XCD_SYS::XCD_SYS(Core::System& system_) : ServiceFramework{system_, "xcd:sys"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetDataFormat"}, | 12 | {0, nullptr, "GetDataFormat"}, |
diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h index fd506d303..54932c228 100644 --- a/src/core/hle/service/hid/xcd.h +++ b/src/core/hle/service/hid/xcd.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::HID { | 13 | namespace Service::HID { |
| 10 | 14 | ||
| 11 | class XCD_SYS final : public ServiceFramework<XCD_SYS> { | 15 | class XCD_SYS final : public ServiceFramework<XCD_SYS> { |
| 12 | public: | 16 | public: |
| 13 | explicit XCD_SYS(); | 17 | explicit XCD_SYS(Core::System& system_); |
| 14 | ~XCD_SYS() override; | 18 | ~XCD_SYS() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index 17350b403..6ad3a2877 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp | |||
| @@ -15,7 +15,7 @@ namespace Service::LBL { | |||
| 15 | 15 | ||
| 16 | class LBL final : public ServiceFramework<LBL> { | 16 | class LBL final : public ServiceFramework<LBL> { |
| 17 | public: | 17 | public: |
| 18 | explicit LBL() : ServiceFramework{"lbl"} { | 18 | explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} { |
| 19 | // clang-format off | 19 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| 21 | {0, nullptr, "SaveCurrentSetting"}, | 21 | {0, nullptr, "SaveCurrentSetting"}, |
| @@ -84,8 +84,8 @@ private: | |||
| 84 | bool vr_mode_enabled = false; | 84 | bool vr_mode_enabled = false; |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | void InstallInterfaces(SM::ServiceManager& sm) { | 87 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 88 | std::make_shared<LBL>()->InstallAsService(sm); | 88 | std::make_shared<LBL>(system)->InstallAsService(sm); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | } // namespace Service::LBL | 91 | } // namespace Service::LBL |
diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h index bf6f400f8..9c2021026 100644 --- a/src/core/hle/service/lbl/lbl.h +++ b/src/core/hle/service/lbl/lbl.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::LBL { | 15 | namespace Service::LBL { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::LBL | 19 | } // namespace Service::LBL |
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 49972cd69..ee908f399 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -13,7 +13,7 @@ namespace Service::LDN { | |||
| 13 | 13 | ||
| 14 | class IMonitorService final : public ServiceFramework<IMonitorService> { | 14 | class IMonitorService final : public ServiceFramework<IMonitorService> { |
| 15 | public: | 15 | public: |
| 16 | explicit IMonitorService() : ServiceFramework{"IMonitorService"} { | 16 | explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} { |
| 17 | // clang-format off | 17 | // clang-format off |
| 18 | static const FunctionInfo functions[] = { | 18 | static const FunctionInfo functions[] = { |
| 19 | {0, nullptr, "GetStateForMonitor"}, | 19 | {0, nullptr, "GetStateForMonitor"}, |
| @@ -33,7 +33,7 @@ public: | |||
| 33 | 33 | ||
| 34 | class LDNM final : public ServiceFramework<LDNM> { | 34 | class LDNM final : public ServiceFramework<LDNM> { |
| 35 | public: | 35 | public: |
| 36 | explicit LDNM() : ServiceFramework{"ldn:m"} { | 36 | explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} { |
| 37 | // clang-format off | 37 | // clang-format off |
| 38 | static const FunctionInfo functions[] = { | 38 | static const FunctionInfo functions[] = { |
| 39 | {0, &LDNM::CreateMonitorService, "CreateMonitorService"} | 39 | {0, &LDNM::CreateMonitorService, "CreateMonitorService"} |
| @@ -48,15 +48,15 @@ public: | |||
| 48 | 48 | ||
| 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 50 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 51 | rb.PushIpcInterface<IMonitorService>(); | 51 | rb.PushIpcInterface<IMonitorService>(system); |
| 52 | } | 52 | } |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | class ISystemLocalCommunicationService final | 55 | class ISystemLocalCommunicationService final |
| 56 | : public ServiceFramework<ISystemLocalCommunicationService> { | 56 | : public ServiceFramework<ISystemLocalCommunicationService> { |
| 57 | public: | 57 | public: |
| 58 | explicit ISystemLocalCommunicationService() | 58 | explicit ISystemLocalCommunicationService(Core::System& system_) |
| 59 | : ServiceFramework{"ISystemLocalCommunicationService"} { | 59 | : ServiceFramework{system_, "ISystemLocalCommunicationService"} { |
| 60 | // clang-format off | 60 | // clang-format off |
| 61 | static const FunctionInfo functions[] = { | 61 | static const FunctionInfo functions[] = { |
| 62 | {0, nullptr, "GetState"}, | 62 | {0, nullptr, "GetState"}, |
| @@ -99,7 +99,8 @@ public: | |||
| 99 | class IUserLocalCommunicationService final | 99 | class IUserLocalCommunicationService final |
| 100 | : public ServiceFramework<IUserLocalCommunicationService> { | 100 | : public ServiceFramework<IUserLocalCommunicationService> { |
| 101 | public: | 101 | public: |
| 102 | explicit IUserLocalCommunicationService() : ServiceFramework{"IUserLocalCommunicationService"} { | 102 | explicit IUserLocalCommunicationService(Core::System& system_) |
| 103 | : ServiceFramework{system_, "IUserLocalCommunicationService"} { | ||
| 103 | // clang-format off | 104 | // clang-format off |
| 104 | static const FunctionInfo functions[] = { | 105 | static const FunctionInfo functions[] = { |
| 105 | {0, nullptr, "GetState"}, | 106 | {0, nullptr, "GetState"}, |
| @@ -148,7 +149,7 @@ public: | |||
| 148 | 149 | ||
| 149 | class LDNS final : public ServiceFramework<LDNS> { | 150 | class LDNS final : public ServiceFramework<LDNS> { |
| 150 | public: | 151 | public: |
| 151 | explicit LDNS() : ServiceFramework{"ldn:s"} { | 152 | explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} { |
| 152 | // clang-format off | 153 | // clang-format off |
| 153 | static const FunctionInfo functions[] = { | 154 | static const FunctionInfo functions[] = { |
| 154 | {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"}, | 155 | {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"}, |
| @@ -163,13 +164,13 @@ public: | |||
| 163 | 164 | ||
| 164 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 165 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 165 | rb.Push(RESULT_SUCCESS); | 166 | rb.Push(RESULT_SUCCESS); |
| 166 | rb.PushIpcInterface<ISystemLocalCommunicationService>(); | 167 | rb.PushIpcInterface<ISystemLocalCommunicationService>(system); |
| 167 | } | 168 | } |
| 168 | }; | 169 | }; |
| 169 | 170 | ||
| 170 | class LDNU final : public ServiceFramework<LDNU> { | 171 | class LDNU final : public ServiceFramework<LDNU> { |
| 171 | public: | 172 | public: |
| 172 | explicit LDNU() : ServiceFramework{"ldn:u"} { | 173 | explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} { |
| 173 | // clang-format off | 174 | // clang-format off |
| 174 | static const FunctionInfo functions[] = { | 175 | static const FunctionInfo functions[] = { |
| 175 | {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, | 176 | {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, |
| @@ -184,14 +185,14 @@ public: | |||
| 184 | 185 | ||
| 185 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 186 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 186 | rb.Push(RESULT_SUCCESS); | 187 | rb.Push(RESULT_SUCCESS); |
| 187 | rb.PushIpcInterface<IUserLocalCommunicationService>(); | 188 | rb.PushIpcInterface<IUserLocalCommunicationService>(system); |
| 188 | } | 189 | } |
| 189 | }; | 190 | }; |
| 190 | 191 | ||
| 191 | void InstallInterfaces(SM::ServiceManager& sm) { | 192 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 192 | std::make_shared<LDNM>()->InstallAsService(sm); | 193 | std::make_shared<LDNM>(system)->InstallAsService(sm); |
| 193 | std::make_shared<LDNS>()->InstallAsService(sm); | 194 | std::make_shared<LDNS>(system)->InstallAsService(sm); |
| 194 | std::make_shared<LDNU>()->InstallAsService(sm); | 195 | std::make_shared<LDNU>(system)->InstallAsService(sm); |
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | } // namespace Service::LDN | 198 | } // namespace Service::LDN |
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h index 6b2a3c2b2..3ccd9738b 100644 --- a/src/core/hle/service/ldn/ldn.h +++ b/src/core/hle/service/ldn/ldn.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::LDN { | 15 | namespace Service::LDN { |
| 12 | 16 | ||
| 13 | /// Registers all LDN services with the specified service manager. | 17 | /// Registers all LDN services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& sm); | 18 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::LDN | 20 | } // namespace Service::LDN |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d8cd10e31..9da786b4e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| 10 | #include "common/hex_util.h" | 10 | #include "common/hex_util.h" |
| 11 | #include "common/scope_exit.h" | 11 | #include "common/scope_exit.h" |
| 12 | #include "core/core.h" | ||
| 12 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/errors.h" | 14 | #include "core/hle/kernel/errors.h" |
| 14 | #include "core/hle/kernel/memory/page_table.h" | 15 | #include "core/hle/kernel/memory/page_table.h" |
| @@ -23,7 +24,7 @@ namespace Service::LDR { | |||
| 23 | 24 | ||
| 24 | constexpr ResultCode ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2}; | 25 | constexpr ResultCode ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2}; |
| 25 | 26 | ||
| 26 | constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51}; | 27 | [[maybe_unused]] constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51}; |
| 27 | constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52}; | 28 | constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52}; |
| 28 | constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53}; | 29 | constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53}; |
| 29 | constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54}; | 30 | constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54}; |
| @@ -33,7 +34,7 @@ constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57}; | |||
| 33 | constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81}; | 34 | constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81}; |
| 34 | constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82}; | 35 | constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82}; |
| 35 | constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84}; | 36 | constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84}; |
| 36 | constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85}; | 37 | [[maybe_unused]] constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85}; |
| 37 | constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; | 38 | constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; |
| 38 | 39 | ||
| 39 | constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; | 40 | constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; |
| @@ -114,7 +115,7 @@ static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size."); | |||
| 114 | 115 | ||
| 115 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 116 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 116 | public: | 117 | public: |
| 117 | explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { | 118 | explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} { |
| 118 | // clang-format off | 119 | // clang-format off |
| 119 | static const FunctionInfo functions[] = { | 120 | static const FunctionInfo functions[] = { |
| 120 | {0, nullptr, "AddProcessToDebugLaunchQueue"}, | 121 | {0, nullptr, "AddProcessToDebugLaunchQueue"}, |
| @@ -129,7 +130,7 @@ public: | |||
| 129 | 130 | ||
| 130 | class ProcessManager final : public ServiceFramework<ProcessManager> { | 131 | class ProcessManager final : public ServiceFramework<ProcessManager> { |
| 131 | public: | 132 | public: |
| 132 | explicit ProcessManager() : ServiceFramework{"ldr:pm"} { | 133 | explicit ProcessManager(Core::System& system_) : ServiceFramework{system_, "ldr:pm"} { |
| 133 | // clang-format off | 134 | // clang-format off |
| 134 | static const FunctionInfo functions[] = { | 135 | static const FunctionInfo functions[] = { |
| 135 | {0, nullptr, "CreateProcess"}, | 136 | {0, nullptr, "CreateProcess"}, |
| @@ -146,7 +147,7 @@ public: | |||
| 146 | 147 | ||
| 147 | class Shell final : public ServiceFramework<Shell> { | 148 | class Shell final : public ServiceFramework<Shell> { |
| 148 | public: | 149 | public: |
| 149 | explicit Shell() : ServiceFramework{"ldr:shel"} { | 150 | explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} { |
| 150 | // clang-format off | 151 | // clang-format off |
| 151 | static const FunctionInfo functions[] = { | 152 | static const FunctionInfo functions[] = { |
| 152 | {0, nullptr, "AddProcessToLaunchQueue"}, | 153 | {0, nullptr, "AddProcessToLaunchQueue"}, |
| @@ -160,13 +161,13 @@ public: | |||
| 160 | 161 | ||
| 161 | class RelocatableObject final : public ServiceFramework<RelocatableObject> { | 162 | class RelocatableObject final : public ServiceFramework<RelocatableObject> { |
| 162 | public: | 163 | public: |
| 163 | explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) { | 164 | explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} { |
| 164 | // clang-format off | 165 | // clang-format off |
| 165 | static const FunctionInfo functions[] = { | 166 | static const FunctionInfo functions[] = { |
| 166 | {0, &RelocatableObject::LoadNro, "LoadNro"}, | 167 | {0, &RelocatableObject::LoadNro, "LoadNro"}, |
| 167 | {1, &RelocatableObject::UnloadNro, "UnloadNro"}, | 168 | {1, &RelocatableObject::UnloadNro, "UnloadNro"}, |
| 168 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, | 169 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, |
| 169 | {3, nullptr, "UnloadNrr"}, | 170 | {3, &RelocatableObject::UnloadNrr, "UnloadNrr"}, |
| 170 | {4, &RelocatableObject::Initialize, "Initialize"}, | 171 | {4, &RelocatableObject::Initialize, "Initialize"}, |
| 171 | {10, nullptr, "LoadNrrEx"}, | 172 | {10, nullptr, "LoadNrrEx"}, |
| 172 | }; | 173 | }; |
| @@ -272,6 +273,20 @@ public: | |||
| 272 | rb.Push(RESULT_SUCCESS); | 273 | rb.Push(RESULT_SUCCESS); |
| 273 | } | 274 | } |
| 274 | 275 | ||
| 276 | void UnloadNrr(Kernel::HLERequestContext& ctx) { | ||
| 277 | IPC::RequestParser rp{ctx}; | ||
| 278 | const auto pid = rp.Pop<u64>(); | ||
| 279 | const auto nrr_address = rp.Pop<VAddr>(); | ||
| 280 | |||
| 281 | LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address); | ||
| 282 | |||
| 283 | nrr.erase(nrr_address); | ||
| 284 | |||
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 286 | |||
| 287 | rb.Push(RESULT_SUCCESS); | ||
| 288 | } | ||
| 289 | |||
| 275 | bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start, | 290 | bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start, |
| 276 | std::size_t size) const { | 291 | std::size_t size) const { |
| 277 | constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize}; | 292 | constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize}; |
| @@ -512,9 +527,6 @@ public: | |||
| 512 | header.segment_headers[RO_INDEX].memory_size, | 527 | header.segment_headers[RO_INDEX].memory_size, |
| 513 | header.segment_headers[DATA_INDEX].memory_size, nro_address}); | 528 | header.segment_headers[DATA_INDEX].memory_size, nro_address}); |
| 514 | 529 | ||
| 515 | // Invalidate JIT caches for the newly mapped process code | ||
| 516 | system.InvalidateCpuInstructionCaches(); | ||
| 517 | |||
| 518 | IPC::ResponseBuilder rb{ctx, 4}; | 530 | IPC::ResponseBuilder rb{ctx, 4}; |
| 519 | rb.Push(RESULT_SUCCESS); | 531 | rb.Push(RESULT_SUCCESS); |
| 520 | rb.Push(*map_result); | 532 | rb.Push(*map_result); |
| @@ -575,8 +587,6 @@ public: | |||
| 575 | 587 | ||
| 576 | const auto result{UnmapNro(iter->second)}; | 588 | const auto result{UnmapNro(iter->second)}; |
| 577 | 589 | ||
| 578 | system.InvalidateCpuInstructionCaches(); | ||
| 579 | |||
| 580 | nro.erase(iter); | 590 | nro.erase(iter); |
| 581 | 591 | ||
| 582 | IPC::ResponseBuilder rb{ctx, 2}; | 592 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -624,13 +634,12 @@ private: | |||
| 624 | Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && | 634 | Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && |
| 625 | Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); | 635 | Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); |
| 626 | } | 636 | } |
| 627 | Core::System& system; | ||
| 628 | }; | 637 | }; |
| 629 | 638 | ||
| 630 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { | 639 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 631 | std::make_shared<DebugMonitor>()->InstallAsService(sm); | 640 | std::make_shared<DebugMonitor>(system)->InstallAsService(sm); |
| 632 | std::make_shared<ProcessManager>()->InstallAsService(sm); | 641 | std::make_shared<ProcessManager>(system)->InstallAsService(sm); |
| 633 | std::make_shared<Shell>()->InstallAsService(sm); | 642 | std::make_shared<Shell>(system)->InstallAsService(sm); |
| 634 | std::make_shared<RelocatableObject>(system)->InstallAsService(sm); | 643 | std::make_shared<RelocatableObject>(system)->InstallAsService(sm); |
| 635 | } | 644 | } |
| 636 | 645 | ||
diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h index 7ac8c0b65..104fc15c5 100644 --- a/src/core/hle/service/ldr/ldr.h +++ b/src/core/hle/service/ldr/ldr.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index dec96b771..8e49b068c 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/scope_exit.h" | 9 | #include "common/scope_exit.h" |
| 10 | #include "core/core.h" | ||
| 10 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/service/lm/lm.h" | 12 | #include "core/hle/service/lm/lm.h" |
| 12 | #include "core/hle/service/lm/manager.h" | 13 | #include "core/hle/service/lm/manager.h" |
| @@ -17,8 +18,9 @@ namespace Service::LM { | |||
| 17 | 18 | ||
| 18 | class ILogger final : public ServiceFramework<ILogger> { | 19 | class ILogger final : public ServiceFramework<ILogger> { |
| 19 | public: | 20 | public: |
| 20 | explicit ILogger(Manager& manager_, Core::Memory::Memory& memory_) | 21 | explicit ILogger(Core::System& system_) |
| 21 | : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} { | 22 | : ServiceFramework{system_, "ILogger"}, manager{system_.GetLogManager()}, |
| 23 | memory{system_.Memory()} { | ||
| 22 | static const FunctionInfo functions[] = { | 24 | static const FunctionInfo functions[] = { |
| 23 | {0, &ILogger::Log, "Log"}, | 25 | {0, &ILogger::Log, "Log"}, |
| 24 | {1, &ILogger::SetDestination, "SetDestination"}, | 26 | {1, &ILogger::SetDestination, "SetDestination"}, |
| @@ -66,7 +68,7 @@ private: | |||
| 66 | IPC::RequestParser rp{ctx}; | 68 | IPC::RequestParser rp{ctx}; |
| 67 | const auto destination = rp.PopEnum<DestinationFlag>(); | 69 | const auto destination = rp.PopEnum<DestinationFlag>(); |
| 68 | 70 | ||
| 69 | LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination)); | 71 | LOG_DEBUG(Service_LM, "called, destination={:08X}", destination); |
| 70 | 72 | ||
| 71 | manager.SetDestination(destination); | 73 | manager.SetDestination(destination); |
| 72 | 74 | ||
| @@ -80,8 +82,7 @@ private: | |||
| 80 | 82 | ||
| 81 | class LM final : public ServiceFramework<LM> { | 83 | class LM final : public ServiceFramework<LM> { |
| 82 | public: | 84 | public: |
| 83 | explicit LM(Manager& manager_, Core::Memory::Memory& memory_) | 85 | explicit LM(Core::System& system_) : ServiceFramework{system_, "lm"} { |
| 84 | : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} { | ||
| 85 | // clang-format off | 86 | // clang-format off |
| 86 | static const FunctionInfo functions[] = { | 87 | static const FunctionInfo functions[] = { |
| 87 | {0, &LM::OpenLogger, "OpenLogger"}, | 88 | {0, &LM::OpenLogger, "OpenLogger"}, |
| @@ -97,16 +98,12 @@ private: | |||
| 97 | 98 | ||
| 98 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 99 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 99 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 100 | rb.PushIpcInterface<ILogger>(manager, memory); | 101 | rb.PushIpcInterface<ILogger>(system); |
| 101 | } | 102 | } |
| 102 | |||
| 103 | Manager& manager; | ||
| 104 | Core::Memory::Memory& memory; | ||
| 105 | }; | 103 | }; |
| 106 | 104 | ||
| 107 | void InstallInterfaces(Core::System& system) { | 105 | void InstallInterfaces(Core::System& system) { |
| 108 | std::make_shared<LM>(system.GetLogManager(), system.Memory()) | 106 | std::make_shared<LM>(system)->InstallAsService(system.ServiceManager()); |
| 109 | ->InstallAsService(system.ServiceManager()); | ||
| 110 | } | 107 | } |
| 111 | 108 | ||
| 112 | } // namespace Service::LM | 109 | } // namespace Service::LM |
diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp index 113a4665c..1599d941b 100644 --- a/src/core/hle/service/mig/mig.cpp +++ b/src/core/hle/service/mig/mig.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::Migration { | |||
| 12 | 12 | ||
| 13 | class MIG_USR final : public ServiceFramework<MIG_USR> { | 13 | class MIG_USR final : public ServiceFramework<MIG_USR> { |
| 14 | public: | 14 | public: |
| 15 | explicit MIG_USR() : ServiceFramework{"mig:usr"} { | 15 | explicit MIG_USR(Core::System& system_) : ServiceFramework{system_, "mig:usr"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {10, nullptr, "TryGetLastMigrationInfo"}, | 18 | {10, nullptr, "TryGetLastMigrationInfo"}, |
| @@ -33,8 +33,8 @@ public: | |||
| 33 | } | 33 | } |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | void InstallInterfaces(SM::ServiceManager& sm) { | 36 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 37 | std::make_shared<MIG_USR>()->InstallAsService(sm); | 37 | std::make_shared<MIG_USR>(system)->InstallAsService(sm); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | } // namespace Service::Migration | 40 | } // namespace Service::Migration |
diff --git a/src/core/hle/service/mig/mig.h b/src/core/hle/service/mig/mig.h index 288c1c1b3..2b24cdf2c 100644 --- a/src/core/hle/service/mig/mig.h +++ b/src/core/hle/service/mig/mig.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::Migration { | 15 | namespace Service::Migration { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::Migration | 19 | } // namespace Service::Migration |
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp index 4730070cb..d73b90015 100644 --- a/src/core/hle/service/mii/manager.cpp +++ b/src/core/hle/service/mii/manager.cpp | |||
| @@ -131,7 +131,7 @@ template <typename T> | |||
| 131 | T GetRandomValue(T min, T max) { | 131 | T GetRandomValue(T min, T max) { |
| 132 | std::random_device device; | 132 | std::random_device device; |
| 133 | std::mt19937 gen(device()); | 133 | std::mt19937 gen(device()); |
| 134 | std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); | 134 | std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max)); |
| 135 | return static_cast<T>(distribution(gen)); | 135 | return static_cast<T>(distribution(gen)); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| @@ -428,7 +428,7 @@ bool MiiManager::IsFullDatabase() const { | |||
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | u32 MiiManager::GetCount(SourceFlag source_flag) const { | 430 | u32 MiiManager::GetCount(SourceFlag source_flag) const { |
| 431 | u32 count{}; | 431 | std::size_t count{}; |
| 432 | if ((source_flag & SourceFlag::Database) != SourceFlag::None) { | 432 | if ((source_flag & SourceFlag::Database) != SourceFlag::None) { |
| 433 | // TODO(bunnei): We don't implement the Mii database, but when we do, update this | 433 | // TODO(bunnei): We don't implement the Mii database, but when we do, update this |
| 434 | count += 0; | 434 | count += 0; |
| @@ -436,7 +436,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const { | |||
| 436 | if ((source_flag & SourceFlag::Default) != SourceFlag::None) { | 436 | if ((source_flag & SourceFlag::Default) != SourceFlag::None) { |
| 437 | count += DefaultMiiCount; | 437 | count += DefaultMiiCount; |
| 438 | } | 438 | } |
| 439 | return count; | 439 | return static_cast<u32>(count); |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, | 442 | ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, |
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index b81bf6277..26be9e45b 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp | |||
| @@ -18,7 +18,8 @@ constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1}; | |||
| 18 | 18 | ||
| 19 | class IDatabaseService final : public ServiceFramework<IDatabaseService> { | 19 | class IDatabaseService final : public ServiceFramework<IDatabaseService> { |
| 20 | public: | 20 | public: |
| 21 | explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} { | 21 | explicit IDatabaseService(Core::System& system_) |
| 22 | : ServiceFramework{system_, "IDatabaseService"} { | ||
| 22 | // clang-format off | 23 | // clang-format off |
| 23 | static const FunctionInfo functions[] = { | 24 | static const FunctionInfo functions[] = { |
| 24 | {0, &IDatabaseService::IsUpdated, "IsUpdated"}, | 25 | {0, &IDatabaseService::IsUpdated, "IsUpdated"}, |
| @@ -47,6 +48,7 @@ public: | |||
| 47 | {23, nullptr, "Convert"}, | 48 | {23, nullptr, "Convert"}, |
| 48 | {24, nullptr, "ConvertCoreDataToCharInfo"}, | 49 | {24, nullptr, "ConvertCoreDataToCharInfo"}, |
| 49 | {25, nullptr, "ConvertCharInfoToCoreData"}, | 50 | {25, nullptr, "ConvertCharInfoToCoreData"}, |
| 51 | {26, nullptr, "Append"}, | ||
| 50 | }; | 52 | }; |
| 51 | // clang-format on | 53 | // clang-format on |
| 52 | 54 | ||
| @@ -251,7 +253,8 @@ private: | |||
| 251 | 253 | ||
| 252 | class MiiDBModule final : public ServiceFramework<MiiDBModule> { | 254 | class MiiDBModule final : public ServiceFramework<MiiDBModule> { |
| 253 | public: | 255 | public: |
| 254 | explicit MiiDBModule(const char* name) : ServiceFramework{name} { | 256 | explicit MiiDBModule(Core::System& system_, const char* name) |
| 257 | : ServiceFramework{system_, name} { | ||
| 255 | // clang-format off | 258 | // clang-format off |
| 256 | static const FunctionInfo functions[] = { | 259 | static const FunctionInfo functions[] = { |
| 257 | {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, | 260 | {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, |
| @@ -265,7 +268,7 @@ private: | |||
| 265 | void GetDatabaseService(Kernel::HLERequestContext& ctx) { | 268 | void GetDatabaseService(Kernel::HLERequestContext& ctx) { |
| 266 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 269 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 267 | rb.Push(RESULT_SUCCESS); | 270 | rb.Push(RESULT_SUCCESS); |
| 268 | rb.PushIpcInterface<IDatabaseService>(); | 271 | rb.PushIpcInterface<IDatabaseService>(system); |
| 269 | 272 | ||
| 270 | LOG_DEBUG(Service_Mii, "called"); | 273 | LOG_DEBUG(Service_Mii, "called"); |
| 271 | } | 274 | } |
| @@ -273,7 +276,7 @@ private: | |||
| 273 | 276 | ||
| 274 | class MiiImg final : public ServiceFramework<MiiImg> { | 277 | class MiiImg final : public ServiceFramework<MiiImg> { |
| 275 | public: | 278 | public: |
| 276 | explicit MiiImg() : ServiceFramework{"miiimg"} { | 279 | explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} { |
| 277 | // clang-format off | 280 | // clang-format off |
| 278 | static const FunctionInfo functions[] = { | 281 | static const FunctionInfo functions[] = { |
| 279 | {0, nullptr, "Initialize"}, | 282 | {0, nullptr, "Initialize"}, |
| @@ -297,11 +300,11 @@ public: | |||
| 297 | } | 300 | } |
| 298 | }; | 301 | }; |
| 299 | 302 | ||
| 300 | void InstallInterfaces(SM::ServiceManager& sm) { | 303 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 301 | std::make_shared<MiiDBModule>("mii:e")->InstallAsService(sm); | 304 | std::make_shared<MiiDBModule>(system, "mii:e")->InstallAsService(sm); |
| 302 | std::make_shared<MiiDBModule>("mii:u")->InstallAsService(sm); | 305 | std::make_shared<MiiDBModule>(system, "mii:u")->InstallAsService(sm); |
| 303 | 306 | ||
| 304 | std::make_shared<MiiImg>()->InstallAsService(sm); | 307 | std::make_shared<MiiImg>(system)->InstallAsService(sm); |
| 305 | } | 308 | } |
| 306 | 309 | ||
| 307 | } // namespace Service::Mii | 310 | } // namespace Service::Mii |
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h index 7ce9be50e..9d3238e72 100644 --- a/src/core/hle/service/mii/mii.h +++ b/src/core/hle/service/mii/mii.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::Mii { | 15 | namespace Service::Mii { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::Mii | 19 | } // namespace Service::Mii |
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index 25c24e537..b0cb07d24 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp | |||
| @@ -6,12 +6,13 @@ | |||
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/client_session.h" | 7 | #include "core/hle/kernel/client_session.h" |
| 8 | #include "core/hle/service/mm/mm_u.h" | 8 | #include "core/hle/service/mm/mm_u.h" |
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 9 | 10 | ||
| 10 | namespace Service::MM { | 11 | namespace Service::MM { |
| 11 | 12 | ||
| 12 | class MM_U final : public ServiceFramework<MM_U> { | 13 | class MM_U final : public ServiceFramework<MM_U> { |
| 13 | public: | 14 | public: |
| 14 | explicit MM_U() : ServiceFramework{"mm:u"} { | 15 | explicit MM_U(Core::System& system_) : ServiceFramework{system_, "mm:u"} { |
| 15 | // clang-format off | 16 | // clang-format off |
| 16 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 17 | {0, &MM_U::InitializeOld, "InitializeOld"}, | 18 | {0, &MM_U::InitializeOld, "InitializeOld"}, |
| @@ -104,8 +105,8 @@ private: | |||
| 104 | u32 id{1}; | 105 | u32 id{1}; |
| 105 | }; | 106 | }; |
| 106 | 107 | ||
| 107 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 108 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 108 | std::make_shared<MM_U>()->InstallAsService(service_manager); | 109 | std::make_shared<MM_U>(system)->InstallAsService(service_manager); |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | } // namespace Service::MM | 112 | } // namespace Service::MM |
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h index 5439fa653..49b6a3355 100644 --- a/src/core/hle/service/mm/mm_u.h +++ b/src/core/hle/service/mm/mm_u.h | |||
| @@ -4,11 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | namespace Core { |
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 8 | 14 | ||
| 9 | namespace Service::MM { | 15 | namespace Service::MM { |
| 10 | 16 | ||
| 11 | /// Registers all MM services with the specified service manager. | 17 | /// Registers all MM services with the specified service manager. |
| 12 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 13 | 19 | ||
| 14 | } // namespace Service::MM | 20 | } // namespace Service::MM |
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp index e38dea1f4..2dcda16f6 100644 --- a/src/core/hle/service/ncm/ncm.cpp +++ b/src/core/hle/service/ncm/ncm.cpp | |||
| @@ -14,8 +14,8 @@ namespace Service::NCM { | |||
| 14 | 14 | ||
| 15 | class ILocationResolver final : public ServiceFramework<ILocationResolver> { | 15 | class ILocationResolver final : public ServiceFramework<ILocationResolver> { |
| 16 | public: | 16 | public: |
| 17 | explicit ILocationResolver(FileSys::StorageId id) | 17 | explicit ILocationResolver(Core::System& system_, FileSys::StorageId id) |
| 18 | : ServiceFramework{"ILocationResolver"}, storage(id) { | 18 | : ServiceFramework{system_, "ILocationResolver"}, storage{id} { |
| 19 | // clang-format off | 19 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| 21 | {0, nullptr, "ResolveProgramPath"}, | 21 | {0, nullptr, "ResolveProgramPath"}, |
| @@ -45,12 +45,13 @@ public: | |||
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | FileSys::StorageId storage; | 48 | [[maybe_unused]] FileSys::StorageId storage; |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> { | 51 | class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> { |
| 52 | public: | 52 | public: |
| 53 | explicit IRegisteredLocationResolver() : ServiceFramework{"IRegisteredLocationResolver"} { | 53 | explicit IRegisteredLocationResolver(Core::System& system_) |
| 54 | : ServiceFramework{system_, "IRegisteredLocationResolver"} { | ||
| 54 | // clang-format off | 55 | // clang-format off |
| 55 | static const FunctionInfo functions[] = { | 56 | static const FunctionInfo functions[] = { |
| 56 | {0, nullptr, "ResolveProgramPath"}, | 57 | {0, nullptr, "ResolveProgramPath"}, |
| @@ -72,7 +73,8 @@ public: | |||
| 72 | 73 | ||
| 73 | class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> { | 74 | class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> { |
| 74 | public: | 75 | public: |
| 75 | explicit IAddOnContentLocationResolver() : ServiceFramework{"IAddOnContentLocationResolver"} { | 76 | explicit IAddOnContentLocationResolver(Core::System& system_) |
| 77 | : ServiceFramework{system_, "IAddOnContentLocationResolver"} { | ||
| 76 | // clang-format off | 78 | // clang-format off |
| 77 | static const FunctionInfo functions[] = { | 79 | static const FunctionInfo functions[] = { |
| 78 | {0, nullptr, "ResolveAddOnContentPath"}, | 80 | {0, nullptr, "ResolveAddOnContentPath"}, |
| @@ -89,7 +91,7 @@ public: | |||
| 89 | 91 | ||
| 90 | class LR final : public ServiceFramework<LR> { | 92 | class LR final : public ServiceFramework<LR> { |
| 91 | public: | 93 | public: |
| 92 | explicit LR() : ServiceFramework{"lr"} { | 94 | explicit LR(Core::System& system_) : ServiceFramework{system_, "lr"} { |
| 93 | // clang-format off | 95 | // clang-format off |
| 94 | static const FunctionInfo functions[] = { | 96 | static const FunctionInfo functions[] = { |
| 95 | {0, nullptr, "OpenLocationResolver"}, | 97 | {0, nullptr, "OpenLocationResolver"}, |
| @@ -105,7 +107,7 @@ public: | |||
| 105 | 107 | ||
| 106 | class NCM final : public ServiceFramework<NCM> { | 108 | class NCM final : public ServiceFramework<NCM> { |
| 107 | public: | 109 | public: |
| 108 | explicit NCM() : ServiceFramework{"ncm"} { | 110 | explicit NCM(Core::System& system_) : ServiceFramework{system_, "ncm"} { |
| 109 | // clang-format off | 111 | // clang-format off |
| 110 | static const FunctionInfo functions[] = { | 112 | static const FunctionInfo functions[] = { |
| 111 | {0, nullptr, "CreateContentStorage"}, | 113 | {0, nullptr, "CreateContentStorage"}, |
| @@ -130,9 +132,9 @@ public: | |||
| 130 | } | 132 | } |
| 131 | }; | 133 | }; |
| 132 | 134 | ||
| 133 | void InstallInterfaces(SM::ServiceManager& sm) { | 135 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 134 | std::make_shared<LR>()->InstallAsService(sm); | 136 | std::make_shared<LR>(system)->InstallAsService(sm); |
| 135 | std::make_shared<NCM>()->InstallAsService(sm); | 137 | std::make_shared<NCM>(system)->InstallAsService(sm); |
| 136 | } | 138 | } |
| 137 | 139 | ||
| 138 | } // namespace Service::NCM | 140 | } // namespace Service::NCM |
diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h index 7bc8518a6..ee01eddc0 100644 --- a/src/core/hle/service/ncm/ncm.h +++ b/src/core/hle/service/ncm/ncm.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::NCM { | 15 | namespace Service::NCM { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::NCM | 19 | } // namespace Service::NCM |
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 780ea30fe..6ab35de47 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp | |||
| @@ -16,7 +16,7 @@ namespace Service::NFC { | |||
| 16 | 16 | ||
| 17 | class IAm final : public ServiceFramework<IAm> { | 17 | class IAm final : public ServiceFramework<IAm> { |
| 18 | public: | 18 | public: |
| 19 | explicit IAm() : ServiceFramework{"NFC::IAm"} { | 19 | explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} { |
| 20 | // clang-format off | 20 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 22 | {0, nullptr, "Initialize"}, | 22 | {0, nullptr, "Initialize"}, |
| @@ -31,7 +31,7 @@ public: | |||
| 31 | 31 | ||
| 32 | class NFC_AM final : public ServiceFramework<NFC_AM> { | 32 | class NFC_AM final : public ServiceFramework<NFC_AM> { |
| 33 | public: | 33 | public: |
| 34 | explicit NFC_AM() : ServiceFramework{"nfc:am"} { | 34 | explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} { |
| 35 | // clang-format off | 35 | // clang-format off |
| 36 | static const FunctionInfo functions[] = { | 36 | static const FunctionInfo functions[] = { |
| 37 | {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, | 37 | {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, |
| @@ -47,13 +47,13 @@ private: | |||
| 47 | 47 | ||
| 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 49 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 50 | rb.PushIpcInterface<IAm>(); | 50 | rb.PushIpcInterface<IAm>(system); |
| 51 | } | 51 | } |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | class MFIUser final : public ServiceFramework<MFIUser> { | 54 | class MFIUser final : public ServiceFramework<MFIUser> { |
| 55 | public: | 55 | public: |
| 56 | explicit MFIUser() : ServiceFramework{"NFC::MFIUser"} { | 56 | explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} { |
| 57 | // clang-format off | 57 | // clang-format off |
| 58 | static const FunctionInfo functions[] = { | 58 | static const FunctionInfo functions[] = { |
| 59 | {0, nullptr, "Initialize"}, | 59 | {0, nullptr, "Initialize"}, |
| @@ -79,7 +79,7 @@ public: | |||
| 79 | 79 | ||
| 80 | class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { | 80 | class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { |
| 81 | public: | 81 | public: |
| 82 | explicit NFC_MF_U() : ServiceFramework{"nfc:mf:u"} { | 82 | explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { |
| 83 | // clang-format off | 83 | // clang-format off |
| 84 | static const FunctionInfo functions[] = { | 84 | static const FunctionInfo functions[] = { |
| 85 | {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, | 85 | {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, |
| @@ -95,13 +95,13 @@ private: | |||
| 95 | 95 | ||
| 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 97 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 98 | rb.PushIpcInterface<MFIUser>(); | 98 | rb.PushIpcInterface<MFIUser>(system); |
| 99 | } | 99 | } |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | class IUser final : public ServiceFramework<IUser> { | 102 | class IUser final : public ServiceFramework<IUser> { |
| 103 | public: | 103 | public: |
| 104 | explicit IUser() : ServiceFramework{"NFC::IUser"} { | 104 | explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} { |
| 105 | // clang-format off | 105 | // clang-format off |
| 106 | static const FunctionInfo functions[] = { | 106 | static const FunctionInfo functions[] = { |
| 107 | {0, &IUser::InitializeOld, "InitializeOld"}, | 107 | {0, &IUser::InitializeOld, "InitializeOld"}, |
| @@ -171,7 +171,7 @@ private: | |||
| 171 | 171 | ||
| 172 | class NFC_U final : public ServiceFramework<NFC_U> { | 172 | class NFC_U final : public ServiceFramework<NFC_U> { |
| 173 | public: | 173 | public: |
| 174 | explicit NFC_U() : ServiceFramework{"nfc:user"} { | 174 | explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} { |
| 175 | // clang-format off | 175 | // clang-format off |
| 176 | static const FunctionInfo functions[] = { | 176 | static const FunctionInfo functions[] = { |
| 177 | {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, | 177 | {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, |
| @@ -187,13 +187,13 @@ private: | |||
| 187 | 187 | ||
| 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 189 | rb.Push(RESULT_SUCCESS); | 189 | rb.Push(RESULT_SUCCESS); |
| 190 | rb.PushIpcInterface<IUser>(); | 190 | rb.PushIpcInterface<IUser>(system); |
| 191 | } | 191 | } |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| 194 | class ISystem final : public ServiceFramework<ISystem> { | 194 | class ISystem final : public ServiceFramework<ISystem> { |
| 195 | public: | 195 | public: |
| 196 | explicit ISystem() : ServiceFramework{"ISystem"} { | 196 | explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} { |
| 197 | // clang-format off | 197 | // clang-format off |
| 198 | static const FunctionInfo functions[] = { | 198 | static const FunctionInfo functions[] = { |
| 199 | {0, nullptr, "Initialize"}, | 199 | {0, nullptr, "Initialize"}, |
| @@ -230,7 +230,7 @@ public: | |||
| 230 | 230 | ||
| 231 | class NFC_SYS final : public ServiceFramework<NFC_SYS> { | 231 | class NFC_SYS final : public ServiceFramework<NFC_SYS> { |
| 232 | public: | 232 | public: |
| 233 | explicit NFC_SYS() : ServiceFramework{"nfc:sys"} { | 233 | explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} { |
| 234 | // clang-format off | 234 | // clang-format off |
| 235 | static const FunctionInfo functions[] = { | 235 | static const FunctionInfo functions[] = { |
| 236 | {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, | 236 | {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, |
| @@ -246,15 +246,15 @@ private: | |||
| 246 | 246 | ||
| 247 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 247 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 248 | rb.Push(RESULT_SUCCESS); | 248 | rb.Push(RESULT_SUCCESS); |
| 249 | rb.PushIpcInterface<ISystem>(); | 249 | rb.PushIpcInterface<ISystem>(system); |
| 250 | } | 250 | } |
| 251 | }; | 251 | }; |
| 252 | 252 | ||
| 253 | void InstallInterfaces(SM::ServiceManager& sm) { | 253 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 254 | std::make_shared<NFC_AM>()->InstallAsService(sm); | 254 | std::make_shared<NFC_AM>(system)->InstallAsService(sm); |
| 255 | std::make_shared<NFC_MF_U>()->InstallAsService(sm); | 255 | std::make_shared<NFC_MF_U>(system)->InstallAsService(sm); |
| 256 | std::make_shared<NFC_U>()->InstallAsService(sm); | 256 | std::make_shared<NFC_U>(system)->InstallAsService(sm); |
| 257 | std::make_shared<NFC_SYS>()->InstallAsService(sm); | 257 | std::make_shared<NFC_SYS>(system)->InstallAsService(sm); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | } // namespace Service::NFC | 260 | } // namespace Service::NFC |
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h index 4d2d815f9..5a94b076d 100644 --- a/src/core/hle/service/nfc/nfc.h +++ b/src/core/hle/service/nfc/nfc.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::NFC { | 15 | namespace Service::NFC { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::NFC | 19 | } // namespace Service::NFC |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a0469ffbd..5557da72e 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -21,8 +21,9 @@ namespace ErrCodes { | |||
| 21 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); | 21 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); |
| 22 | } // namespace ErrCodes | 22 | } // namespace ErrCodes |
| 23 | 23 | ||
| 24 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) | 24 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 25 | : ServiceFramework(name), module(std::move(module)), system(system) { | 25 | const char* name) |
| 26 | : ServiceFramework{system_, name}, module{std::move(module_)} { | ||
| 26 | auto& kernel = system.Kernel(); | 27 | auto& kernel = system.Kernel(); |
| 27 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected"); | 28 | nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected"); |
| 28 | } | 29 | } |
| @@ -31,8 +32,8 @@ Module::Interface::~Interface() = default; | |||
| 31 | 32 | ||
| 32 | class IUser final : public ServiceFramework<IUser> { | 33 | class IUser final : public ServiceFramework<IUser> { |
| 33 | public: | 34 | public: |
| 34 | IUser(Module::Interface& nfp_interface, Core::System& system) | 35 | explicit IUser(Module::Interface& nfp_interface_, Core::System& system_) |
| 35 | : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { | 36 | : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_} { |
| 36 | static const FunctionInfo functions[] = { | 37 | static const FunctionInfo functions[] = { |
| 37 | {0, &IUser::Initialize, "Initialize"}, | 38 | {0, &IUser::Initialize, "Initialize"}, |
| 38 | {1, &IUser::Finalize, "Finalize"}, | 39 | {1, &IUser::Finalize, "Finalize"}, |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 200013795..295de535b 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -16,7 +16,8 @@ class Module final { | |||
| 16 | public: | 16 | public: |
| 17 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 18 | public: | 18 | public: |
| 19 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); | 19 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 20 | const char* name); | ||
| 20 | ~Interface() override; | 21 | ~Interface() override; |
| 21 | 22 | ||
| 22 | struct ModelInfo { | 23 | struct ModelInfo { |
| @@ -43,7 +44,6 @@ public: | |||
| 43 | 44 | ||
| 44 | protected: | 45 | protected: |
| 45 | std::shared_ptr<Module> module; | 46 | std::shared_ptr<Module> module; |
| 46 | Core::System& system; | ||
| 47 | }; | 47 | }; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 298184f17..10b0ef944 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::NFP { | 7 | namespace Service::NFP { |
| 8 | 8 | ||
| 9 | NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system) | 9 | NFP_User::NFP_User(std::shared_ptr<Module> module_, Core::System& system_) |
| 10 | : Module::Interface(std::move(module), system, "nfp:user") { | 10 | : Interface(std::move(module_), system_, "nfp:user") { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, | 12 | {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, |
| 13 | }; | 13 | }; |
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 1686ebf20..7f3c124f6 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h | |||
| @@ -10,7 +10,7 @@ namespace Service::NFP { | |||
| 10 | 10 | ||
| 11 | class NFP_User final : public Module::Interface { | 11 | class NFP_User final : public Module::Interface { |
| 12 | public: | 12 | public: |
| 13 | explicit NFP_User(std::shared_ptr<Module> module, Core::System& system); | 13 | explicit NFP_User(std::shared_ptr<Module> module_, Core::System& system_); |
| 14 | ~NFP_User() override; | 14 | ~NFP_User() override; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 2e9d95195..ef5176bea 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -23,7 +23,7 @@ enum class RequestState : u32 { | |||
| 23 | 23 | ||
| 24 | class IScanRequest final : public ServiceFramework<IScanRequest> { | 24 | class IScanRequest final : public ServiceFramework<IScanRequest> { |
| 25 | public: | 25 | public: |
| 26 | explicit IScanRequest() : ServiceFramework("IScanRequest") { | 26 | explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { |
| 27 | // clang-format off | 27 | // clang-format off |
| 28 | static const FunctionInfo functions[] = { | 28 | static const FunctionInfo functions[] = { |
| 29 | {0, nullptr, "Submit"}, | 29 | {0, nullptr, "Submit"}, |
| @@ -40,7 +40,7 @@ public: | |||
| 40 | 40 | ||
| 41 | class IRequest final : public ServiceFramework<IRequest> { | 41 | class IRequest final : public ServiceFramework<IRequest> { |
| 42 | public: | 42 | public: |
| 43 | explicit IRequest(Core::System& system) : ServiceFramework("IRequest") { | 43 | explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} { |
| 44 | static const FunctionInfo functions[] = { | 44 | static const FunctionInfo functions[] = { |
| 45 | {0, &IRequest::GetRequestState, "GetRequestState"}, | 45 | {0, &IRequest::GetRequestState, "GetRequestState"}, |
| 46 | {1, &IRequest::GetResult, "GetResult"}, | 46 | {1, &IRequest::GetResult, "GetResult"}, |
| @@ -62,7 +62,7 @@ public: | |||
| 62 | {18, nullptr, "SetRequirementByRevision"}, | 62 | {18, nullptr, "SetRequirementByRevision"}, |
| 63 | {19, nullptr, "GetRequirement"}, | 63 | {19, nullptr, "GetRequirement"}, |
| 64 | {20, nullptr, "GetRevision"}, | 64 | {20, nullptr, "GetRevision"}, |
| 65 | {21, nullptr, "GetAppletInfo"}, | 65 | {21, &IRequest::GetAppletInfo, "GetAppletInfo"}, |
| 66 | {22, nullptr, "GetAdditionalInfo"}, | 66 | {22, nullptr, "GetAdditionalInfo"}, |
| 67 | {23, nullptr, "SetKeptInSleep"}, | 67 | {23, nullptr, "SetKeptInSleep"}, |
| 68 | {24, nullptr, "RegisterSocketDescriptor"}, | 68 | {24, nullptr, "RegisterSocketDescriptor"}, |
| @@ -125,12 +125,22 @@ private: | |||
| 125 | rb.Push(RESULT_SUCCESS); | 125 | rb.Push(RESULT_SUCCESS); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | void GetAppletInfo(Kernel::HLERequestContext& ctx) { | ||
| 129 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 130 | |||
| 131 | IPC::ResponseBuilder rb{ctx, 8}; | ||
| 132 | rb.Push(RESULT_SUCCESS); | ||
| 133 | rb.Push<u32>(0); | ||
| 134 | rb.Push<u32>(0); | ||
| 135 | rb.Push<u32>(0); | ||
| 136 | } | ||
| 137 | |||
| 128 | Kernel::EventPair event1, event2; | 138 | Kernel::EventPair event1, event2; |
| 129 | }; | 139 | }; |
| 130 | 140 | ||
| 131 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { | 141 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { |
| 132 | public: | 142 | public: |
| 133 | explicit INetworkProfile() : ServiceFramework("INetworkProfile") { | 143 | explicit INetworkProfile(Core::System& system_) : ServiceFramework{system_, "INetworkProfile"} { |
| 134 | static const FunctionInfo functions[] = { | 144 | static const FunctionInfo functions[] = { |
| 135 | {0, nullptr, "Update"}, | 145 | {0, nullptr, "Update"}, |
| 136 | {1, nullptr, "PersistOld"}, | 146 | {1, nullptr, "PersistOld"}, |
| @@ -142,7 +152,7 @@ public: | |||
| 142 | 152 | ||
| 143 | class IGeneralService final : public ServiceFramework<IGeneralService> { | 153 | class IGeneralService final : public ServiceFramework<IGeneralService> { |
| 144 | public: | 154 | public: |
| 145 | IGeneralService(Core::System& system); | 155 | explicit IGeneralService(Core::System& system_); |
| 146 | 156 | ||
| 147 | private: | 157 | private: |
| 148 | void GetClientId(Kernel::HLERequestContext& ctx) { | 158 | void GetClientId(Kernel::HLERequestContext& ctx) { |
| @@ -159,7 +169,7 @@ private: | |||
| 159 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 169 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 160 | 170 | ||
| 161 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| 162 | rb.PushIpcInterface<IScanRequest>(); | 172 | rb.PushIpcInterface<IScanRequest>(system); |
| 163 | } | 173 | } |
| 164 | void CreateRequest(Kernel::HLERequestContext& ctx) { | 174 | void CreateRequest(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_DEBUG(Service_NIFM, "called"); | 175 | LOG_DEBUG(Service_NIFM, "called"); |
| @@ -197,7 +207,7 @@ private: | |||
| 197 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | 207 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
| 198 | 208 | ||
| 199 | rb.Push(RESULT_SUCCESS); | 209 | rb.Push(RESULT_SUCCESS); |
| 200 | rb.PushIpcInterface<INetworkProfile>(); | 210 | rb.PushIpcInterface<INetworkProfile>(system); |
| 201 | rb.PushRaw<u128>(uuid); | 211 | rb.PushRaw<u128>(uuid); |
| 202 | } | 212 | } |
| 203 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 213 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -229,11 +239,10 @@ private: | |||
| 229 | rb.Push<u8>(1); | 239 | rb.Push<u8>(1); |
| 230 | } | 240 | } |
| 231 | } | 241 | } |
| 232 | Core::System& system; | ||
| 233 | }; | 242 | }; |
| 234 | 243 | ||
| 235 | IGeneralService::IGeneralService(Core::System& system) | 244 | IGeneralService::IGeneralService(Core::System& system_) |
| 236 | : ServiceFramework("IGeneralService"), system(system) { | 245 | : ServiceFramework{system_, "IGeneralService"} { |
| 237 | // clang-format off | 246 | // clang-format off |
| 238 | static const FunctionInfo functions[] = { | 247 | static const FunctionInfo functions[] = { |
| 239 | {1, &IGeneralService::GetClientId, "GetClientId"}, | 248 | {1, &IGeneralService::GetClientId, "GetClientId"}, |
| @@ -286,8 +295,8 @@ IGeneralService::IGeneralService(Core::System& system) | |||
| 286 | 295 | ||
| 287 | class NetworkInterface final : public ServiceFramework<NetworkInterface> { | 296 | class NetworkInterface final : public ServiceFramework<NetworkInterface> { |
| 288 | public: | 297 | public: |
| 289 | explicit NetworkInterface(const char* name, Core::System& system) | 298 | explicit NetworkInterface(const char* name, Core::System& system_) |
| 290 | : ServiceFramework{name}, system(system) { | 299 | : ServiceFramework{system_, name} { |
| 291 | static const FunctionInfo functions[] = { | 300 | static const FunctionInfo functions[] = { |
| 292 | {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, | 301 | {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, |
| 293 | {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, | 302 | {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, |
| @@ -295,6 +304,7 @@ public: | |||
| 295 | RegisterHandlers(functions); | 304 | RegisterHandlers(functions); |
| 296 | } | 305 | } |
| 297 | 306 | ||
| 307 | private: | ||
| 298 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 308 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { |
| 299 | LOG_DEBUG(Service_NIFM, "called"); | 309 | LOG_DEBUG(Service_NIFM, "called"); |
| 300 | 310 | ||
| @@ -310,9 +320,6 @@ public: | |||
| 310 | rb.Push(RESULT_SUCCESS); | 320 | rb.Push(RESULT_SUCCESS); |
| 311 | rb.PushIpcInterface<IGeneralService>(system); | 321 | rb.PushIpcInterface<IGeneralService>(system); |
| 312 | } | 322 | } |
| 313 | |||
| 314 | private: | ||
| 315 | Core::System& system; | ||
| 316 | }; | 323 | }; |
| 317 | 324 | ||
| 318 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 325 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 6857e18f9..c3dd4f386 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h | |||
| @@ -4,14 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Service::SM { | ||
| 8 | class ServiceManager; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Core { | 7 | namespace Core { |
| 12 | class System; | 8 | class System; |
| 13 | } | 9 | } |
| 14 | 10 | ||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::NIFM { | 15 | namespace Service::NIFM { |
| 16 | 16 | ||
| 17 | /// Registers all NIFM services with the specified service manager. | 17 | /// Registers all NIFM services with the specified service manager. |
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 11aa74828..d16223064 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -17,7 +17,8 @@ namespace Service::NIM { | |||
| 17 | 17 | ||
| 18 | class IShopServiceAsync final : public ServiceFramework<IShopServiceAsync> { | 18 | class IShopServiceAsync final : public ServiceFramework<IShopServiceAsync> { |
| 19 | public: | 19 | public: |
| 20 | IShopServiceAsync() : ServiceFramework("IShopServiceAsync") { | 20 | explicit IShopServiceAsync(Core::System& system_) |
| 21 | : ServiceFramework{system_, "IShopServiceAsync"} { | ||
| 21 | // clang-format off | 22 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 23 | static const FunctionInfo functions[] = { |
| 23 | {0, nullptr, "Cancel"}, | 24 | {0, nullptr, "Cancel"}, |
| @@ -35,7 +36,8 @@ public: | |||
| 35 | 36 | ||
| 36 | class IShopServiceAccessor final : public ServiceFramework<IShopServiceAccessor> { | 37 | class IShopServiceAccessor final : public ServiceFramework<IShopServiceAccessor> { |
| 37 | public: | 38 | public: |
| 38 | IShopServiceAccessor() : ServiceFramework("IShopServiceAccessor") { | 39 | explicit IShopServiceAccessor(Core::System& system_) |
| 40 | : ServiceFramework{system_, "IShopServiceAccessor"} { | ||
| 39 | // clang-format off | 41 | // clang-format off |
| 40 | static const FunctionInfo functions[] = { | 42 | static const FunctionInfo functions[] = { |
| 41 | {0, &IShopServiceAccessor::CreateAsyncInterface, "CreateAsyncInterface"}, | 43 | {0, &IShopServiceAccessor::CreateAsyncInterface, "CreateAsyncInterface"}, |
| @@ -50,13 +52,14 @@ private: | |||
| 50 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | 52 | LOG_WARNING(Service_NIM, "(STUBBED) called"); |
| 51 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 53 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 52 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 53 | rb.PushIpcInterface<IShopServiceAsync>(); | 55 | rb.PushIpcInterface<IShopServiceAsync>(system); |
| 54 | } | 56 | } |
| 55 | }; | 57 | }; |
| 56 | 58 | ||
| 57 | class IShopServiceAccessServer final : public ServiceFramework<IShopServiceAccessServer> { | 59 | class IShopServiceAccessServer final : public ServiceFramework<IShopServiceAccessServer> { |
| 58 | public: | 60 | public: |
| 59 | IShopServiceAccessServer() : ServiceFramework("IShopServiceAccessServer") { | 61 | explicit IShopServiceAccessServer(Core::System& system_) |
| 62 | : ServiceFramework{system_, "IShopServiceAccessServer"} { | ||
| 60 | // clang-format off | 63 | // clang-format off |
| 61 | static const FunctionInfo functions[] = { | 64 | static const FunctionInfo functions[] = { |
| 62 | {0, &IShopServiceAccessServer::CreateAccessorInterface, "CreateAccessorInterface"}, | 65 | {0, &IShopServiceAccessServer::CreateAccessorInterface, "CreateAccessorInterface"}, |
| @@ -71,13 +74,13 @@ private: | |||
| 71 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | 74 | LOG_WARNING(Service_NIM, "(STUBBED) called"); |
| 72 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 73 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 74 | rb.PushIpcInterface<IShopServiceAccessor>(); | 77 | rb.PushIpcInterface<IShopServiceAccessor>(system); |
| 75 | } | 78 | } |
| 76 | }; | 79 | }; |
| 77 | 80 | ||
| 78 | class NIM final : public ServiceFramework<NIM> { | 81 | class NIM final : public ServiceFramework<NIM> { |
| 79 | public: | 82 | public: |
| 80 | explicit NIM() : ServiceFramework{"nim"} { | 83 | explicit NIM(Core::System& system_) : ServiceFramework{system_, "nim"} { |
| 81 | // clang-format off | 84 | // clang-format off |
| 82 | static const FunctionInfo functions[] = { | 85 | static const FunctionInfo functions[] = { |
| 83 | {0, nullptr, "CreateSystemUpdateTask"}, | 86 | {0, nullptr, "CreateSystemUpdateTask"}, |
| @@ -207,14 +210,14 @@ public: | |||
| 207 | 210 | ||
| 208 | class NIM_ECA final : public ServiceFramework<NIM_ECA> { | 211 | class NIM_ECA final : public ServiceFramework<NIM_ECA> { |
| 209 | public: | 212 | public: |
| 210 | explicit NIM_ECA() : ServiceFramework{"nim:eca"} { | 213 | explicit NIM_ECA(Core::System& system_) : ServiceFramework{system_, "nim:eca"} { |
| 211 | // clang-format off | 214 | // clang-format off |
| 212 | static const FunctionInfo functions[] = { | 215 | static const FunctionInfo functions[] = { |
| 213 | {0, &NIM_ECA::CreateServerInterface, "CreateServerInterface"}, | 216 | {0, &NIM_ECA::CreateServerInterface, "CreateServerInterface"}, |
| 214 | {1, nullptr, "RefreshDebugAvailability"}, | 217 | {1, nullptr, "RefreshDebugAvailability"}, |
| 215 | {2, nullptr, "ClearDebugResponse"}, | 218 | {2, nullptr, "ClearDebugResponse"}, |
| 216 | {3, nullptr, "RegisterDebugResponse"}, | 219 | {3, nullptr, "RegisterDebugResponse"}, |
| 217 | {4, nullptr, "IsLargeResourceAvailable"}, | 220 | {4, &NIM_ECA::IsLargeResourceAvailable, "IsLargeResourceAvailable"}, |
| 218 | }; | 221 | }; |
| 219 | // clang-format on | 222 | // clang-format on |
| 220 | 223 | ||
| @@ -226,13 +229,25 @@ private: | |||
| 226 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | 229 | LOG_WARNING(Service_NIM, "(STUBBED) called"); |
| 227 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 230 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 228 | rb.Push(RESULT_SUCCESS); | 231 | rb.Push(RESULT_SUCCESS); |
| 229 | rb.PushIpcInterface<IShopServiceAccessServer>(); | 232 | rb.PushIpcInterface<IShopServiceAccessServer>(system); |
| 233 | } | ||
| 234 | |||
| 235 | void IsLargeResourceAvailable(Kernel::HLERequestContext& ctx) { | ||
| 236 | IPC::RequestParser rp{ctx}; | ||
| 237 | |||
| 238 | const auto unknown{rp.Pop<u64>()}; | ||
| 239 | |||
| 240 | LOG_INFO(Service_NIM, "(STUBBED) called, unknown={}", unknown); | ||
| 241 | |||
| 242 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 243 | rb.Push(RESULT_SUCCESS); | ||
| 244 | rb.Push(false); | ||
| 230 | } | 245 | } |
| 231 | }; | 246 | }; |
| 232 | 247 | ||
| 233 | class NIM_SHP final : public ServiceFramework<NIM_SHP> { | 248 | class NIM_SHP final : public ServiceFramework<NIM_SHP> { |
| 234 | public: | 249 | public: |
| 235 | explicit NIM_SHP() : ServiceFramework{"nim:shp"} { | 250 | explicit NIM_SHP(Core::System& system_) : ServiceFramework{system_, "nim:shp"} { |
| 236 | // clang-format off | 251 | // clang-format off |
| 237 | static const FunctionInfo functions[] = { | 252 | static const FunctionInfo functions[] = { |
| 238 | {0, nullptr, "RequestDeviceAuthenticationToken"}, | 253 | {0, nullptr, "RequestDeviceAuthenticationToken"}, |
| @@ -272,8 +287,8 @@ public: | |||
| 272 | class IEnsureNetworkClockAvailabilityService final | 287 | class IEnsureNetworkClockAvailabilityService final |
| 273 | : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { | 288 | : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { |
| 274 | public: | 289 | public: |
| 275 | explicit IEnsureNetworkClockAvailabilityService(Core::System& system) | 290 | explicit IEnsureNetworkClockAvailabilityService(Core::System& system_) |
| 276 | : ServiceFramework("IEnsureNetworkClockAvailabilityService") { | 291 | : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"} { |
| 277 | static const FunctionInfo functions[] = { | 292 | static const FunctionInfo functions[] = { |
| 278 | {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, | 293 | {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, |
| 279 | {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, | 294 | {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, |
| @@ -345,7 +360,7 @@ private: | |||
| 345 | 360 | ||
| 346 | class NTC final : public ServiceFramework<NTC> { | 361 | class NTC final : public ServiceFramework<NTC> { |
| 347 | public: | 362 | public: |
| 348 | explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) { | 363 | explicit NTC(Core::System& system_) : ServiceFramework{system_, "ntc"} { |
| 349 | // clang-format off | 364 | // clang-format off |
| 350 | static const FunctionInfo functions[] = { | 365 | static const FunctionInfo functions[] = { |
| 351 | {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, | 366 | {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, |
| @@ -380,13 +395,12 @@ private: | |||
| 380 | IPC::ResponseBuilder rb{ctx, 2}; | 395 | IPC::ResponseBuilder rb{ctx, 2}; |
| 381 | rb.Push(RESULT_SUCCESS); | 396 | rb.Push(RESULT_SUCCESS); |
| 382 | } | 397 | } |
| 383 | Core::System& system; | ||
| 384 | }; | 398 | }; |
| 385 | 399 | ||
| 386 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { | 400 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 387 | std::make_shared<NIM>()->InstallAsService(sm); | 401 | std::make_shared<NIM>(system)->InstallAsService(sm); |
| 388 | std::make_shared<NIM_ECA>()->InstallAsService(sm); | 402 | std::make_shared<NIM_ECA>(system)->InstallAsService(sm); |
| 389 | std::make_shared<NIM_SHP>()->InstallAsService(sm); | 403 | std::make_shared<NIM_SHP>(system)->InstallAsService(sm); |
| 390 | std::make_shared<NTC>(system)->InstallAsService(sm); | 404 | std::make_shared<NTC>(system)->InstallAsService(sm); |
| 391 | } | 405 | } |
| 392 | 406 | ||
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h index dbe25dc01..571153fe6 100644 --- a/src/core/hle/service/nim/nim.h +++ b/src/core/hle/service/nim/nim.h | |||
| @@ -4,14 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Service::SM { | ||
| 8 | class ServiceManager; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Core { | 7 | namespace Core { |
| 12 | class System; | 8 | class System; |
| 13 | } | 9 | } |
| 14 | 10 | ||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::NIM { | 15 | namespace Service::NIM { |
| 16 | 16 | ||
| 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp index 8fa16fb08..f7a58f659 100644 --- a/src/core/hle/service/npns/npns.cpp +++ b/src/core/hle/service/npns/npns.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::NPNS { | |||
| 12 | 12 | ||
| 13 | class NPNS_S final : public ServiceFramework<NPNS_S> { | 13 | class NPNS_S final : public ServiceFramework<NPNS_S> { |
| 14 | public: | 14 | public: |
| 15 | explicit NPNS_S() : ServiceFramework{"npns:s"} { | 15 | explicit NPNS_S(Core::System& system_) : ServiceFramework{system_, "npns:s"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {1, nullptr, "ListenAll"}, | 18 | {1, nullptr, "ListenAll"}, |
| @@ -62,7 +62,7 @@ public: | |||
| 62 | 62 | ||
| 63 | class NPNS_U final : public ServiceFramework<NPNS_U> { | 63 | class NPNS_U final : public ServiceFramework<NPNS_U> { |
| 64 | public: | 64 | public: |
| 65 | explicit NPNS_U() : ServiceFramework{"npns:u"} { | 65 | explicit NPNS_U(Core::System& system_) : ServiceFramework{system_, "npns:u"} { |
| 66 | // clang-format off | 66 | // clang-format off |
| 67 | static const FunctionInfo functions[] = { | 67 | static const FunctionInfo functions[] = { |
| 68 | {1, nullptr, "ListenAll"}, | 68 | {1, nullptr, "ListenAll"}, |
| @@ -91,9 +91,9 @@ public: | |||
| 91 | } | 91 | } |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | void InstallInterfaces(SM::ServiceManager& sm) { | 94 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 95 | std::make_shared<NPNS_S>()->InstallAsService(sm); | 95 | std::make_shared<NPNS_S>(system)->InstallAsService(sm); |
| 96 | std::make_shared<NPNS_U>()->InstallAsService(sm); | 96 | std::make_shared<NPNS_U>(system)->InstallAsService(sm); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | } // namespace Service::NPNS | 99 | } // namespace Service::NPNS |
diff --git a/src/core/hle/service/npns/npns.h b/src/core/hle/service/npns/npns.h index 861cd3e48..3b7596b6b 100644 --- a/src/core/hle/service/npns/npns.h +++ b/src/core/hle/service/npns/npns.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::NPNS { | 15 | namespace Service::NPNS { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::NPNS | 19 | } // namespace Service::NPNS |
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 58ee1f712..6ccf8995c 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/file_sys/control_metadata.h" | 7 | #include "core/file_sys/control_metadata.h" |
| 7 | #include "core/file_sys/patch_manager.h" | 8 | #include "core/file_sys/patch_manager.h" |
| 8 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| @@ -17,7 +18,8 @@ | |||
| 17 | 18 | ||
| 18 | namespace Service::NS { | 19 | namespace Service::NS { |
| 19 | 20 | ||
| 20 | IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} { | 21 | IAccountProxyInterface::IAccountProxyInterface(Core::System& system_) |
| 22 | : ServiceFramework{system_, "IAccountProxyInterface"} { | ||
| 21 | // clang-format off | 23 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 24 | static const FunctionInfo functions[] = { |
| 23 | {0, nullptr, "CreateUserAccount"}, | 25 | {0, nullptr, "CreateUserAccount"}, |
| @@ -29,8 +31,8 @@ IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountPro | |||
| 29 | 31 | ||
| 30 | IAccountProxyInterface::~IAccountProxyInterface() = default; | 32 | IAccountProxyInterface::~IAccountProxyInterface() = default; |
| 31 | 33 | ||
| 32 | IApplicationManagerInterface::IApplicationManagerInterface() | 34 | IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_) |
| 33 | : ServiceFramework{"IApplicationManagerInterface"} { | 35 | : ServiceFramework{system_, "IApplicationManagerInterface"} { |
| 34 | // clang-format off | 36 | // clang-format off |
| 35 | static const FunctionInfo functions[] = { | 37 | static const FunctionInfo functions[] = { |
| 36 | {0, nullptr, "ListApplicationRecord"}, | 38 | {0, nullptr, "ListApplicationRecord"}, |
| @@ -298,7 +300,8 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC | |||
| 298 | 300 | ||
| 299 | const auto size = ctx.GetWriteBufferSize(); | 301 | const auto size = ctx.GetWriteBufferSize(); |
| 300 | 302 | ||
| 301 | const FileSys::PatchManager pm{title_id}; | 303 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 304 | system.GetContentProvider()}; | ||
| 302 | const auto control = pm.GetControlMetadata(); | 305 | const auto control = pm.GetControlMetadata(); |
| 303 | 306 | ||
| 304 | std::vector<u8> out; | 307 | std::vector<u8> out; |
| @@ -426,8 +429,8 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag | |||
| 426 | return MakeResult(static_cast<u64>(*language_code)); | 429 | return MakeResult(static_cast<u64>(*language_code)); |
| 427 | } | 430 | } |
| 428 | 431 | ||
| 429 | IApplicationVersionInterface::IApplicationVersionInterface() | 432 | IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_) |
| 430 | : ServiceFramework{"IApplicationVersionInterface"} { | 433 | : ServiceFramework{system_, "IApplicationVersionInterface"} { |
| 431 | // clang-format off | 434 | // clang-format off |
| 432 | static const FunctionInfo functions[] = { | 435 | static const FunctionInfo functions[] = { |
| 433 | {0, nullptr, "GetLaunchRequiredVersion"}, | 436 | {0, nullptr, "GetLaunchRequiredVersion"}, |
| @@ -447,8 +450,8 @@ IApplicationVersionInterface::IApplicationVersionInterface() | |||
| 447 | 450 | ||
| 448 | IApplicationVersionInterface::~IApplicationVersionInterface() = default; | 451 | IApplicationVersionInterface::~IApplicationVersionInterface() = default; |
| 449 | 452 | ||
| 450 | IContentManagementInterface::IContentManagementInterface() | 453 | IContentManagementInterface::IContentManagementInterface(Core::System& system_) |
| 451 | : ServiceFramework{"IContentManagementInterface"} { | 454 | : ServiceFramework{system_, "IContentManagementInterface"} { |
| 452 | // clang-format off | 455 | // clang-format off |
| 453 | static const FunctionInfo functions[] = { | 456 | static const FunctionInfo functions[] = { |
| 454 | {11, nullptr, "CalculateApplicationOccupiedSize"}, | 457 | {11, nullptr, "CalculateApplicationOccupiedSize"}, |
| @@ -467,7 +470,8 @@ IContentManagementInterface::IContentManagementInterface() | |||
| 467 | 470 | ||
| 468 | IContentManagementInterface::~IContentManagementInterface() = default; | 471 | IContentManagementInterface::~IContentManagementInterface() = default; |
| 469 | 472 | ||
| 470 | IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { | 473 | IDocumentInterface::IDocumentInterface(Core::System& system_) |
| 474 | : ServiceFramework{system_, "IDocumentInterface"} { | ||
| 471 | // clang-format off | 475 | // clang-format off |
| 472 | static const FunctionInfo functions[] = { | 476 | static const FunctionInfo functions[] = { |
| 473 | {21, nullptr, "GetApplicationContentPath"}, | 477 | {21, nullptr, "GetApplicationContentPath"}, |
| @@ -481,7 +485,8 @@ IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface" | |||
| 481 | 485 | ||
| 482 | IDocumentInterface::~IDocumentInterface() = default; | 486 | IDocumentInterface::~IDocumentInterface() = default; |
| 483 | 487 | ||
| 484 | IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} { | 488 | IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) |
| 489 | : ServiceFramework{system_, "IDownloadTaskInterface"} { | ||
| 485 | // clang-format off | 490 | // clang-format off |
| 486 | static const FunctionInfo functions[] = { | 491 | static const FunctionInfo functions[] = { |
| 487 | {701, nullptr, "ClearTaskStatusList"}, | 492 | {701, nullptr, "ClearTaskStatusList"}, |
| @@ -501,7 +506,8 @@ IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTa | |||
| 501 | 506 | ||
| 502 | IDownloadTaskInterface::~IDownloadTaskInterface() = default; | 507 | IDownloadTaskInterface::~IDownloadTaskInterface() = default; |
| 503 | 508 | ||
| 504 | IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterface"} { | 509 | IECommerceInterface::IECommerceInterface(Core::System& system_) |
| 510 | : ServiceFramework{system_, "IECommerceInterface"} { | ||
| 505 | // clang-format off | 511 | // clang-format off |
| 506 | static const FunctionInfo functions[] = { | 512 | static const FunctionInfo functions[] = { |
| 507 | {0, nullptr, "RequestLinkDevice"}, | 513 | {0, nullptr, "RequestLinkDevice"}, |
| @@ -519,8 +525,8 @@ IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterfa | |||
| 519 | 525 | ||
| 520 | IECommerceInterface::~IECommerceInterface() = default; | 526 | IECommerceInterface::~IECommerceInterface() = default; |
| 521 | 527 | ||
| 522 | IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface() | 528 | IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) |
| 523 | : ServiceFramework{"IFactoryResetInterface"} { | 529 | : ServiceFramework{system_, "IFactoryResetInterface"} { |
| 524 | // clang-format off | 530 | // clang-format off |
| 525 | static const FunctionInfo functions[] = { | 531 | static const FunctionInfo functions[] = { |
| 526 | {100, nullptr, "ResetToFactorySettings"}, | 532 | {100, nullptr, "ResetToFactorySettings"}, |
| @@ -538,14 +544,14 @@ IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface() | |||
| 538 | 544 | ||
| 539 | IFactoryResetInterface::~IFactoryResetInterface() = default; | 545 | IFactoryResetInterface::~IFactoryResetInterface() = default; |
| 540 | 546 | ||
| 541 | NS::NS(const char* name) : ServiceFramework{name} { | 547 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { |
| 542 | // clang-format off | 548 | // clang-format off |
| 543 | static const FunctionInfo functions[] = { | 549 | static const FunctionInfo functions[] = { |
| 544 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, | 550 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, |
| 545 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, | 551 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, |
| 546 | {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, | 552 | {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, |
| 547 | {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, | 553 | {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, |
| 548 | {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, | 554 | {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"}, |
| 549 | {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, | 555 | {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, |
| 550 | {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, | 556 | {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, |
| 551 | {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, | 557 | {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, |
| @@ -558,12 +564,12 @@ NS::NS(const char* name) : ServiceFramework{name} { | |||
| 558 | NS::~NS() = default; | 564 | NS::~NS() = default; |
| 559 | 565 | ||
| 560 | std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { | 566 | std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { |
| 561 | return GetInterface<IApplicationManagerInterface>(); | 567 | return GetInterface<IApplicationManagerInterface>(system); |
| 562 | } | 568 | } |
| 563 | 569 | ||
| 564 | class NS_DEV final : public ServiceFramework<NS_DEV> { | 570 | class NS_DEV final : public ServiceFramework<NS_DEV> { |
| 565 | public: | 571 | public: |
| 566 | explicit NS_DEV() : ServiceFramework{"ns:dev"} { | 572 | explicit NS_DEV(Core::System& system_) : ServiceFramework{system_, "ns:dev"} { |
| 567 | // clang-format off | 573 | // clang-format off |
| 568 | static const FunctionInfo functions[] = { | 574 | static const FunctionInfo functions[] = { |
| 569 | {0, nullptr, "LaunchProgram"}, | 575 | {0, nullptr, "LaunchProgram"}, |
| @@ -590,7 +596,8 @@ public: | |||
| 590 | 596 | ||
| 591 | class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> { | 597 | class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> { |
| 592 | public: | 598 | public: |
| 593 | explicit ISystemUpdateControl() : ServiceFramework{"ISystemUpdateControl"} { | 599 | explicit ISystemUpdateControl(Core::System& system_) |
| 600 | : ServiceFramework{system_, "ISystemUpdateControl"} { | ||
| 594 | // clang-format off | 601 | // clang-format off |
| 595 | static const FunctionInfo functions[] = { | 602 | static const FunctionInfo functions[] = { |
| 596 | {0, nullptr, "HasDownloaded"}, | 603 | {0, nullptr, "HasDownloaded"}, |
| @@ -625,7 +632,7 @@ public: | |||
| 625 | 632 | ||
| 626 | class NS_SU final : public ServiceFramework<NS_SU> { | 633 | class NS_SU final : public ServiceFramework<NS_SU> { |
| 627 | public: | 634 | public: |
| 628 | explicit NS_SU() : ServiceFramework{"ns:su"} { | 635 | explicit NS_SU(Core::System& system_) : ServiceFramework{system_, "ns:su"} { |
| 629 | // clang-format off | 636 | // clang-format off |
| 630 | static const FunctionInfo functions[] = { | 637 | static const FunctionInfo functions[] = { |
| 631 | {0, nullptr, "GetBackgroundNetworkUpdateState"}, | 638 | {0, nullptr, "GetBackgroundNetworkUpdateState"}, |
| @@ -657,16 +664,16 @@ private: | |||
| 657 | 664 | ||
| 658 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 665 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 659 | rb.Push(RESULT_SUCCESS); | 666 | rb.Push(RESULT_SUCCESS); |
| 660 | rb.PushIpcInterface<ISystemUpdateControl>(); | 667 | rb.PushIpcInterface<ISystemUpdateControl>(system); |
| 661 | } | 668 | } |
| 662 | }; | 669 | }; |
| 663 | 670 | ||
| 664 | class NS_VM final : public ServiceFramework<NS_VM> { | 671 | class NS_VM final : public ServiceFramework<NS_VM> { |
| 665 | public: | 672 | public: |
| 666 | explicit NS_VM() : ServiceFramework{"ns:vm"} { | 673 | explicit NS_VM(Core::System& system_) : ServiceFramework{system_, "ns:vm"} { |
| 667 | // clang-format off | 674 | // clang-format off |
| 668 | static const FunctionInfo functions[] = { | 675 | static const FunctionInfo functions[] = { |
| 669 | {1200, nullptr, "NeedsUpdateVulnerability"}, | 676 | {1200, &NS_VM::NeedsUpdateVulnerability, "NeedsUpdateVulnerability"}, |
| 670 | {1201, nullptr, "UpdateSafeSystemVersionForDebug"}, | 677 | {1201, nullptr, "UpdateSafeSystemVersionForDebug"}, |
| 671 | {1202, nullptr, "GetSafeSystemVersion"}, | 678 | {1202, nullptr, "GetSafeSystemVersion"}, |
| 672 | }; | 679 | }; |
| @@ -674,19 +681,28 @@ public: | |||
| 674 | 681 | ||
| 675 | RegisterHandlers(functions); | 682 | RegisterHandlers(functions); |
| 676 | } | 683 | } |
| 684 | |||
| 685 | private: | ||
| 686 | void NeedsUpdateVulnerability(Kernel::HLERequestContext& ctx) { | ||
| 687 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 688 | |||
| 689 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 690 | rb.Push(RESULT_SUCCESS); | ||
| 691 | rb.Push(false); | ||
| 692 | } | ||
| 677 | }; | 693 | }; |
| 678 | 694 | ||
| 679 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 695 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 680 | 696 | ||
| 681 | std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); | 697 | std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager); |
| 682 | std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); | 698 | std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager); |
| 683 | std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); | 699 | std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager); |
| 684 | std::make_shared<NS>("ns:rt")->InstallAsService(service_manager); | 700 | std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager); |
| 685 | std::make_shared<NS>("ns:web")->InstallAsService(service_manager); | 701 | std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager); |
| 686 | 702 | ||
| 687 | std::make_shared<NS_DEV>()->InstallAsService(service_manager); | 703 | std::make_shared<NS_DEV>(system)->InstallAsService(service_manager); |
| 688 | std::make_shared<NS_SU>()->InstallAsService(service_manager); | 704 | std::make_shared<NS_SU>(system)->InstallAsService(service_manager); |
| 689 | std::make_shared<NS_VM>()->InstallAsService(service_manager); | 705 | std::make_shared<NS_VM>(system)->InstallAsService(service_manager); |
| 690 | 706 | ||
| 691 | std::make_shared<PL_U>(system)->InstallAsService(service_manager); | 707 | std::make_shared<PL_U>(system)->InstallAsService(service_manager); |
| 692 | } | 708 | } |
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index c2554b878..991271f3e 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service { | 13 | namespace Service { |
| 10 | 14 | ||
| 11 | namespace FileSystem { | 15 | namespace FileSystem { |
| @@ -16,13 +20,13 @@ namespace NS { | |||
| 16 | 20 | ||
| 17 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { | 21 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { |
| 18 | public: | 22 | public: |
| 19 | explicit IAccountProxyInterface(); | 23 | explicit IAccountProxyInterface(Core::System& system_); |
| 20 | ~IAccountProxyInterface() override; | 24 | ~IAccountProxyInterface() override; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { | 27 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { |
| 24 | public: | 28 | public: |
| 25 | explicit IApplicationManagerInterface(); | 29 | explicit IApplicationManagerInterface(Core::System& system_); |
| 26 | ~IApplicationManagerInterface() override; | 30 | ~IApplicationManagerInterface() override; |
| 27 | 31 | ||
| 28 | ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); | 32 | ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); |
| @@ -36,63 +40,71 @@ private: | |||
| 36 | 40 | ||
| 37 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | 41 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { |
| 38 | public: | 42 | public: |
| 39 | explicit IApplicationVersionInterface(); | 43 | explicit IApplicationVersionInterface(Core::System& system_); |
| 40 | ~IApplicationVersionInterface() override; | 44 | ~IApplicationVersionInterface() override; |
| 41 | }; | 45 | }; |
| 42 | 46 | ||
| 43 | class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { | 47 | class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { |
| 44 | public: | 48 | public: |
| 45 | explicit IContentManagementInterface(); | 49 | explicit IContentManagementInterface(Core::System& system_); |
| 46 | ~IContentManagementInterface() override; | 50 | ~IContentManagementInterface() override; |
| 47 | }; | 51 | }; |
| 48 | 52 | ||
| 49 | class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { | 53 | class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { |
| 50 | public: | 54 | public: |
| 51 | explicit IDocumentInterface(); | 55 | explicit IDocumentInterface(Core::System& system_); |
| 52 | ~IDocumentInterface() override; | 56 | ~IDocumentInterface() override; |
| 53 | }; | 57 | }; |
| 54 | 58 | ||
| 55 | class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { | 59 | class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { |
| 56 | public: | 60 | public: |
| 57 | explicit IDownloadTaskInterface(); | 61 | explicit IDownloadTaskInterface(Core::System& system_); |
| 58 | ~IDownloadTaskInterface() override; | 62 | ~IDownloadTaskInterface() override; |
| 59 | }; | 63 | }; |
| 60 | 64 | ||
| 61 | class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { | 65 | class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { |
| 62 | public: | 66 | public: |
| 63 | explicit IECommerceInterface(); | 67 | explicit IECommerceInterface(Core::System& system_); |
| 64 | ~IECommerceInterface() override; | 68 | ~IECommerceInterface() override; |
| 65 | }; | 69 | }; |
| 66 | 70 | ||
| 67 | class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { | 71 | class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { |
| 68 | public: | 72 | public: |
| 69 | explicit IFactoryResetInterface(); | 73 | explicit IFactoryResetInterface(Core::System& system_); |
| 70 | ~IFactoryResetInterface() override; | 74 | ~IFactoryResetInterface() override; |
| 71 | }; | 75 | }; |
| 72 | 76 | ||
| 73 | class NS final : public ServiceFramework<NS> { | 77 | class NS final : public ServiceFramework<NS> { |
| 74 | public: | 78 | public: |
| 75 | explicit NS(const char* name); | 79 | explicit NS(const char* name, Core::System& system_); |
| 76 | ~NS() override; | 80 | ~NS() override; |
| 77 | 81 | ||
| 78 | std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; | 82 | std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; |
| 79 | 83 | ||
| 80 | private: | 84 | private: |
| 81 | template <typename T> | 85 | template <typename T, typename... Args> |
| 82 | void PushInterface(Kernel::HLERequestContext& ctx) { | 86 | void PushInterface(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_DEBUG(Service_NS, "called"); | 87 | LOG_DEBUG(Service_NS, "called"); |
| 84 | 88 | ||
| 85 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 89 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 86 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 87 | rb.PushIpcInterface<T>(); | 91 | rb.PushIpcInterface<T>(system); |
| 92 | } | ||
| 93 | |||
| 94 | void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) { | ||
| 95 | LOG_DEBUG(Service_NS, "called"); | ||
| 96 | |||
| 97 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 98 | rb.Push(RESULT_SUCCESS); | ||
| 99 | rb.PushIpcInterface<IApplicationManagerInterface>(system); | ||
| 88 | } | 100 | } |
| 89 | 101 | ||
| 90 | template <typename T> | 102 | template <typename T, typename... Args> |
| 91 | std::shared_ptr<T> GetInterface() const { | 103 | std::shared_ptr<T> GetInterface(Args&&... args) const { |
| 92 | static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, | 104 | static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, |
| 93 | "Not a base of ServiceFrameworkBase"); | 105 | "Not a base of ServiceFrameworkBase"); |
| 94 | 106 | ||
| 95 | return std::make_shared<T>(); | 107 | return std::make_shared<T>(std::forward<Args>(args)...); |
| 96 | } | 108 | } |
| 97 | }; | 109 | }; |
| 98 | 110 | ||
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 40838a225..71c7587db 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -27,42 +27,14 @@ | |||
| 27 | 27 | ||
| 28 | namespace Service::NS { | 28 | namespace Service::NS { |
| 29 | 29 | ||
| 30 | enum class FontArchives : u64 { | ||
| 31 | Extension = 0x0100000000000810, | ||
| 32 | Standard = 0x0100000000000811, | ||
| 33 | Korean = 0x0100000000000812, | ||
| 34 | ChineseTraditional = 0x0100000000000813, | ||
| 35 | ChineseSimple = 0x0100000000000814, | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct FontRegion { | 30 | struct FontRegion { |
| 39 | u32 offset; | 31 | u32 offset; |
| 40 | u32 size; | 32 | u32 size; |
| 41 | }; | 33 | }; |
| 42 | 34 | ||
| 43 | constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ | ||
| 44 | std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), | ||
| 45 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), | ||
| 46 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), | ||
| 47 | std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), | ||
| 48 | std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), | ||
| 49 | std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), | ||
| 50 | std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), | ||
| 51 | }; | ||
| 52 | |||
| 53 | constexpr std::array<const char*, 7> SHARED_FONTS_TTF{ | ||
| 54 | "FontStandard.ttf", | ||
| 55 | "FontChineseSimplified.ttf", | ||
| 56 | "FontExtendedChineseSimplified.ttf", | ||
| 57 | "FontChineseTraditional.ttf", | ||
| 58 | "FontKorean.ttf", | ||
| 59 | "FontNintendoExtended.ttf", | ||
| 60 | "FontNintendoExtended2.ttf", | ||
| 61 | }; | ||
| 62 | |||
| 63 | // The below data is specific to shared font data dumped from Switch on f/w 2.2 | 35 | // The below data is specific to shared font data dumped from Switch on f/w 2.2 |
| 64 | // Virtual address and offsets/sizes likely will vary by dump | 36 | // Virtual address and offsets/sizes likely will vary by dump |
| 65 | constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; | 37 | [[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; |
| 66 | constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be | 38 | constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be |
| 67 | constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be | 39 | constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be |
| 68 | constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; | 40 | constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; |
| @@ -90,6 +62,18 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem | |||
| 90 | offset += transformed_font.size() * sizeof(u32); | 62 | offset += transformed_font.size() * sizeof(u32); |
| 91 | } | 63 | } |
| 92 | 64 | ||
| 65 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { | ||
| 66 | ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); | ||
| 67 | |||
| 68 | const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor | ||
| 69 | std::vector<u32> transformed_font(input.size()); | ||
| 70 | // TODO(ogniK): Figure out a better way to do this | ||
| 71 | std::transform(input.begin(), input.end(), transformed_font.begin(), | ||
| 72 | [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); | ||
| 73 | transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size | ||
| 74 | std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32)); | ||
| 75 | } | ||
| 76 | |||
| 93 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, | 77 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, |
| 94 | std::size_t& offset) { | 78 | std::size_t& offset) { |
| 95 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, | 79 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, |
| @@ -151,8 +135,8 @@ struct PL_U::Impl { | |||
| 151 | std::vector<FontRegion> shared_font_regions; | 135 | std::vector<FontRegion> shared_font_regions; |
| 152 | }; | 136 | }; |
| 153 | 137 | ||
| 154 | PL_U::PL_U(Core::System& system) | 138 | PL_U::PL_U(Core::System& system_) |
| 155 | : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) { | 139 | : ServiceFramework{system_, "pl:u"}, impl{std::make_unique<Impl>()} { |
| 156 | // clang-format off | 140 | // clang-format off |
| 157 | static const FunctionInfo functions[] = { | 141 | static const FunctionInfo functions[] = { |
| 158 | {0, &PL_U::RequestLoad, "RequestLoad"}, | 142 | {0, &PL_U::RequestLoad, "RequestLoad"}, |
| @@ -192,21 +176,18 @@ PL_U::PL_U(Core::System& system) | |||
| 192 | } | 176 | } |
| 193 | 177 | ||
| 194 | if (!romfs) { | 178 | if (!romfs) { |
| 195 | LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", | 179 | LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first); |
| 196 | static_cast<u64>(font.first)); | ||
| 197 | continue; | 180 | continue; |
| 198 | } | 181 | } |
| 199 | 182 | ||
| 200 | const auto extracted_romfs = FileSys::ExtractRomFS(romfs); | 183 | const auto extracted_romfs = FileSys::ExtractRomFS(romfs); |
| 201 | if (!extracted_romfs) { | 184 | if (!extracted_romfs) { |
| 202 | LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", | 185 | LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first); |
| 203 | static_cast<u64>(font.first)); | ||
| 204 | continue; | 186 | continue; |
| 205 | } | 187 | } |
| 206 | const auto font_fp = extracted_romfs->GetFile(font.second); | 188 | const auto font_fp = extracted_romfs->GetFile(font.second); |
| 207 | if (!font_fp) { | 189 | if (!font_fp) { |
| 208 | LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", | 190 | LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second); |
| 209 | static_cast<u64>(font.first), font.second); | ||
| 210 | continue; | 191 | continue; |
| 211 | } | 192 | } |
| 212 | std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32)); | 193 | std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32)); |
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index 27161bd7a..f920c7f69 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h | |||
| @@ -16,11 +16,30 @@ class FileSystemController; | |||
| 16 | 16 | ||
| 17 | namespace NS { | 17 | namespace NS { |
| 18 | 18 | ||
| 19 | enum class FontArchives : u64 { | ||
| 20 | Extension = 0x0100000000000810, | ||
| 21 | Standard = 0x0100000000000811, | ||
| 22 | Korean = 0x0100000000000812, | ||
| 23 | ChineseTraditional = 0x0100000000000813, | ||
| 24 | ChineseSimple = 0x0100000000000814, | ||
| 25 | }; | ||
| 26 | |||
| 27 | constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ | ||
| 28 | std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), | ||
| 29 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), | ||
| 30 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), | ||
| 31 | std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), | ||
| 32 | std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), | ||
| 33 | std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), | ||
| 34 | std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), | ||
| 35 | }; | ||
| 36 | |||
| 37 | void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output); | ||
| 19 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); | 38 | void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); |
| 20 | 39 | ||
| 21 | class PL_U final : public ServiceFramework<PL_U> { | 40 | class PL_U final : public ServiceFramework<PL_U> { |
| 22 | public: | 41 | public: |
| 23 | explicit PL_U(Core::System& system); | 42 | explicit PL_U(Core::System& system_); |
| 24 | ~PL_U() override; | 43 | ~PL_U() override; |
| 25 | 44 | ||
| 26 | private: | 45 | private: |
| @@ -33,7 +52,6 @@ private: | |||
| 33 | 52 | ||
| 34 | struct Impl; | 53 | struct Impl; |
| 35 | std::unique_ptr<Impl> impl; | 54 | std::unique_ptr<Impl> impl; |
| 36 | Core::System& system; | ||
| 37 | }; | 55 | }; |
| 38 | 56 | ||
| 39 | } // namespace NS | 57 | } // namespace NS |
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 0240d6643..5681599ba 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -24,25 +24,37 @@ public: | |||
| 24 | explicit nvdevice(Core::System& system) : system{system} {} | 24 | explicit nvdevice(Core::System& system) : system{system} {} |
| 25 | virtual ~nvdevice() = default; | 25 | virtual ~nvdevice() = default; |
| 26 | 26 | ||
| 27 | union Ioctl { | 27 | /** |
| 28 | u32_le raw; | 28 | * Handles an ioctl1 request. |
| 29 | BitField<0, 8, u32> cmd; | 29 | * @param command The ioctl command id. |
| 30 | BitField<8, 8, u32> group; | 30 | * @param input A buffer containing the input data for the ioctl. |
| 31 | BitField<16, 14, u32> length; | 31 | * @param output A buffer where the output data will be written to. |
| 32 | BitField<30, 1, u32> is_in; | 32 | * @returns The result code of the ioctl. |
| 33 | BitField<31, 1, u32> is_out; | 33 | */ |
| 34 | }; | 34 | virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 35 | std::vector<u8>& output) = 0; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Handles an ioctl2 request. | ||
| 39 | * @param command The ioctl command id. | ||
| 40 | * @param input A buffer containing the input data for the ioctl. | ||
| 41 | * @param inline_input A buffer containing the input data for the ioctl which has been inlined. | ||
| 42 | * @param output A buffer where the output data will be written to. | ||
| 43 | * @returns The result code of the ioctl. | ||
| 44 | */ | ||
| 45 | virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 46 | const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; | ||
| 35 | 47 | ||
| 36 | /** | 48 | /** |
| 37 | * Handles an ioctl request. | 49 | * Handles an ioctl3 request. |
| 38 | * @param command The ioctl command id. | 50 | * @param command The ioctl command id. |
| 39 | * @param input A buffer containing the input data for the ioctl. | 51 | * @param input A buffer containing the input data for the ioctl. |
| 40 | * @param output A buffer where the output data will be written to. | 52 | * @param output A buffer where the output data will be written to. |
| 53 | * @param inline_output A buffer where the inlined output data will be written to. | ||
| 41 | * @returns The result code of the ioctl. | 54 | * @returns The result code of the ioctl. |
| 42 | */ | 55 | */ |
| 43 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 56 | virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 44 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 57 | std::vector<u8>& inline_output) = 0; |
| 45 | IoctlVersion version) = 0; | ||
| 46 | 58 | ||
| 47 | protected: | 59 | protected: |
| 48 | Core::System& system; | 60 | Core::System& system; |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 3f7b8e670..ce615c758 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; | 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; |
| 20 | 20 | ||
| 21 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | std::vector<u8>& output) { |
| 23 | IoctlVersion version) { | 23 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 24 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 24 | return NvResult::NotImplemented; |
| 25 | return 0; | 25 | } |
| 26 | |||
| 27 | NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 28 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 29 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 30 | return NvResult::NotImplemented; | ||
| 31 | } | ||
| 32 | |||
| 33 | NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 34 | std::vector<u8>& inline_output) { | ||
| 35 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 36 | return NvResult::NotImplemented; | ||
| 26 | } | 37 | } |
| 27 | 38 | ||
| 28 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, | 39 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6fcdeee84..55a33b7e4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -20,9 +20,11 @@ public: | |||
| 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvdisp_disp0() override; | 21 | ~nvdisp_disp0() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 25 | IoctlVersion version) override; | 25 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 26 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 27 | std::vector<u8>& inline_output) override; | ||
| 26 | 28 | ||
| 27 | /// Performs a screen flip, drawing the buffer pointed to by the handle. | 29 | /// Performs a screen flip, drawing the buffer pointed to by the handle. |
| 28 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, | 30 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 39bd2a45b..6b062e10e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -17,57 +17,77 @@ | |||
| 17 | 17 | ||
| 18 | namespace Service::Nvidia::Devices { | 18 | namespace Service::Nvidia::Devices { |
| 19 | 19 | ||
| 20 | namespace NvErrCodes { | ||
| 21 | constexpr u32 Success{}; | ||
| 22 | constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 23 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 24 | } // namespace NvErrCodes | ||
| 25 | |||
| 26 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 20 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 27 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 21 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 28 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 22 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 29 | 23 | ||
| 30 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 24 | NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 31 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 25 | std::vector<u8>& output) { |
| 32 | IoctlVersion version) { | 26 | switch (command.group) { |
| 33 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 27 | case 'A': |
| 34 | command.raw, input.size(), output.size()); | 28 | switch (command.cmd) { |
| 35 | 29 | case 0x1: | |
| 36 | switch (static_cast<IoctlCommand>(command.raw)) { | 30 | return BindChannel(input, output); |
| 37 | case IoctlCommand::IocInitalizeExCommand: | 31 | case 0x2: |
| 38 | return InitalizeEx(input, output); | 32 | return AllocateSpace(input, output); |
| 39 | case IoctlCommand::IocAllocateSpaceCommand: | 33 | case 0x3: |
| 40 | return AllocateSpace(input, output); | 34 | return FreeSpace(input, output); |
| 41 | case IoctlCommand::IocMapBufferExCommand: | 35 | case 0x5: |
| 42 | return MapBufferEx(input, output); | 36 | return UnmapBuffer(input, output); |
| 43 | case IoctlCommand::IocBindChannelCommand: | 37 | case 0x6: |
| 44 | return BindChannel(input, output); | 38 | return MapBufferEx(input, output); |
| 45 | case IoctlCommand::IocGetVaRegionsCommand: | 39 | case 0x8: |
| 46 | return GetVARegions(input, output); | 40 | return GetVARegions(input, output); |
| 47 | case IoctlCommand::IocUnmapBufferCommand: | 41 | case 0x9: |
| 48 | return UnmapBuffer(input, output); | 42 | return InitalizeEx(input, output); |
| 43 | case 0x14: | ||
| 44 | return Remap(input, output); | ||
| 45 | default: | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | break; | ||
| 49 | default: | 49 | default: |
| 50 | break; | 50 | break; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { | 53 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 54 | return Remap(input, output); | 54 | return NvResult::NotImplemented; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | UNIMPLEMENTED_MSG("Unimplemented ioctl command"); | 57 | NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 58 | return 0; | 58 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 60 | return NvResult::NotImplemented; | ||
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { | 63 | NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 64 | std::vector<u8>& inline_output) { | ||
| 65 | switch (command.group) { | ||
| 66 | case 'A': | ||
| 67 | switch (command.cmd) { | ||
| 68 | case 0x8: | ||
| 69 | return GetVARegions(input, output, inline_output); | ||
| 70 | default: | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 78 | return NvResult::NotImplemented; | ||
| 79 | } | ||
| 80 | |||
| 81 | NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 62 | IoctlInitalizeEx params{}; | 82 | IoctlInitalizeEx params{}; |
| 63 | std::memcpy(¶ms, input.data(), input.size()); | 83 | std::memcpy(¶ms, input.data(), input.size()); |
| 64 | 84 | ||
| 65 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 85 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 66 | 86 | ||
| 67 | return 0; | 87 | return NvResult::Success; |
| 68 | } | 88 | } |
| 69 | 89 | ||
| 70 | u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 90 | NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 71 | IoctlAllocSpace params{}; | 91 | IoctlAllocSpace params{}; |
| 72 | std::memcpy(¶ms, input.data(), input.size()); | 92 | std::memcpy(¶ms, input.data(), input.size()); |
| 73 | 93 | ||
| @@ -81,22 +101,36 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& | |||
| 81 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); | 101 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); |
| 82 | } | 102 | } |
| 83 | 103 | ||
| 84 | auto result{NvErrCodes::Success}; | 104 | auto result = NvResult::Success; |
| 85 | if (!params.offset) { | 105 | if (!params.offset) { |
| 86 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); | 106 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); |
| 87 | result = NvErrCodes::OutOfMemory; | 107 | result = NvResult::InsufficientMemory; |
| 88 | } | 108 | } |
| 89 | 109 | ||
| 90 | std::memcpy(output.data(), ¶ms, output.size()); | 110 | std::memcpy(output.data(), ¶ms, output.size()); |
| 91 | return result; | 111 | return result; |
| 92 | } | 112 | } |
| 93 | 113 | ||
| 94 | u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { | 114 | NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 115 | IoctlFreeSpace params{}; | ||
| 116 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 117 | |||
| 118 | LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, | ||
| 119 | params.pages, params.page_size); | ||
| 120 | |||
| 121 | system.GPU().MemoryManager().Unmap(params.offset, | ||
| 122 | static_cast<std::size_t>(params.pages) * params.page_size); | ||
| 123 | |||
| 124 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 125 | return NvResult::Success; | ||
| 126 | } | ||
| 127 | |||
| 128 | NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 95 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); | 129 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); |
| 96 | 130 | ||
| 97 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); | 131 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); |
| 98 | 132 | ||
| 99 | auto result{NvErrCodes::Success}; | 133 | auto result = NvResult::Success; |
| 100 | std::vector<IoctlRemapEntry> entries(num_entries); | 134 | std::vector<IoctlRemapEntry> entries(num_entries); |
| 101 | std::memcpy(entries.data(), input.data(), input.size()); | 135 | std::memcpy(entries.data(), input.data(), input.size()); |
| 102 | 136 | ||
| @@ -107,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 107 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; | 141 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; |
| 108 | if (!object) { | 142 | if (!object) { |
| 109 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); | 143 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); |
| 110 | result = NvErrCodes::InvalidInput; | 144 | result = NvResult::InvalidState; |
| 111 | break; | 145 | break; |
| 112 | } | 146 | } |
| 113 | 147 | ||
| @@ -118,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 118 | 152 | ||
| 119 | if (!addr) { | 153 | if (!addr) { |
| 120 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); | 154 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); |
| 121 | result = NvErrCodes::InvalidInput; | 155 | result = NvResult::InvalidState; |
| 122 | break; | 156 | break; |
| 123 | } | 157 | } |
| 124 | } | 158 | } |
| @@ -127,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 127 | return result; | 161 | return result; |
| 128 | } | 162 | } |
| 129 | 163 | ||
| 130 | u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 131 | IoctlMapBufferEx params{}; | 165 | IoctlMapBufferEx params{}; |
| 132 | std::memcpy(¶ms, input.data(), input.size()); | 166 | std::memcpy(¶ms, input.data(), input.size()); |
| 133 | 167 | ||
| @@ -141,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 141 | if (!object) { | 175 | if (!object) { |
| 142 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); | 176 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); |
| 143 | std::memcpy(output.data(), ¶ms, output.size()); | 177 | std::memcpy(output.data(), ¶ms, output.size()); |
| 144 | return NvErrCodes::InvalidInput; | 178 | return NvResult::InvalidState; |
| 145 | } | 179 | } |
| 146 | 180 | ||
| 147 | // The real nvservices doesn't make a distinction between handles and ids, and | 181 | // The real nvservices doesn't make a distinction between handles and ids, and |
| @@ -168,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 168 | params.mapping_size, params.offset); | 202 | params.mapping_size, params.offset); |
| 169 | 203 | ||
| 170 | std::memcpy(output.data(), ¶ms, output.size()); | 204 | std::memcpy(output.data(), ¶ms, output.size()); |
| 171 | return NvErrCodes::InvalidInput; | 205 | return NvResult::InvalidState; |
| 172 | } | 206 | } |
| 173 | 207 | ||
| 174 | std::memcpy(output.data(), ¶ms, output.size()); | 208 | std::memcpy(output.data(), ¶ms, output.size()); |
| 175 | return NvErrCodes::Success; | 209 | return NvResult::Success; |
| 176 | } else { | 210 | } else { |
| 177 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); | 211 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); |
| 178 | 212 | ||
| 179 | std::memcpy(output.data(), ¶ms, output.size()); | 213 | std::memcpy(output.data(), ¶ms, output.size()); |
| 180 | return NvErrCodes::InvalidInput; | 214 | return NvResult::InvalidState; |
| 181 | } | 215 | } |
| 182 | } | 216 | } |
| 183 | 217 | ||
| @@ -197,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 197 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); | 231 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); |
| 198 | } | 232 | } |
| 199 | 233 | ||
| 200 | auto result{NvErrCodes::Success}; | 234 | auto result = NvResult::Success; |
| 201 | if (!params.offset) { | 235 | if (!params.offset) { |
| 202 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); | 236 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); |
| 203 | result = NvErrCodes::InvalidInput; | 237 | result = NvResult::InvalidState; |
| 204 | } else { | 238 | } else { |
| 205 | AddBufferMap(params.offset, size, physical_address, is_alloc); | 239 | AddBufferMap(params.offset, size, physical_address, is_alloc); |
| 206 | } | 240 | } |
| @@ -209,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 209 | return result; | 243 | return result; |
| 210 | } | 244 | } |
| 211 | 245 | ||
| 212 | u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 246 | NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 213 | IoctlUnmapBuffer params{}; | 247 | IoctlUnmapBuffer params{}; |
| 214 | std::memcpy(¶ms, input.data(), input.size()); | 248 | std::memcpy(¶ms, input.data(), input.size()); |
| 215 | 249 | ||
| @@ -222,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 222 | } | 256 | } |
| 223 | 257 | ||
| 224 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 225 | return NvErrCodes::Success; | 259 | return NvResult::Success; |
| 226 | } | 260 | } |
| 227 | 261 | ||
| 228 | u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { |
| 229 | IoctlBindChannel params{}; | 263 | IoctlBindChannel params{}; |
| 230 | std::memcpy(¶ms, input.data(), input.size()); | 264 | std::memcpy(¶ms, input.data(), input.size()); |
| 231 | 265 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd); | |
| 232 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | ||
| 233 | 266 | ||
| 234 | channel = params.fd; | 267 | channel = params.fd; |
| 235 | return 0; | 268 | return NvResult::Success; |
| 269 | } | ||
| 270 | |||
| 271 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 272 | IoctlGetVaRegions params{}; | ||
| 273 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 274 | |||
| 275 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, | ||
| 276 | params.buf_size); | ||
| 277 | |||
| 278 | params.buf_size = 0x30; | ||
| 279 | params.regions[0].offset = 0x04000000; | ||
| 280 | params.regions[0].page_size = 0x1000; | ||
| 281 | params.regions[0].pages = 0x3fbfff; | ||
| 282 | |||
| 283 | params.regions[1].offset = 0x04000000; | ||
| 284 | params.regions[1].page_size = 0x10000; | ||
| 285 | params.regions[1].pages = 0x1bffff; | ||
| 286 | |||
| 287 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | ||
| 288 | |||
| 289 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 290 | return NvResult::Success; | ||
| 236 | } | 291 | } |
| 237 | 292 | ||
| 238 | u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 294 | std::vector<u8>& inline_output) { | ||
| 239 | IoctlGetVaRegions params{}; | 295 | IoctlGetVaRegions params{}; |
| 240 | std::memcpy(¶ms, input.data(), input.size()); | 296 | std::memcpy(¶ms, input.data(), input.size()); |
| 241 | 297 | ||
| @@ -254,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o | |||
| 254 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | 310 | // TODO(ogniK): This probably can stay stubbed but should add support way way later |
| 255 | 311 | ||
| 256 | std::memcpy(output.data(), ¶ms, output.size()); | 312 | std::memcpy(output.data(), ¶ms, output.size()); |
| 257 | return 0; | 313 | std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size()); |
| 314 | return NvResult::Success; | ||
| 258 | } | 315 | } |
| 259 | 316 | ||
| 260 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { | 317 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 9a0cdff0c..08035fa0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -30,9 +30,11 @@ public: | |||
| 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 31 | ~nvhost_as_gpu() override; | 31 | ~nvhost_as_gpu() override; |
| 32 | 32 | ||
| 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 33 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 34 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 34 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 35 | IoctlVersion version) override; | 35 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 36 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 37 | std::vector<u8>& inline_output) override; | ||
| 36 | 38 | ||
| 37 | private: | 39 | private: |
| 38 | class BufferMap final { | 40 | class BufferMap final { |
| @@ -74,31 +76,21 @@ private: | |||
| 74 | bool is_allocated{}; | 76 | bool is_allocated{}; |
| 75 | }; | 77 | }; |
| 76 | 78 | ||
| 77 | enum class IoctlCommand : u32_le { | ||
| 78 | IocInitalizeExCommand = 0x40284109, | ||
| 79 | IocAllocateSpaceCommand = 0xC0184102, | ||
| 80 | IocRemapCommand = 0x00000014, | ||
| 81 | IocMapBufferExCommand = 0xC0284106, | ||
| 82 | IocBindChannelCommand = 0x40044101, | ||
| 83 | IocGetVaRegionsCommand = 0xC0404108, | ||
| 84 | IocUnmapBufferCommand = 0xC0084105, | ||
| 85 | }; | ||
| 86 | |||
| 87 | struct IoctlInitalizeEx { | 79 | struct IoctlInitalizeEx { |
| 88 | u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default | 80 | u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default |
| 89 | s32_le as_fd; // ignored; passes 0 | 81 | s32_le as_fd{}; // ignored; passes 0 |
| 90 | u32_le flags; // passes 0 | 82 | u32_le flags{}; // passes 0 |
| 91 | u32_le reserved; // ignored; passes 0 | 83 | u32_le reserved{}; // ignored; passes 0 |
| 92 | u64_le unk0; | 84 | u64_le unk0{}; |
| 93 | u64_le unk1; | 85 | u64_le unk1{}; |
| 94 | u64_le unk2; | 86 | u64_le unk2{}; |
| 95 | }; | 87 | }; |
| 96 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); | 88 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); |
| 97 | 89 | ||
| 98 | struct IoctlAllocSpace { | 90 | struct IoctlAllocSpace { |
| 99 | u32_le pages; | 91 | u32_le pages{}; |
| 100 | u32_le page_size; | 92 | u32_le page_size{}; |
| 101 | AddressSpaceFlags flags; | 93 | AddressSpaceFlags flags{}; |
| 102 | INSERT_PADDING_WORDS(1); | 94 | INSERT_PADDING_WORDS(1); |
| 103 | union { | 95 | union { |
| 104 | u64_le offset; | 96 | u64_le offset; |
| @@ -107,63 +99,74 @@ private: | |||
| 107 | }; | 99 | }; |
| 108 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); | 100 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); |
| 109 | 101 | ||
| 102 | struct IoctlFreeSpace { | ||
| 103 | u64_le offset{}; | ||
| 104 | u32_le pages{}; | ||
| 105 | u32_le page_size{}; | ||
| 106 | }; | ||
| 107 | static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); | ||
| 108 | |||
| 110 | struct IoctlRemapEntry { | 109 | struct IoctlRemapEntry { |
| 111 | u16_le flags; | 110 | u16_le flags{}; |
| 112 | u16_le kind; | 111 | u16_le kind{}; |
| 113 | u32_le nvmap_handle; | 112 | u32_le nvmap_handle{}; |
| 114 | u32_le map_offset; | 113 | u32_le map_offset{}; |
| 115 | u32_le offset; | 114 | u32_le offset{}; |
| 116 | u32_le pages; | 115 | u32_le pages{}; |
| 117 | }; | 116 | }; |
| 118 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); | 117 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); |
| 119 | 118 | ||
| 120 | struct IoctlMapBufferEx { | 119 | struct IoctlMapBufferEx { |
| 121 | AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable | 120 | AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable |
| 122 | u32_le kind; // -1 is default | 121 | u32_le kind{}; // -1 is default |
| 123 | u32_le nvmap_handle; | 122 | u32_le nvmap_handle{}; |
| 124 | u32_le page_size; // 0 means don't care | 123 | u32_le page_size{}; // 0 means don't care |
| 125 | s64_le buffer_offset; | 124 | s64_le buffer_offset{}; |
| 126 | u64_le mapping_size; | 125 | u64_le mapping_size{}; |
| 127 | s64_le offset; | 126 | s64_le offset{}; |
| 128 | }; | 127 | }; |
| 129 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); | 128 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); |
| 130 | 129 | ||
| 131 | struct IoctlUnmapBuffer { | 130 | struct IoctlUnmapBuffer { |
| 132 | s64_le offset; | 131 | s64_le offset{}; |
| 133 | }; | 132 | }; |
| 134 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); | 133 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); |
| 135 | 134 | ||
| 136 | struct IoctlBindChannel { | 135 | struct IoctlBindChannel { |
| 137 | u32_le fd; | 136 | s32_le fd{}; |
| 138 | }; | 137 | }; |
| 139 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); | 138 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); |
| 140 | 139 | ||
| 141 | struct IoctlVaRegion { | 140 | struct IoctlVaRegion { |
| 142 | u64_le offset; | 141 | u64_le offset{}; |
| 143 | u32_le page_size; | 142 | u32_le page_size{}; |
| 144 | INSERT_PADDING_WORDS(1); | 143 | INSERT_PADDING_WORDS(1); |
| 145 | u64_le pages; | 144 | u64_le pages{}; |
| 146 | }; | 145 | }; |
| 147 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); | 146 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); |
| 148 | 147 | ||
| 149 | struct IoctlGetVaRegions { | 148 | struct IoctlGetVaRegions { |
| 150 | u64_le buf_addr; // (contained output user ptr on linux, ignored) | 149 | u64_le buf_addr{}; // (contained output user ptr on linux, ignored) |
| 151 | u32_le buf_size; // forced to 2*sizeof(struct va_region) | 150 | u32_le buf_size{}; // forced to 2*sizeof(struct va_region) |
| 152 | u32_le reserved; | 151 | u32_le reserved{}; |
| 153 | IoctlVaRegion regions[2]; | 152 | IoctlVaRegion regions[2]{}; |
| 154 | }; | 153 | }; |
| 155 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, | 154 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, |
| 156 | "IoctlGetVaRegions is incorrect size"); | 155 | "IoctlGetVaRegions is incorrect size"); |
| 157 | 156 | ||
| 158 | u32 channel{}; | 157 | s32 channel{}; |
| 158 | |||
| 159 | NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 160 | NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 161 | NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 162 | NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 163 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 164 | NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 165 | NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 159 | 166 | ||
| 160 | u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | 167 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); |
| 161 | u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | 168 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 162 | u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); | 169 | std::vector<u8>& inline_output); |
| 163 | u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 164 | u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 165 | u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 166 | u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 167 | 170 | ||
| 168 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | 171 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; |
| 169 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | 172 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index b27ee0502..fea3b7b9f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -15,45 +15,59 @@ | |||
| 15 | 15 | ||
| 16 | namespace Service::Nvidia::Devices { | 16 | namespace Service::Nvidia::Devices { |
| 17 | 17 | ||
| 18 | nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) | 18 | nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, |
| 19 | : nvdevice(system), events_interface{events_interface} {} | 19 | SyncpointManager& syncpoint_manager) |
| 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} | ||
| 20 | nvhost_ctrl::~nvhost_ctrl() = default; | 21 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 21 | 22 | ||
| 22 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 23 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | switch (command.group) { |
| 24 | IoctlVersion version) { | 25 | case 0x0: |
| 25 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 26 | switch (command.cmd) { |
| 26 | command.raw, input.size(), output.size()); | 27 | case 0x1b: |
| 27 | 28 | return NvOsGetConfigU32(input, output); | |
| 28 | switch (static_cast<IoctlCommand>(command.raw)) { | 29 | case 0x1c: |
| 29 | case IoctlCommand::IocGetConfigCommand: | 30 | return IocCtrlClearEventWait(input, output); |
| 30 | return NvOsGetConfigU32(input, output); | 31 | case 0x1d: |
| 31 | case IoctlCommand::IocCtrlEventWaitCommand: | 32 | return IocCtrlEventWait(input, output, false); |
| 32 | return IocCtrlEventWait(input, output, false, ctrl); | 33 | case 0x1e: |
| 33 | case IoctlCommand::IocCtrlEventWaitAsyncCommand: | 34 | return IocCtrlEventWait(input, output, true); |
| 34 | return IocCtrlEventWait(input, output, true, ctrl); | 35 | case 0x1f: |
| 35 | case IoctlCommand::IocCtrlEventRegisterCommand: | 36 | return IocCtrlEventRegister(input, output); |
| 36 | return IocCtrlEventRegister(input, output); | 37 | case 0x20: |
| 37 | case IoctlCommand::IocCtrlEventUnregisterCommand: | 38 | return IocCtrlEventUnregister(input, output); |
| 38 | return IocCtrlEventUnregister(input, output); | 39 | } |
| 39 | case IoctlCommand::IocCtrlEventSignalCommand: | 40 | break; |
| 40 | return IocCtrlEventSignal(input, output); | ||
| 41 | default: | 41 | default: |
| 42 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 42 | break; |
| 43 | return 0; | ||
| 44 | } | 43 | } |
| 44 | |||
| 45 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 46 | return NvResult::NotImplemented; | ||
| 47 | } | ||
| 48 | |||
| 49 | NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 50 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 51 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 52 | return NvResult::NotImplemented; | ||
| 53 | } | ||
| 54 | |||
| 55 | NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 56 | std::vector<u8>& inline_outpu) { | ||
| 57 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 58 | return NvResult::NotImplemented; | ||
| 45 | } | 59 | } |
| 46 | 60 | ||
| 47 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { | 61 | NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { |
| 48 | IocGetConfigParams params{}; | 62 | IocGetConfigParams params{}; |
| 49 | std::memcpy(¶ms, input.data(), sizeof(params)); | 63 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 50 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), | 64 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), |
| 51 | params.param_str.data()); | 65 | params.param_str.data()); |
| 52 | return 0x30006; // Returns error on production mode | 66 | return NvResult::ConfigVarNotFound; // Returns error on production mode |
| 53 | } | 67 | } |
| 54 | 68 | ||
| 55 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, | 69 | NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, |
| 56 | bool is_async, IoctlCtrl& ctrl) { | 70 | bool is_async) { |
| 57 | IocCtrlEventWaitParams params{}; | 71 | IocCtrlEventWaitParams params{}; |
| 58 | std::memcpy(¶ms, input.data(), sizeof(params)); | 72 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 59 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", | 73 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", |
| @@ -70,19 +84,33 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 70 | return NvResult::BadParameter; | 84 | return NvResult::BadParameter; |
| 71 | } | 85 | } |
| 72 | 86 | ||
| 87 | if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | ||
| 88 | params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); | ||
| 89 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 90 | return NvResult::Success; | ||
| 91 | } | ||
| 92 | |||
| 93 | if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id); | ||
| 94 | syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { | ||
| 95 | params.value = new_value; | ||
| 96 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 97 | return NvResult::Success; | ||
| 98 | } | ||
| 99 | |||
| 73 | auto event = events_interface.events[event_id]; | 100 | auto event = events_interface.events[event_id]; |
| 74 | auto& gpu = system.GPU(); | 101 | auto& gpu = system.GPU(); |
| 102 | |||
| 75 | // This is mostly to take into account unimplemented features. As synced | 103 | // This is mostly to take into account unimplemented features. As synced |
| 76 | // gpu is always synced. | 104 | // gpu is always synced. |
| 77 | if (!gpu.IsAsync()) { | 105 | if (!gpu.IsAsync()) { |
| 78 | event.writable->Signal(); | 106 | event.event.writable->Signal(); |
| 79 | return NvResult::Success; | 107 | return NvResult::Success; |
| 80 | } | 108 | } |
| 81 | auto lock = gpu.LockSync(); | 109 | auto lock = gpu.LockSync(); |
| 82 | const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); | 110 | const u32 current_syncpoint_value = event.fence.value; |
| 83 | const s32 diff = current_syncpoint_value - params.threshold; | 111 | const s32 diff = current_syncpoint_value - params.threshold; |
| 84 | if (diff >= 0) { | 112 | if (diff >= 0) { |
| 85 | event.writable->Signal(); | 113 | event.event.writable->Signal(); |
| 86 | params.value = current_syncpoint_value; | 114 | params.value = current_syncpoint_value; |
| 87 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 115 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 88 | return NvResult::Success; | 116 | return NvResult::Success; |
| @@ -109,14 +137,8 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 109 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; | 137 | params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; |
| 110 | } | 138 | } |
| 111 | params.value |= event_id; | 139 | params.value |= event_id; |
| 112 | event.writable->Clear(); | 140 | event.event.writable->Clear(); |
| 113 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 141 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 114 | if (!is_async && ctrl.fresh_call) { | ||
| 115 | ctrl.must_delay = true; | ||
| 116 | ctrl.timeout = params.timeout; | ||
| 117 | ctrl.event_id = event_id; | ||
| 118 | return NvResult::Timeout; | ||
| 119 | } | ||
| 120 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 142 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 121 | return NvResult::Timeout; | 143 | return NvResult::Timeout; |
| 122 | } | 144 | } |
| @@ -124,7 +146,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 124 | return NvResult::BadParameter; | 146 | return NvResult::BadParameter; |
| 125 | } | 147 | } |
| 126 | 148 | ||
| 127 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { | 149 | NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { |
| 128 | IocCtrlEventRegisterParams params{}; | 150 | IocCtrlEventRegisterParams params{}; |
| 129 | std::memcpy(¶ms, input.data(), sizeof(params)); | 151 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 130 | const u32 event_id = params.user_event_id & 0x00FF; | 152 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -139,7 +161,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector< | |||
| 139 | return NvResult::Success; | 161 | return NvResult::Success; |
| 140 | } | 162 | } |
| 141 | 163 | ||
| 142 | u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, |
| 165 | std::vector<u8>& output) { | ||
| 143 | IocCtrlEventUnregisterParams params{}; | 166 | IocCtrlEventUnregisterParams params{}; |
| 144 | std::memcpy(¶ms, input.data(), sizeof(params)); | 167 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 145 | const u32 event_id = params.user_event_id & 0x00FF; | 168 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -154,24 +177,22 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto | |||
| 154 | return NvResult::Success; | 177 | return NvResult::Success; |
| 155 | } | 178 | } |
| 156 | 179 | ||
| 157 | u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output) { | 180 | NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { |
| 158 | IocCtrlEventSignalParams params{}; | 181 | IocCtrlEventSignalParams params{}; |
| 159 | std::memcpy(¶ms, input.data(), sizeof(params)); | 182 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 160 | // TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization | 183 | |
| 161 | // It is believed from RE to cancel the GPU Event. However, better research is required | 184 | u32 event_id = params.event_id & 0x00FF; |
| 162 | u32 event_id = params.user_event_id & 0x00FF; | 185 | LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id); |
| 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id); | 186 | |
| 164 | if (event_id >= MaxNvEvents) { | 187 | if (event_id >= MaxNvEvents) { |
| 165 | return NvResult::BadParameter; | 188 | return NvResult::BadParameter; |
| 166 | } | 189 | } |
| 167 | if (events_interface.status[event_id] == EventState::Waiting) { | 190 | if (events_interface.status[event_id] == EventState::Waiting) { |
| 168 | auto& gpu = system.GPU(); | 191 | events_interface.LiberateEvent(event_id); |
| 169 | if (gpu.CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], | ||
| 170 | events_interface.assigned_value[event_id])) { | ||
| 171 | events_interface.LiberateEvent(event_id); | ||
| 172 | events_interface.events[event_id].writable->Signal(); | ||
| 173 | } | ||
| 174 | } | 192 | } |
| 193 | |||
| 194 | syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); | ||
| 195 | |||
| 175 | return NvResult::Success; | 196 | return NvResult::Success; |
| 176 | } | 197 | } |
| 177 | 198 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 9898623de..c5aa1362a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -14,137 +14,120 @@ namespace Service::Nvidia::Devices { | |||
| 14 | 14 | ||
| 15 | class nvhost_ctrl final : public nvdevice { | 15 | class nvhost_ctrl final : public nvdevice { |
| 16 | public: | 16 | public: |
| 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); | 17 | explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface, |
| 18 | SyncpointManager& syncpoint_manager); | ||
| 18 | ~nvhost_ctrl() override; | 19 | ~nvhost_ctrl() override; |
| 19 | 20 | ||
| 20 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 21 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 22 | IoctlVersion version) override; | 23 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 24 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 25 | std::vector<u8>& inline_output) override; | ||
| 23 | 26 | ||
| 24 | private: | 27 | private: |
| 25 | enum class IoctlCommand : u32_le { | ||
| 26 | IocSyncptReadCommand = 0xC0080014, | ||
| 27 | IocSyncptIncrCommand = 0x40040015, | ||
| 28 | IocSyncptWaitCommand = 0xC00C0016, | ||
| 29 | IocModuleMutexCommand = 0x40080017, | ||
| 30 | IocModuleRegRDWRCommand = 0xC0180018, | ||
| 31 | IocSyncptWaitexCommand = 0xC0100019, | ||
| 32 | IocSyncptReadMaxCommand = 0xC008001A, | ||
| 33 | IocGetConfigCommand = 0xC183001B, | ||
| 34 | IocCtrlEventSignalCommand = 0xC004001C, | ||
| 35 | IocCtrlEventWaitCommand = 0xC010001D, | ||
| 36 | IocCtrlEventWaitAsyncCommand = 0xC010001E, | ||
| 37 | IocCtrlEventRegisterCommand = 0xC004001F, | ||
| 38 | IocCtrlEventUnregisterCommand = 0xC0040020, | ||
| 39 | IocCtrlEventKillCommand = 0x40080021, | ||
| 40 | }; | ||
| 41 | struct IocSyncptReadParams { | 28 | struct IocSyncptReadParams { |
| 42 | u32_le id; | 29 | u32_le id{}; |
| 43 | u32_le value; | 30 | u32_le value{}; |
| 44 | }; | 31 | }; |
| 45 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); | 32 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); |
| 46 | 33 | ||
| 47 | struct IocSyncptIncrParams { | 34 | struct IocSyncptIncrParams { |
| 48 | u32_le id; | 35 | u32_le id{}; |
| 49 | }; | 36 | }; |
| 50 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); | 37 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); |
| 51 | 38 | ||
| 52 | struct IocSyncptWaitParams { | 39 | struct IocSyncptWaitParams { |
| 53 | u32_le id; | 40 | u32_le id{}; |
| 54 | u32_le thresh; | 41 | u32_le thresh{}; |
| 55 | s32_le timeout; | 42 | s32_le timeout{}; |
| 56 | }; | 43 | }; |
| 57 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); | 44 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); |
| 58 | 45 | ||
| 59 | struct IocModuleMutexParams { | 46 | struct IocModuleMutexParams { |
| 60 | u32_le id; | 47 | u32_le id{}; |
| 61 | u32_le lock; // (0 = unlock and 1 = lock) | 48 | u32_le lock{}; // (0 = unlock and 1 = lock) |
| 62 | }; | 49 | }; |
| 63 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); | 50 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); |
| 64 | 51 | ||
| 65 | struct IocModuleRegRDWRParams { | 52 | struct IocModuleRegRDWRParams { |
| 66 | u32_le id; | 53 | u32_le id{}; |
| 67 | u32_le num_offsets; | 54 | u32_le num_offsets{}; |
| 68 | u32_le block_size; | 55 | u32_le block_size{}; |
| 69 | u32_le offsets; | 56 | u32_le offsets{}; |
| 70 | u32_le values; | 57 | u32_le values{}; |
| 71 | u32_le write; | 58 | u32_le write{}; |
| 72 | }; | 59 | }; |
| 73 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); | 60 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); |
| 74 | 61 | ||
| 75 | struct IocSyncptWaitexParams { | 62 | struct IocSyncptWaitexParams { |
| 76 | u32_le id; | 63 | u32_le id{}; |
| 77 | u32_le thresh; | 64 | u32_le thresh{}; |
| 78 | s32_le timeout; | 65 | s32_le timeout{}; |
| 79 | u32_le value; | 66 | u32_le value{}; |
| 80 | }; | 67 | }; |
| 81 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); | 68 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); |
| 82 | 69 | ||
| 83 | struct IocSyncptReadMaxParams { | 70 | struct IocSyncptReadMaxParams { |
| 84 | u32_le id; | 71 | u32_le id{}; |
| 85 | u32_le value; | 72 | u32_le value{}; |
| 86 | }; | 73 | }; |
| 87 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); | 74 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); |
| 88 | 75 | ||
| 89 | struct IocGetConfigParams { | 76 | struct IocGetConfigParams { |
| 90 | std::array<char, 0x41> domain_str; | 77 | std::array<char, 0x41> domain_str{}; |
| 91 | std::array<char, 0x41> param_str; | 78 | std::array<char, 0x41> param_str{}; |
| 92 | std::array<char, 0x101> config_str; | 79 | std::array<char, 0x101> config_str{}; |
| 93 | }; | 80 | }; |
| 94 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); | 81 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); |
| 95 | 82 | ||
| 96 | struct IocCtrlEventSignalParams { | 83 | struct IocCtrlEventSignalParams { |
| 97 | u32_le user_event_id; | 84 | u32_le event_id{}; |
| 98 | }; | 85 | }; |
| 99 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, | 86 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, |
| 100 | "IocCtrlEventSignalParams is incorrect size"); | 87 | "IocCtrlEventSignalParams is incorrect size"); |
| 101 | 88 | ||
| 102 | struct IocCtrlEventWaitParams { | 89 | struct IocCtrlEventWaitParams { |
| 103 | u32_le syncpt_id; | 90 | u32_le syncpt_id{}; |
| 104 | u32_le threshold; | 91 | u32_le threshold{}; |
| 105 | s32_le timeout; | 92 | s32_le timeout{}; |
| 106 | u32_le value; | 93 | u32_le value{}; |
| 107 | }; | 94 | }; |
| 108 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); | 95 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); |
| 109 | 96 | ||
| 110 | struct IocCtrlEventWaitAsyncParams { | 97 | struct IocCtrlEventWaitAsyncParams { |
| 111 | u32_le syncpt_id; | 98 | u32_le syncpt_id{}; |
| 112 | u32_le threshold; | 99 | u32_le threshold{}; |
| 113 | u32_le timeout; | 100 | u32_le timeout{}; |
| 114 | u32_le value; | 101 | u32_le value{}; |
| 115 | }; | 102 | }; |
| 116 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, | 103 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, |
| 117 | "IocCtrlEventWaitAsyncParams is incorrect size"); | 104 | "IocCtrlEventWaitAsyncParams is incorrect size"); |
| 118 | 105 | ||
| 119 | struct IocCtrlEventRegisterParams { | 106 | struct IocCtrlEventRegisterParams { |
| 120 | u32_le user_event_id; | 107 | u32_le user_event_id{}; |
| 121 | }; | 108 | }; |
| 122 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, | 109 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, |
| 123 | "IocCtrlEventRegisterParams is incorrect size"); | 110 | "IocCtrlEventRegisterParams is incorrect size"); |
| 124 | 111 | ||
| 125 | struct IocCtrlEventUnregisterParams { | 112 | struct IocCtrlEventUnregisterParams { |
| 126 | u32_le user_event_id; | 113 | u32_le user_event_id{}; |
| 127 | }; | 114 | }; |
| 128 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, | 115 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, |
| 129 | "IocCtrlEventUnregisterParams is incorrect size"); | 116 | "IocCtrlEventUnregisterParams is incorrect size"); |
| 130 | 117 | ||
| 131 | struct IocCtrlEventKill { | 118 | struct IocCtrlEventKill { |
| 132 | u64_le user_events; | 119 | u64_le user_events{}; |
| 133 | }; | 120 | }; |
| 134 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); | 121 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); |
| 135 | 122 | ||
| 136 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); |
| 137 | 124 | NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); | |
| 138 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, | 125 | NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); |
| 139 | IoctlCtrl& ctrl); | 126 | NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); |
| 140 | 127 | NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | |
| 141 | u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 142 | |||
| 143 | u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 144 | |||
| 145 | u32 IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 146 | 128 | ||
| 147 | EventInterface& events_interface; | 129 | EventInterface& events_interface; |
| 130 | SyncpointManager& syncpoint_manager; | ||
| 148 | }; | 131 | }; |
| 149 | 132 | ||
| 150 | } // namespace Service::Nvidia::Devices | 133 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index fba89e7a6..0320d3ae2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices { | |||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} |
| 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, | 18 | NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 19 | const std::vector<u8>& input2, std::vector<u8>& output, | 19 | std::vector<u8>& output) { |
| 20 | std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { | 20 | switch (command.group) { |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | case 'G': |
| 22 | command.raw, input.size(), output.size()); | 22 | switch (command.cmd) { |
| 23 | 23 | case 0x1: | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | return ZCullGetCtxSize(input, output); |
| 25 | case IoctlCommand::IocGetCharacteristicsCommand: | 25 | case 0x2: |
| 26 | return GetCharacteristics(input, output, output2, version); | 26 | return ZCullGetInfo(input, output); |
| 27 | case IoctlCommand::IocGetTPCMasksCommand: | 27 | case 0x3: |
| 28 | return GetTPCMasks(input, output, output2, version); | 28 | return ZBCSetTable(input, output); |
| 29 | case IoctlCommand::IocGetActiveSlotMaskCommand: | 29 | case 0x4: |
| 30 | return GetActiveSlotMask(input, output); | 30 | return ZBCQueryTable(input, output); |
| 31 | case IoctlCommand::IocZcullGetCtxSizeCommand: | 31 | case 0x5: |
| 32 | return ZCullGetCtxSize(input, output); | 32 | return GetCharacteristics(input, output); |
| 33 | case IoctlCommand::IocZcullGetInfo: | 33 | case 0x6: |
| 34 | return ZCullGetInfo(input, output); | 34 | return GetTPCMasks(input, output); |
| 35 | case IoctlCommand::IocZbcSetTable: | 35 | case 0x7: |
| 36 | return ZBCSetTable(input, output); | 36 | return FlushL2(input, output); |
| 37 | case IoctlCommand::IocZbcQueryTable: | 37 | case 0x14: |
| 38 | return ZBCQueryTable(input, output); | 38 | return GetActiveSlotMask(input, output); |
| 39 | case IoctlCommand::IocFlushL2: | 39 | case 0x1c: |
| 40 | return FlushL2(input, output); | 40 | return GetGpuTime(input, output); |
| 41 | case IoctlCommand::IocGetGpuTime: | 41 | default: |
| 42 | return GetGpuTime(input, output); | 42 | break; |
| 43 | } | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, | ||
| 57 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 58 | switch (command.group) { | ||
| 59 | case 'G': | ||
| 60 | switch (command.cmd) { | ||
| 61 | case 0x5: | ||
| 62 | return GetCharacteristics(input, output, inline_output); | ||
| 63 | case 0x6: | ||
| 64 | return GetTPCMasks(input, output, inline_output); | ||
| 65 | default: | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | break; | ||
| 43 | default: | 69 | default: |
| 44 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 70 | break; |
| 45 | return 0; | ||
| 46 | } | 71 | } |
| 72 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 73 | return NvResult::NotImplemented; | ||
| 47 | } | 74 | } |
| 48 | 75 | ||
| 49 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 76 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, |
| 50 | std::vector<u8>& output2, IoctlVersion version) { | 77 | std::vector<u8>& output) { |
| 51 | LOG_DEBUG(Service_NVDRV, "called"); | 78 | LOG_DEBUG(Service_NVDRV, "called"); |
| 52 | IoctlCharacteristics params{}; | 79 | IoctlCharacteristics params{}; |
| 53 | std::memcpy(¶ms, input.data(), input.size()); | 80 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto | |||
| 88 | params.gc.gr_compbit_store_base_hw = 0x0; | 115 | params.gc.gr_compbit_store_base_hw = 0x0; |
| 89 | params.gpu_characteristics_buf_size = 0xA0; | 116 | params.gpu_characteristics_buf_size = 0xA0; |
| 90 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | 117 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) |
| 118 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 119 | return NvResult::Success; | ||
| 120 | } | ||
| 91 | 121 | ||
| 92 | if (version == IoctlVersion::Version3) { | 122 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 93 | std::memcpy(output.data(), input.data(), output.size()); | 123 | std::vector<u8>& inline_output) { |
| 94 | std::memcpy(output2.data(), ¶ms.gc, output2.size()); | 124 | LOG_DEBUG(Service_NVDRV, "called"); |
| 95 | } else { | 125 | IoctlCharacteristics params{}; |
| 96 | std::memcpy(output.data(), ¶ms, output.size()); | 126 | std::memcpy(¶ms, input.data(), input.size()); |
| 97 | } | 127 | params.gc.arch = 0x120; |
| 98 | return 0; | 128 | params.gc.impl = 0xb; |
| 129 | params.gc.rev = 0xa1; | ||
| 130 | params.gc.num_gpc = 0x1; | ||
| 131 | params.gc.l2_cache_size = 0x40000; | ||
| 132 | params.gc.on_board_video_memory_size = 0x0; | ||
| 133 | params.gc.num_tpc_per_gpc = 0x2; | ||
| 134 | params.gc.bus_type = 0x20; | ||
| 135 | params.gc.big_page_size = 0x20000; | ||
| 136 | params.gc.compression_page_size = 0x20000; | ||
| 137 | params.gc.pde_coverage_bit_count = 0x1B; | ||
| 138 | params.gc.available_big_page_sizes = 0x30000; | ||
| 139 | params.gc.gpc_mask = 0x1; | ||
| 140 | params.gc.sm_arch_sm_version = 0x503; | ||
| 141 | params.gc.sm_arch_spa_version = 0x503; | ||
| 142 | params.gc.sm_arch_warp_count = 0x80; | ||
| 143 | params.gc.gpu_va_bit_count = 0x28; | ||
| 144 | params.gc.reserved = 0x0; | ||
| 145 | params.gc.flags = 0x55; | ||
| 146 | params.gc.twod_class = 0x902D; | ||
| 147 | params.gc.threed_class = 0xB197; | ||
| 148 | params.gc.compute_class = 0xB1C0; | ||
| 149 | params.gc.gpfifo_class = 0xB06F; | ||
| 150 | params.gc.inline_to_memory_class = 0xA140; | ||
| 151 | params.gc.dma_copy_class = 0xB0B5; | ||
| 152 | params.gc.max_fbps_count = 0x1; | ||
| 153 | params.gc.fbp_en_mask = 0x0; | ||
| 154 | params.gc.max_ltc_per_fbp = 0x2; | ||
| 155 | params.gc.max_lts_per_ltc = 0x1; | ||
| 156 | params.gc.max_tex_per_tpc = 0x0; | ||
| 157 | params.gc.max_gpc_count = 0x1; | ||
| 158 | params.gc.rop_l2_en_mask_0 = 0x21D70; | ||
| 159 | params.gc.rop_l2_en_mask_1 = 0x0; | ||
| 160 | params.gc.chipname = 0x6230326D67; | ||
| 161 | params.gc.gr_compbit_store_base_hw = 0x0; | ||
| 162 | params.gpu_characteristics_buf_size = 0xA0; | ||
| 163 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | ||
| 164 | |||
| 165 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 166 | std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); | ||
| 167 | return NvResult::Success; | ||
| 99 | } | 168 | } |
| 100 | 169 | ||
| 101 | u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, | 170 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { |
| 102 | std::vector<u8>& output2, IoctlVersion version) { | ||
| 103 | IoctlGpuGetTpcMasksArgs params{}; | 171 | IoctlGpuGetTpcMasksArgs params{}; |
| 104 | std::memcpy(¶ms, input.data(), input.size()); | 172 | std::memcpy(¶ms, input.data(), input.size()); |
| 105 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); | 173 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 106 | if (params.mask_buffer_size != 0) { | 174 | if (params.mask_buffer_size != 0) { |
| 107 | params.tcp_mask = 3; | 175 | params.tcp_mask = 3; |
| 108 | } | 176 | } |
| 177 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 178 | return NvResult::Success; | ||
| 179 | } | ||
| 109 | 180 | ||
| 110 | if (version == IoctlVersion::Version3) { | 181 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 111 | std::memcpy(output.data(), input.data(), output.size()); | 182 | std::vector<u8>& inline_output) { |
| 112 | std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size()); | 183 | IoctlGpuGetTpcMasksArgs params{}; |
| 113 | } else { | 184 | std::memcpy(¶ms, input.data(), input.size()); |
| 114 | std::memcpy(output.data(), ¶ms, output.size()); | 185 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 186 | if (params.mask_buffer_size != 0) { | ||
| 187 | params.tcp_mask = 3; | ||
| 115 | } | 188 | } |
| 116 | 189 | std::memcpy(output.data(), ¶ms, output.size()); | |
| 117 | return 0; | 190 | std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); |
| 191 | return NvResult::Success; | ||
| 118 | } | 192 | } |
| 119 | 193 | ||
| 120 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 194 | NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 121 | LOG_DEBUG(Service_NVDRV, "called"); | 195 | LOG_DEBUG(Service_NVDRV, "called"); |
| 122 | 196 | ||
| 123 | IoctlActiveSlotMask params{}; | 197 | IoctlActiveSlotMask params{}; |
| @@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 127 | params.slot = 0x07; | 201 | params.slot = 0x07; |
| 128 | params.mask = 0x01; | 202 | params.mask = 0x01; |
| 129 | std::memcpy(output.data(), ¶ms, output.size()); | 203 | std::memcpy(output.data(), ¶ms, output.size()); |
| 130 | return 0; | 204 | return NvResult::Success; |
| 131 | } | 205 | } |
| 132 | 206 | ||
| 133 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 207 | NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 134 | LOG_DEBUG(Service_NVDRV, "called"); | 208 | LOG_DEBUG(Service_NVDRV, "called"); |
| 135 | 209 | ||
| 136 | IoctlZcullGetCtxSize params{}; | 210 | IoctlZcullGetCtxSize params{}; |
| @@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 139 | } | 213 | } |
| 140 | params.size = 0x1; | 214 | params.size = 0x1; |
| 141 | std::memcpy(output.data(), ¶ms, output.size()); | 215 | std::memcpy(output.data(), ¶ms, output.size()); |
| 142 | return 0; | 216 | return NvResult::Success; |
| 143 | } | 217 | } |
| 144 | 218 | ||
| 145 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 219 | NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | LOG_DEBUG(Service_NVDRV, "called"); | 220 | LOG_DEBUG(Service_NVDRV, "called"); |
| 147 | 221 | ||
| 148 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 222 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| @@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 162 | params.subregion_height_align_pixels = 0x40; | 236 | params.subregion_height_align_pixels = 0x40; |
| 163 | params.subregion_count = 0x10; | 237 | params.subregion_count = 0x10; |
| 164 | std::memcpy(output.data(), ¶ms, output.size()); | 238 | std::memcpy(output.data(), ¶ms, output.size()); |
| 165 | return 0; | 239 | return NvResult::Success; |
| 166 | } | 240 | } |
| 167 | 241 | ||
| 168 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 242 | NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 169 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 243 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 170 | 244 | ||
| 171 | IoctlZbcSetTable params{}; | 245 | IoctlZbcSetTable params{}; |
| 172 | std::memcpy(¶ms, input.data(), input.size()); | 246 | std::memcpy(¶ms, input.data(), input.size()); |
| 173 | // TODO(ogniK): What does this even actually do? | 247 | // TODO(ogniK): What does this even actually do? |
| 174 | std::memcpy(output.data(), ¶ms, output.size()); | 248 | std::memcpy(output.data(), ¶ms, output.size()); |
| 175 | return 0; | 249 | return NvResult::Success; |
| 176 | } | 250 | } |
| 177 | 251 | ||
| 178 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 252 | NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 179 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 253 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 180 | 254 | ||
| 181 | IoctlZbcQueryTable params{}; | 255 | IoctlZbcQueryTable params{}; |
| 182 | std::memcpy(¶ms, input.data(), input.size()); | 256 | std::memcpy(¶ms, input.data(), input.size()); |
| 183 | // TODO : To implement properly | 257 | // TODO : To implement properly |
| 184 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 185 | return 0; | 259 | return NvResult::Success; |
| 186 | } | 260 | } |
| 187 | 261 | ||
| 188 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 189 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 263 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 190 | 264 | ||
| 191 | IoctlFlushL2 params{}; | 265 | IoctlFlushL2 params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 266 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | // TODO : To implement properly | 267 | // TODO : To implement properly |
| 194 | std::memcpy(output.data(), ¶ms, output.size()); | 268 | std::memcpy(output.data(), ¶ms, output.size()); |
| 195 | return 0; | 269 | return NvResult::Success; |
| 196 | } | 270 | } |
| 197 | 271 | ||
| 198 | u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { | 272 | NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { |
| 199 | LOG_DEBUG(Service_NVDRV, "called"); | 273 | LOG_DEBUG(Service_NVDRV, "called"); |
| 200 | 274 | ||
| 201 | IoctlGetGpuTime params{}; | 275 | IoctlGetGpuTime params{}; |
| 202 | std::memcpy(¶ms, input.data(), input.size()); | 276 | std::memcpy(¶ms, input.data(), input.size()); |
| 203 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); | 277 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); |
| 204 | std::memcpy(output.data(), ¶ms, output.size()); | 278 | std::memcpy(output.data(), ¶ms, output.size()); |
| 205 | return 0; | 279 | return NvResult::Success; |
| 206 | } | 280 | } |
| 207 | 281 | ||
| 208 | } // namespace Service::Nvidia::Devices | 282 | } // 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 ef60f72ce..137b88238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -16,32 +16,13 @@ public: | |||
| 16 | explicit nvhost_ctrl_gpu(Core::System& system); | 16 | explicit nvhost_ctrl_gpu(Core::System& system); |
| 17 | ~nvhost_ctrl_gpu() override; | 17 | ~nvhost_ctrl_gpu() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocGetCharacteristicsCommand = 0xC0B04705, | ||
| 26 | IocGetTPCMasksCommand = 0xC0184706, | ||
| 27 | IocGetActiveSlotMaskCommand = 0x80084714, | ||
| 28 | IocZcullGetCtxSizeCommand = 0x80044701, | ||
| 29 | IocZcullGetInfo = 0x80284702, | ||
| 30 | IocZbcSetTable = 0x402C4703, | ||
| 31 | IocZbcQueryTable = 0xC0344704, | ||
| 32 | IocFlushL2 = 0x40084707, | ||
| 33 | IocInvalICache = 0x4008470D, | ||
| 34 | IocSetMmudebugMode = 0x4008470E, | ||
| 35 | IocSetSmDebugMode = 0x4010470F, | ||
| 36 | IocWaitForPause = 0xC0084710, | ||
| 37 | IocGetTcpExceptionEnStatus = 0x80084711, | ||
| 38 | IocNumVsms = 0x80084712, | ||
| 39 | IocVsmsMapping = 0xC0044713, | ||
| 40 | IocGetErrorChannelUserData = 0xC008471B, | ||
| 41 | IocGetGpuTime = 0xC010471C, | ||
| 42 | IocGetCpuTimeCorrelationInfo = 0xC108471D, | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct IoctlGpuCharacteristics { | 26 | struct IoctlGpuCharacteristics { |
| 46 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) | 27 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) |
| 47 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) | 28 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) |
| @@ -159,17 +140,21 @@ private: | |||
| 159 | }; | 140 | }; |
| 160 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); | 141 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); |
| 161 | 142 | ||
| 162 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 143 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); |
| 163 | std::vector<u8>& output2, IoctlVersion version); | 144 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 164 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, | 145 | std::vector<u8>& inline_output); |
| 165 | IoctlVersion version); | 146 | |
| 166 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 147 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 167 | u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); | 148 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 168 | u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); | 149 | std::vector<u8>& inline_output); |
| 169 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | 150 | |
| 170 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | 151 | NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| 171 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | 152 | NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); |
| 172 | u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | 153 | NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); |
| 154 | NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 155 | NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 156 | NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 157 | NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 173 | }; | 158 | }; |
| 174 | 159 | ||
| 175 | } // namespace Service::Nvidia::Devices | 160 | } // 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 f1966ac0e..af8b3d9f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -7,117 +7,148 @@ | |||
| 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/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 10 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 11 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace Service::Nvidia::Devices { | 15 | namespace Service::Nvidia::Devices { |
| 15 | 16 | ||
| 16 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 17 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | SyncpointManager& syncpoint_manager) |
| 19 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} { | ||
| 20 | channel_fence.id = syncpoint_manager.AllocateSyncpoint(); | ||
| 21 | channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); | ||
| 22 | } | ||
| 23 | |||
| 18 | nvhost_gpu::~nvhost_gpu() = default; | 24 | nvhost_gpu::~nvhost_gpu() = default; |
| 19 | 25 | ||
| 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 26 | NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 21 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 27 | switch (command.group) { |
| 22 | IoctlVersion version) { | 28 | case 0x0: |
| 23 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 29 | switch (command.cmd) { |
| 24 | command.raw, input.size(), output.size()); | 30 | case 0x3: |
| 25 | 31 | return GetWaitbase(input, output); | |
| 26 | switch (static_cast<IoctlCommand>(command.raw)) { | 32 | default: |
| 27 | case IoctlCommand::IocSetNVMAPfdCommand: | 33 | break; |
| 28 | return SetNVMAPfd(input, output); | 34 | } |
| 29 | case IoctlCommand::IocSetClientDataCommand: | 35 | break; |
| 30 | return SetClientData(input, output); | 36 | case 'H': |
| 31 | case IoctlCommand::IocGetClientDataCommand: | 37 | switch (command.cmd) { |
| 32 | return GetClientData(input, output); | 38 | case 0x1: |
| 33 | case IoctlCommand::IocZCullBind: | 39 | return SetNVMAPfd(input, output); |
| 34 | return ZCullBind(input, output); | 40 | case 0x3: |
| 35 | case IoctlCommand::IocSetErrorNotifierCommand: | 41 | return ChannelSetTimeout(input, output); |
| 36 | return SetErrorNotifier(input, output); | 42 | case 0x8: |
| 37 | case IoctlCommand::IocChannelSetPriorityCommand: | 43 | return SubmitGPFIFOBase(input, output, false); |
| 38 | return SetChannelPriority(input, output); | 44 | case 0x9: |
| 39 | case IoctlCommand::IocAllocGPFIFOEx2Command: | 45 | return AllocateObjectContext(input, output); |
| 40 | return AllocGPFIFOEx2(input, output); | 46 | case 0xb: |
| 41 | case IoctlCommand::IocAllocObjCtxCommand: | 47 | return ZCullBind(input, output); |
| 42 | return AllocateObjectContext(input, output); | 48 | case 0xc: |
| 43 | case IoctlCommand::IocChannelGetWaitbaseCommand: | 49 | return SetErrorNotifier(input, output); |
| 44 | return GetWaitbase(input, output); | 50 | case 0xd: |
| 45 | case IoctlCommand::IocChannelSetTimeoutCommand: | 51 | return SetChannelPriority(input, output); |
| 46 | return ChannelSetTimeout(input, output); | 52 | case 0x1a: |
| 47 | case IoctlCommand::IocChannelSetTimeslice: | 53 | return AllocGPFIFOEx2(input, output); |
| 48 | return ChannelSetTimeslice(input, output); | 54 | case 0x1b: |
| 49 | default: | 55 | return SubmitGPFIFOBase(input, output, true); |
| 56 | case 0x1d: | ||
| 57 | return ChannelSetTimeslice(input, output); | ||
| 58 | default: | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | break; | ||
| 62 | case 'G': | ||
| 63 | switch (command.cmd) { | ||
| 64 | case 0x14: | ||
| 65 | return SetClientData(input, output); | ||
| 66 | case 0x15: | ||
| 67 | return GetClientData(input, output); | ||
| 68 | default: | ||
| 69 | break; | ||
| 70 | } | ||
| 50 | break; | 71 | break; |
| 51 | } | 72 | } |
| 73 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 74 | return NvResult::NotImplemented; | ||
| 75 | }; | ||
| 52 | 76 | ||
| 53 | if (command.group == NVGPU_IOCTL_MAGIC) { | 77 | NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 54 | if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { | 78 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 55 | return SubmitGPFIFO(input, output); | 79 | switch (command.group) { |
| 56 | } | 80 | case 'H': |
| 57 | if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { | 81 | switch (command.cmd) { |
| 58 | return KickoffPB(input, output, input2, version); | 82 | case 0x1b: |
| 83 | return SubmitGPFIFOBase(input, inline_input, output); | ||
| 59 | } | 84 | } |
| 85 | break; | ||
| 60 | } | 86 | } |
| 87 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 88 | return NvResult::NotImplemented; | ||
| 89 | } | ||
| 61 | 90 | ||
| 62 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 91 | NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 63 | return 0; | 92 | std::vector<u8>& inline_output) { |
| 64 | }; | 93 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 94 | return NvResult::NotImplemented; | ||
| 95 | } | ||
| 65 | 96 | ||
| 66 | u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 97 | NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { |
| 67 | IoctlSetNvmapFD params{}; | 98 | IoctlSetNvmapFD params{}; |
| 68 | std::memcpy(¶ms, input.data(), input.size()); | 99 | std::memcpy(¶ms, input.data(), input.size()); |
| 69 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 100 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 70 | 101 | ||
| 71 | nvmap_fd = params.nvmap_fd; | 102 | nvmap_fd = params.nvmap_fd; |
| 72 | return 0; | 103 | return NvResult::Success; |
| 73 | } | 104 | } |
| 74 | 105 | ||
| 75 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 106 | NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 76 | LOG_DEBUG(Service_NVDRV, "called"); | 107 | LOG_DEBUG(Service_NVDRV, "called"); |
| 77 | 108 | ||
| 78 | IoctlClientData params{}; | 109 | IoctlClientData params{}; |
| 79 | std::memcpy(¶ms, input.data(), input.size()); | 110 | std::memcpy(¶ms, input.data(), input.size()); |
| 80 | user_data = params.data; | 111 | user_data = params.data; |
| 81 | return 0; | 112 | return NvResult::Success; |
| 82 | } | 113 | } |
| 83 | 114 | ||
| 84 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 115 | NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 85 | LOG_DEBUG(Service_NVDRV, "called"); | 116 | LOG_DEBUG(Service_NVDRV, "called"); |
| 86 | 117 | ||
| 87 | IoctlClientData params{}; | 118 | IoctlClientData params{}; |
| 88 | std::memcpy(¶ms, input.data(), input.size()); | 119 | std::memcpy(¶ms, input.data(), input.size()); |
| 89 | params.data = user_data; | 120 | params.data = user_data; |
| 90 | std::memcpy(output.data(), ¶ms, output.size()); | 121 | std::memcpy(output.data(), ¶ms, output.size()); |
| 91 | return 0; | 122 | return NvResult::Success; |
| 92 | } | 123 | } |
| 93 | 124 | ||
| 94 | u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { | 125 | NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { |
| 95 | std::memcpy(&zcull_params, input.data(), input.size()); | 126 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 96 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 127 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 97 | zcull_params.mode); | 128 | zcull_params.mode); |
| 98 | 129 | ||
| 99 | std::memcpy(output.data(), &zcull_params, output.size()); | 130 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 100 | return 0; | 131 | return NvResult::Success; |
| 101 | } | 132 | } |
| 102 | 133 | ||
| 103 | u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { | 134 | NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { |
| 104 | IoctlSetErrorNotifier params{}; | 135 | IoctlSetErrorNotifier params{}; |
| 105 | std::memcpy(¶ms, input.data(), input.size()); | 136 | std::memcpy(¶ms, input.data(), input.size()); |
| 106 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 137 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 107 | params.size, params.mem); | 138 | params.size, params.mem); |
| 108 | 139 | ||
| 109 | std::memcpy(output.data(), ¶ms, output.size()); | 140 | std::memcpy(output.data(), ¶ms, output.size()); |
| 110 | return 0; | 141 | return NvResult::Success; |
| 111 | } | 142 | } |
| 112 | 143 | ||
| 113 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 144 | NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 114 | std::memcpy(&channel_priority, input.data(), input.size()); | 145 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 115 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 146 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 116 | 147 | ||
| 117 | return 0; | 148 | return NvResult::Success; |
| 118 | } | 149 | } |
| 119 | 150 | ||
| 120 | u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { | 151 | NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 121 | IoctlAllocGpfifoEx2 params{}; | 152 | IoctlAllocGpfifoEx2 params{}; |
| 122 | std::memcpy(¶ms, input.data(), input.size()); | 153 | std::memcpy(¶ms, input.data(), input.size()); |
| 123 | LOG_WARNING(Service_NVDRV, | 154 | LOG_WARNING(Service_NVDRV, |
| @@ -126,15 +157,15 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 126 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 157 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 127 | params.unk3); | 158 | params.unk3); |
| 128 | 159 | ||
| 129 | auto& gpu = system.GPU(); | 160 | channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); |
| 130 | params.fence_out.id = assigned_syncpoints; | 161 | |
| 131 | params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints); | 162 | params.fence_out = channel_fence; |
| 132 | assigned_syncpoints++; | 163 | |
| 133 | std::memcpy(output.data(), ¶ms, output.size()); | 164 | std::memcpy(output.data(), ¶ms, output.size()); |
| 134 | return 0; | 165 | return NvResult::Success; |
| 135 | } | 166 | } |
| 136 | 167 | ||
| 137 | u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { | 168 | NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { |
| 138 | IoctlAllocObjCtx params{}; | 169 | IoctlAllocObjCtx params{}; |
| 139 | std::memcpy(¶ms, input.data(), input.size()); | 170 | std::memcpy(¶ms, input.data(), input.size()); |
| 140 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 171 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| @@ -142,102 +173,149 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 142 | 173 | ||
| 143 | params.obj_id = 0x0; | 174 | params.obj_id = 0x0; |
| 144 | std::memcpy(output.data(), ¶ms, output.size()); | 175 | std::memcpy(output.data(), ¶ms, output.size()); |
| 145 | return 0; | 176 | return NvResult::Success; |
| 146 | } | 177 | } |
| 147 | 178 | ||
| 148 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 179 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { |
| 149 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 180 | return { |
| 150 | UNIMPLEMENTED(); | 181 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, |
| 182 | Tegra::SubmissionMode::Increasing), | ||
| 183 | {fence.value}, | ||
| 184 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 185 | Tegra::SubmissionMode::Increasing), | ||
| 186 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id), | ||
| 187 | }; | ||
| 188 | } | ||
| 189 | |||
| 190 | static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) { | ||
| 191 | std::vector<Tegra::CommandHeader> result{ | ||
| 192 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, | ||
| 193 | Tegra::SubmissionMode::Increasing), | ||
| 194 | {}}; | ||
| 195 | |||
| 196 | for (u32 count = 0; count < add_increment; ++count) { | ||
| 197 | result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 198 | Tegra::SubmissionMode::Increasing)); | ||
| 199 | result.emplace_back( | ||
| 200 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id)); | ||
| 151 | } | 201 | } |
| 152 | IoctlSubmitGpfifo params{}; | 202 | |
| 153 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 203 | return result; |
| 204 | } | ||
| 205 | |||
| 206 | static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence, | ||
| 207 | u32 add_increment) { | ||
| 208 | std::vector<Tegra::CommandHeader> result{ | ||
| 209 | Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, | ||
| 210 | Tegra::SubmissionMode::Increasing), | ||
| 211 | {}}; | ||
| 212 | const std::vector<Tegra::CommandHeader> increment{ | ||
| 213 | BuildIncrementCommandList(fence, add_increment)}; | ||
| 214 | |||
| 215 | result.insert(result.end(), increment.begin(), increment.end()); | ||
| 216 | |||
| 217 | return result; | ||
| 218 | } | ||
| 219 | |||
| 220 | NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | ||
| 221 | Tegra::CommandList&& entries) { | ||
| 154 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | 222 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, |
| 155 | params.num_entries, params.flags.raw); | 223 | params.num_entries, params.flags.raw); |
| 156 | 224 | ||
| 157 | ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + | 225 | auto& gpu = system.GPU(); |
| 158 | params.num_entries * sizeof(Tegra::CommandListHeader), | ||
| 159 | "Incorrect input size"); | ||
| 160 | 226 | ||
| 161 | Tegra::CommandList entries(params.num_entries); | 227 | params.fence_out.id = channel_fence.id; |
| 162 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 163 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 164 | 228 | ||
| 165 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | 229 | if (params.flags.add_wait.Value() && |
| 166 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | 230 | !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) { |
| 231 | gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); | ||
| 232 | } | ||
| 167 | 233 | ||
| 168 | auto& gpu = system.GPU(); | 234 | if (params.flags.add_increment.Value() || params.flags.increment.Value()) { |
| 169 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | 235 | const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0; |
| 170 | if (params.flags.increment.Value()) { | 236 | params.fence_out.value = syncpoint_manager.IncreaseSyncpoint( |
| 171 | params.fence_out.value += current_syncpoint_value; | 237 | params.fence_out.id, params.AddIncrementValue() + increment_value); |
| 172 | } else { | 238 | } else { |
| 173 | params.fence_out.value = current_syncpoint_value; | 239 | params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id); |
| 174 | } | 240 | } |
| 241 | |||
| 175 | gpu.PushGPUEntries(std::move(entries)); | 242 | gpu.PushGPUEntries(std::move(entries)); |
| 176 | 243 | ||
| 244 | if (params.flags.add_increment.Value()) { | ||
| 245 | if (params.flags.suppress_wfi) { | ||
| 246 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 247 | BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 248 | } else { | ||
| 249 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 250 | BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 254 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 178 | return 0; | 255 | return NvResult::Success; |
| 179 | } | 256 | } |
| 180 | 257 | ||
| 181 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 258 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 182 | const std::vector<u8>& input2, IoctlVersion version) { | 259 | bool kickoff) { |
| 183 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 260 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 184 | UNIMPLEMENTED(); | 261 | UNIMPLEMENTED(); |
| 262 | return NvResult::InvalidSize; | ||
| 185 | } | 263 | } |
| 186 | IoctlSubmitGpfifo params{}; | 264 | IoctlSubmitGpfifo params{}; |
| 187 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 265 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 188 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | ||
| 189 | params.num_entries, params.flags.raw); | ||
| 190 | |||
| 191 | Tegra::CommandList entries(params.num_entries); | 266 | Tegra::CommandList entries(params.num_entries); |
| 192 | if (version == IoctlVersion::Version2) { | ||
| 193 | std::memcpy(entries.data(), input2.data(), | ||
| 194 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 195 | } else { | ||
| 196 | system.Memory().ReadBlock(params.address, entries.data(), | ||
| 197 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 198 | } | ||
| 199 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | ||
| 200 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | ||
| 201 | 267 | ||
| 202 | auto& gpu = system.GPU(); | 268 | if (kickoff) { |
| 203 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | 269 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), |
| 204 | if (params.flags.increment.Value()) { | 270 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 205 | params.fence_out.value += current_syncpoint_value; | ||
| 206 | } else { | 271 | } else { |
| 207 | params.fence_out.value = current_syncpoint_value; | 272 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], |
| 273 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 208 | } | 274 | } |
| 209 | gpu.PushGPUEntries(std::move(entries)); | ||
| 210 | 275 | ||
| 211 | std::memcpy(output.data(), ¶ms, output.size()); | 276 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 212 | return 0; | 277 | } |
| 278 | |||
| 279 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, | ||
| 280 | const std::vector<u8>& input_inline, | ||
| 281 | std::vector<u8>& output) { | ||
| 282 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | ||
| 283 | UNIMPLEMENTED(); | ||
| 284 | return NvResult::InvalidSize; | ||
| 285 | } | ||
| 286 | IoctlSubmitGpfifo params{}; | ||
| 287 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | ||
| 288 | Tegra::CommandList entries(params.num_entries); | ||
| 289 | std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); | ||
| 290 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | ||
| 213 | } | 291 | } |
| 214 | 292 | ||
| 215 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 216 | IoctlGetWaitbase params{}; | 294 | IoctlGetWaitbase params{}; |
| 217 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 295 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 218 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 296 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 219 | 297 | ||
| 220 | params.value = 0; // Seems to be hard coded at 0 | 298 | params.value = 0; // Seems to be hard coded at 0 |
| 221 | std::memcpy(output.data(), ¶ms, output.size()); | 299 | std::memcpy(output.data(), ¶ms, output.size()); |
| 222 | return 0; | 300 | return NvResult::Success; |
| 223 | } | 301 | } |
| 224 | 302 | ||
| 225 | u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 303 | NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { |
| 226 | IoctlChannelSetTimeout params{}; | 304 | IoctlChannelSetTimeout params{}; |
| 227 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 305 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 228 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 306 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 229 | 307 | ||
| 230 | return 0; | 308 | return NvResult::Success; |
| 231 | } | 309 | } |
| 232 | 310 | ||
| 233 | u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { | 311 | NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { |
| 234 | IoctlSetTimeslice params{}; | 312 | IoctlSetTimeslice params{}; |
| 235 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); | 313 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); |
| 236 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); | 314 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); |
| 237 | 315 | ||
| 238 | channel_timeslice = params.timeslice; | 316 | channel_timeslice = params.timeslice; |
| 239 | 317 | ||
| 240 | return 0; | 318 | return NvResult::Success; |
| 241 | } | 319 | } |
| 242 | 320 | ||
| 243 | } // namespace Service::Nvidia::Devices | 321 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 2ac74743f..e0298b4fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -11,46 +11,28 @@ | |||
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 13 | #include "core/hle/service/nvdrv/nvdata.h" | 13 | #include "core/hle/service/nvdrv/nvdata.h" |
| 14 | #include "video_core/dma_pusher.h" | ||
| 15 | |||
| 16 | namespace Service::Nvidia { | ||
| 17 | class SyncpointManager; | ||
| 18 | } | ||
| 14 | 19 | ||
| 15 | namespace Service::Nvidia::Devices { | 20 | namespace Service::Nvidia::Devices { |
| 16 | 21 | ||
| 17 | class nvmap; | 22 | class nvmap; |
| 18 | constexpr u32 NVGPU_IOCTL_MAGIC('H'); | ||
| 19 | constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); | ||
| 20 | constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | ||
| 21 | |||
| 22 | class nvhost_gpu final : public nvdevice { | 23 | class nvhost_gpu final : public nvdevice { |
| 23 | public: | 24 | public: |
| 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 25 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 26 | SyncpointManager& syncpoint_manager); | ||
| 25 | ~nvhost_gpu() override; | 27 | ~nvhost_gpu() override; |
| 26 | 28 | ||
| 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 29 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 28 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 30 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 29 | IoctlVersion version) override; | 31 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 32 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 33 | std::vector<u8>& inline_output) override; | ||
| 30 | 34 | ||
| 31 | private: | 35 | private: |
| 32 | enum class IoctlCommand : u32_le { | ||
| 33 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 34 | IocAllocGPFIFOCommand = 0x40084805, | ||
| 35 | IocSetClientDataCommand = 0x40084714, | ||
| 36 | IocGetClientDataCommand = 0x80084715, | ||
| 37 | IocZCullBind = 0xc010480b, | ||
| 38 | IocSetErrorNotifierCommand = 0xC018480C, | ||
| 39 | IocChannelSetPriorityCommand = 0x4004480D, | ||
| 40 | IocEnableCommand = 0x0000480E, | ||
| 41 | IocDisableCommand = 0x0000480F, | ||
| 42 | IocPreemptCommand = 0x00004810, | ||
| 43 | IocForceResetCommand = 0x00004811, | ||
| 44 | IocEventIdControlCommand = 0x40084812, | ||
| 45 | IocGetErrorNotificationCommand = 0xC0104817, | ||
| 46 | IocAllocGPFIFOExCommand = 0x40204818, | ||
| 47 | IocAllocGPFIFOEx2Command = 0xC020481A, | ||
| 48 | IocAllocObjCtxCommand = 0xC0104809, | ||
| 49 | IocChannelGetWaitbaseCommand = 0xC0080003, | ||
| 50 | IocChannelSetTimeoutCommand = 0x40044803, | ||
| 51 | IocChannelSetTimeslice = 0xC004481D, | ||
| 52 | }; | ||
| 53 | |||
| 54 | enum class CtxObjects : u32_le { | 36 | enum class CtxObjects : u32_le { |
| 55 | Ctx2D = 0x902D, | 37 | Ctx2D = 0x902D, |
| 56 | Ctx3D = 0xB197, | 38 | Ctx3D = 0xB197, |
| @@ -61,63 +43,63 @@ private: | |||
| 61 | }; | 43 | }; |
| 62 | 44 | ||
| 63 | struct IoctlSetNvmapFD { | 45 | struct IoctlSetNvmapFD { |
| 64 | u32_le nvmap_fd; | 46 | s32_le nvmap_fd{}; |
| 65 | }; | 47 | }; |
| 66 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 48 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 67 | 49 | ||
| 68 | struct IoctlChannelSetTimeout { | 50 | struct IoctlChannelSetTimeout { |
| 69 | u32_le timeout; | 51 | u32_le timeout{}; |
| 70 | }; | 52 | }; |
| 71 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); | 53 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); |
| 72 | 54 | ||
| 73 | struct IoctlAllocGPFIFO { | 55 | struct IoctlAllocGPFIFO { |
| 74 | u32_le num_entries; | 56 | u32_le num_entries{}; |
| 75 | u32_le flags; | 57 | u32_le flags{}; |
| 76 | }; | 58 | }; |
| 77 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); | 59 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); |
| 78 | 60 | ||
| 79 | struct IoctlClientData { | 61 | struct IoctlClientData { |
| 80 | u64_le data; | 62 | u64_le data{}; |
| 81 | }; | 63 | }; |
| 82 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); | 64 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); |
| 83 | 65 | ||
| 84 | struct IoctlZCullBind { | 66 | struct IoctlZCullBind { |
| 85 | u64_le gpu_va; | 67 | u64_le gpu_va{}; |
| 86 | u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf | 68 | u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf |
| 87 | INSERT_PADDING_WORDS(1); | 69 | INSERT_PADDING_WORDS(1); |
| 88 | }; | 70 | }; |
| 89 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); | 71 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); |
| 90 | 72 | ||
| 91 | struct IoctlSetErrorNotifier { | 73 | struct IoctlSetErrorNotifier { |
| 92 | u64_le offset; | 74 | u64_le offset{}; |
| 93 | u64_le size; | 75 | u64_le size{}; |
| 94 | u32_le mem; // nvmap object handle | 76 | u32_le mem{}; // nvmap object handle |
| 95 | INSERT_PADDING_WORDS(1); | 77 | INSERT_PADDING_WORDS(1); |
| 96 | }; | 78 | }; |
| 97 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); | 79 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); |
| 98 | 80 | ||
| 99 | struct IoctlChannelSetPriority { | 81 | struct IoctlChannelSetPriority { |
| 100 | u32_le priority; | 82 | u32_le priority{}; |
| 101 | }; | 83 | }; |
| 102 | static_assert(sizeof(IoctlChannelSetPriority) == 4, | 84 | static_assert(sizeof(IoctlChannelSetPriority) == 4, |
| 103 | "IoctlChannelSetPriority is incorrect size"); | 85 | "IoctlChannelSetPriority is incorrect size"); |
| 104 | 86 | ||
| 105 | struct IoctlSetTimeslice { | 87 | struct IoctlSetTimeslice { |
| 106 | u32_le timeslice; | 88 | u32_le timeslice{}; |
| 107 | }; | 89 | }; |
| 108 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); | 90 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); |
| 109 | 91 | ||
| 110 | struct IoctlEventIdControl { | 92 | struct IoctlEventIdControl { |
| 111 | u32_le cmd; // 0=disable, 1=enable, 2=clear | 93 | u32_le cmd{}; // 0=disable, 1=enable, 2=clear |
| 112 | u32_le id; | 94 | u32_le id{}; |
| 113 | }; | 95 | }; |
| 114 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); | 96 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); |
| 115 | 97 | ||
| 116 | struct IoctlGetErrorNotification { | 98 | struct IoctlGetErrorNotification { |
| 117 | u64_le timestamp; | 99 | u64_le timestamp{}; |
| 118 | u32_le info32; | 100 | u32_le info32{}; |
| 119 | u16_le info16; | 101 | u16_le info16{}; |
| 120 | u16_le status; // always 0xFFFF | 102 | u16_le status{}; // always 0xFFFF |
| 121 | }; | 103 | }; |
| 122 | static_assert(sizeof(IoctlGetErrorNotification) == 16, | 104 | static_assert(sizeof(IoctlGetErrorNotification) == 16, |
| 123 | "IoctlGetErrorNotification is incorrect size"); | 105 | "IoctlGetErrorNotification is incorrect size"); |
| @@ -125,80 +107,89 @@ private: | |||
| 125 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); | 107 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); |
| 126 | 108 | ||
| 127 | struct IoctlAllocGpfifoEx { | 109 | struct IoctlAllocGpfifoEx { |
| 128 | u32_le num_entries; | 110 | u32_le num_entries{}; |
| 129 | u32_le flags; | 111 | u32_le flags{}; |
| 130 | u32_le unk0; | 112 | u32_le unk0{}; |
| 131 | u32_le unk1; | 113 | u32_le unk1{}; |
| 132 | u32_le unk2; | 114 | u32_le unk2{}; |
| 133 | u32_le unk3; | 115 | u32_le unk3{}; |
| 134 | u32_le unk4; | 116 | u32_le unk4{}; |
| 135 | u32_le unk5; | 117 | u32_le unk5{}; |
| 136 | }; | 118 | }; |
| 137 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); | 119 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); |
| 138 | 120 | ||
| 139 | struct IoctlAllocGpfifoEx2 { | 121 | struct IoctlAllocGpfifoEx2 { |
| 140 | u32_le num_entries; // in | 122 | u32_le num_entries{}; // in |
| 141 | u32_le flags; // in | 123 | u32_le flags{}; // in |
| 142 | u32_le unk0; // in (1 works) | 124 | u32_le unk0{}; // in (1 works) |
| 143 | Fence fence_out; // out | 125 | Fence fence_out{}; // out |
| 144 | u32_le unk1; // in | 126 | u32_le unk1{}; // in |
| 145 | u32_le unk2; // in | 127 | u32_le unk2{}; // in |
| 146 | u32_le unk3; // in | 128 | u32_le unk3{}; // in |
| 147 | }; | 129 | }; |
| 148 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); | 130 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); |
| 149 | 131 | ||
| 150 | struct IoctlAllocObjCtx { | 132 | struct IoctlAllocObjCtx { |
| 151 | u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, | 133 | u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, |
| 152 | // 0xB06F=channel_gpfifo | 134 | // 0xB06F=channel_gpfifo |
| 153 | u32_le flags; | 135 | u32_le flags{}; |
| 154 | u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported | 136 | u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported |
| 155 | }; | 137 | }; |
| 156 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); | 138 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); |
| 157 | 139 | ||
| 158 | struct IoctlSubmitGpfifo { | 140 | struct IoctlSubmitGpfifo { |
| 159 | u64_le address; // pointer to gpfifo entry structs | 141 | u64_le address{}; // pointer to gpfifo entry structs |
| 160 | u32_le num_entries; // number of fence objects being submitted | 142 | u32_le num_entries{}; // number of fence objects being submitted |
| 161 | union { | 143 | union { |
| 162 | u32_le raw; | 144 | u32_le raw; |
| 163 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list | 145 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| 164 | BitField<1, 1, u32_le> add_increment; // append an increment to the list | 146 | BitField<1, 1, u32_le> add_increment; // append an increment to the list |
| 165 | BitField<2, 1, u32_le> new_hw_format; // Mostly ignored | 147 | BitField<2, 1, u32_le> new_hw_format; // mostly ignored |
| 148 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt | ||
| 166 | BitField<8, 1, u32_le> increment; // increment the returned fence | 149 | BitField<8, 1, u32_le> increment; // increment the returned fence |
| 167 | } flags; | 150 | } flags; |
| 168 | Fence fence_out; // returned new fence object for others to wait on | 151 | Fence fence_out{}; // returned new fence object for others to wait on |
| 152 | |||
| 153 | u32 AddIncrementValue() const { | ||
| 154 | return flags.add_increment.Value() << 1; | ||
| 155 | } | ||
| 169 | }; | 156 | }; |
| 170 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), | 157 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), |
| 171 | "IoctlSubmitGpfifo is incorrect size"); | 158 | "IoctlSubmitGpfifo is incorrect size"); |
| 172 | 159 | ||
| 173 | struct IoctlGetWaitbase { | 160 | struct IoctlGetWaitbase { |
| 174 | u32 unknown; // seems to be ignored? Nintendo added this | 161 | u32 unknown{}; // seems to be ignored? Nintendo added this |
| 175 | u32 value; | 162 | u32 value{}; |
| 176 | }; | 163 | }; |
| 177 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); | 164 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); |
| 178 | 165 | ||
| 179 | u32_le nvmap_fd{}; | 166 | s32_le nvmap_fd{}; |
| 180 | u64_le user_data{}; | 167 | u64_le user_data{}; |
| 181 | IoctlZCullBind zcull_params{}; | 168 | IoctlZCullBind zcull_params{}; |
| 182 | u32_le channel_priority{}; | 169 | u32_le channel_priority{}; |
| 183 | u32_le channel_timeslice{}; | 170 | u32_le channel_timeslice{}; |
| 184 | 171 | ||
| 185 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 172 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 186 | u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 173 | NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 187 | u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 174 | NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 188 | u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); | 175 | NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); |
| 189 | u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); | 176 | NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); |
| 190 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); | 177 | NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); |
| 191 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 178 | NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 192 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 179 | NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 193 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 180 | NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 194 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 181 | Tegra::CommandList&& entries); |
| 195 | const std::vector<u8>& input2, IoctlVersion version); | 182 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 196 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 183 | bool kickoff = false); |
| 197 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 184 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, |
| 198 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | 185 | std::vector<u8>& output); |
| 186 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 187 | NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 188 | NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 199 | 189 | ||
| 200 | std::shared_ptr<nvmap> nvmap_dev; | 190 | std::shared_ptr<nvmap> nvmap_dev; |
| 201 | u32 assigned_syncpoints{}; | 191 | SyncpointManager& syncpoint_manager; |
| 192 | Fence channel_fence; | ||
| 202 | }; | 193 | }; |
| 203 | 194 | ||
| 204 | } // namespace Service::Nvidia::Devices | 195 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index bdae8b887..36970f828 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -2,39 +2,72 @@ | |||
| 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> | ||
| 6 | |||
| 7 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" | 8 | #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" |
| 9 | #include "video_core/memory_manager.h" | ||
| 10 | #include "video_core/renderer_base.h" | ||
| 10 | 11 | ||
| 11 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 12 | 13 | ||
| 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} | 14 | nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 15 | SyncpointManager& syncpoint_manager) | ||
| 16 | : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} | ||
| 14 | nvhost_nvdec::~nvhost_nvdec() = default; | 17 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 15 | 18 | ||
| 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | std::vector<u8>& output) { |
| 18 | IoctlVersion version) { | 21 | switch (command.group) { |
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 22 | case 0x0: |
| 20 | command.raw, input.size(), output.size()); | 23 | switch (command.cmd) { |
| 21 | 24 | case 0x1: | |
| 22 | switch (static_cast<IoctlCommand>(command.raw)) { | 25 | return Submit(input, output); |
| 23 | case IoctlCommand::IocSetNVMAPfdCommand: | 26 | case 0x2: |
| 24 | return SetNVMAPfd(input, output); | 27 | return GetSyncpoint(input, output); |
| 28 | case 0x3: | ||
| 29 | return GetWaitbase(input, output); | ||
| 30 | case 0x7: | ||
| 31 | return SetSubmitTimeout(input, output); | ||
| 32 | case 0x9: | ||
| 33 | return MapBuffer(input, output); | ||
| 34 | case 0xa: { | ||
| 35 | if (command.length == 0x1c) { | ||
| 36 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | ||
| 37 | Tegra::ChCommandHeaderList cmdlist(1); | ||
| 38 | cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; | ||
| 39 | system.GPU().PushCommandBuffer(cmdlist); | ||
| 40 | } | ||
| 41 | return UnmapBuffer(input, output); | ||
| 42 | } | ||
| 43 | default: | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | break; | ||
| 47 | case 'H': | ||
| 48 | switch (command.cmd) { | ||
| 49 | case 0x1: | ||
| 50 | return SetNVMAPfd(input); | ||
| 51 | default: | ||
| 52 | break; | ||
| 53 | } | ||
| 54 | break; | ||
| 25 | } | 55 | } |
| 26 | 56 | ||
| 27 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 57 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 28 | return 0; | 58 | return NvResult::NotImplemented; |
| 29 | } | 59 | } |
| 30 | 60 | ||
| 31 | u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 61 | NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 32 | IoctlSetNvmapFD params{}; | 62 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 33 | std::memcpy(¶ms, input.data(), input.size()); | 63 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 34 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 64 | return NvResult::NotImplemented; |
| 65 | } | ||
| 35 | 66 | ||
| 36 | nvmap_fd = params.nvmap_fd; | 67 | NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 37 | return 0; | 68 | std::vector<u8>& inline_output) { |
| 69 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 70 | return NvResult::NotImplemented; | ||
| 38 | } | 71 | } |
| 39 | 72 | ||
| 40 | } // namespace Service::Nvidia::Devices | 73 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index cbdac8069..77ef53cdd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -4,35 +4,22 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | 7 | #include <memory> |
| 8 | #include "common/common_types.h" | 8 | #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" |
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | ||
| 11 | 9 | ||
| 12 | namespace Service::Nvidia::Devices { | 10 | namespace Service::Nvidia::Devices { |
| 13 | 11 | ||
| 14 | class nvhost_nvdec final : public nvdevice { | 12 | class nvhost_nvdec final : public nvhost_nvdec_common { |
| 15 | public: | 13 | public: |
| 16 | explicit nvhost_nvdec(Core::System& system); | 14 | explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 15 | SyncpointManager& syncpoint_manager); | ||
| 17 | ~nvhost_nvdec() override; | 16 | ~nvhost_nvdec() override; |
| 18 | 17 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 19 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 20 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | 21 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | |
| 23 | private: | 22 | std::vector<u8>& inline_output) override; |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct IoctlSetNvmapFD { | ||
| 29 | u32_le nvmap_fd; | ||
| 30 | }; | ||
| 31 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | ||
| 32 | |||
| 33 | u32_le nvmap_fd{}; | ||
| 34 | |||
| 35 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 36 | }; | 23 | }; |
| 37 | 24 | ||
| 38 | } // namespace Service::Nvidia::Devices | 25 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp new file mode 100644 index 000000000..4898dc27a --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstring> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" | ||
| 13 | #include "core/hle/service/nvdrv/devices/nvmap.h" | ||
| 14 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 15 | #include "core/memory.h" | ||
| 16 | #include "video_core/memory_manager.h" | ||
| 17 | #include "video_core/renderer_base.h" | ||
| 18 | |||
| 19 | namespace Service::Nvidia::Devices { | ||
| 20 | |||
| 21 | namespace { | ||
| 22 | // Splice vectors will copy count amount of type T from the input vector into the dst vector. | ||
| 23 | template <typename T> | ||
| 24 | std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count, | ||
| 25 | std::size_t offset) { | ||
| 26 | std::memcpy(dst.data(), input.data() + offset, count * sizeof(T)); | ||
| 27 | offset += count * sizeof(T); | ||
| 28 | return offset; | ||
| 29 | } | ||
| 30 | |||
| 31 | // Write vectors will write data to the output buffer | ||
| 32 | template <typename T> | ||
| 33 | std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) { | ||
| 34 | std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T)); | ||
| 35 | offset += src.size() * sizeof(T); | ||
| 36 | return offset; | ||
| 37 | } | ||
| 38 | } // Anonymous namespace | ||
| 39 | |||
| 40 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | ||
| 41 | SyncpointManager& syncpoint_manager) | ||
| 42 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager(syncpoint_manager) {} | ||
| 43 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; | ||
| 44 | |||
| 45 | NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { | ||
| 46 | IoctlSetNvmapFD params{}; | ||
| 47 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); | ||
| 48 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | ||
| 49 | |||
| 50 | nvmap_fd = params.nvmap_fd; | ||
| 51 | return NvResult::Success; | ||
| 52 | } | ||
| 53 | |||
| 54 | NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 55 | IoctlSubmit params{}; | ||
| 56 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | ||
| 57 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); | ||
| 58 | |||
| 59 | // Instantiate param buffers | ||
| 60 | std::size_t offset = sizeof(IoctlSubmit); | ||
| 61 | std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count); | ||
| 62 | std::vector<Reloc> relocs(params.relocation_count); | ||
| 63 | std::vector<u32> reloc_shifts(params.relocation_count); | ||
| 64 | std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count); | ||
| 65 | std::vector<SyncptIncr> wait_checks(params.syncpoint_count); | ||
| 66 | std::vector<Fence> fences(params.fence_count); | ||
| 67 | |||
| 68 | // Splice input into their respective buffers | ||
| 69 | offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset); | ||
| 70 | offset = SpliceVectors(input, relocs, params.relocation_count, offset); | ||
| 71 | offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset); | ||
| 72 | offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset); | ||
| 73 | offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset); | ||
| 74 | offset = SpliceVectors(input, fences, params.fence_count, offset); | ||
| 75 | |||
| 76 | auto& gpu = system.GPU(); | ||
| 77 | if (gpu.UseNvdec()) { | ||
| 78 | for (std::size_t i = 0; i < syncpt_increments.size(); i++) { | ||
| 79 | const SyncptIncr& syncpt_incr = syncpt_increments[i]; | ||
| 80 | fences[i].id = syncpt_incr.id; | ||
| 81 | fences[i].value = | ||
| 82 | syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | for (const auto& cmd_buffer : command_buffers) { | ||
| 86 | auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); | ||
| 87 | ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); | ||
| 88 | const auto map = FindBufferMap(object->dma_map_addr); | ||
| 89 | if (!map) { | ||
| 90 | LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", | ||
| 91 | object->addr, object->dma_map_addr); | ||
| 92 | return NvResult::Success; | ||
| 93 | } | ||
| 94 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); | ||
| 95 | gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), | ||
| 96 | cmdlist.size() * sizeof(u32)); | ||
| 97 | gpu.PushCommandBuffer(cmdlist); | ||
| 98 | } | ||
| 99 | if (gpu.UseNvdec()) { | ||
| 100 | |||
| 101 | fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1); | ||
| 102 | |||
| 103 | Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}}; | ||
| 104 | gpu.PushCommandBuffer(cmdlist); | ||
| 105 | } | ||
| 106 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); | ||
| 107 | // Some games expect command_buffers to be written back | ||
| 108 | offset = sizeof(IoctlSubmit); | ||
| 109 | offset = WriteVectors(output, command_buffers, offset); | ||
| 110 | offset = WriteVectors(output, relocs, offset); | ||
| 111 | offset = WriteVectors(output, reloc_shifts, offset); | ||
| 112 | offset = WriteVectors(output, syncpt_increments, offset); | ||
| 113 | offset = WriteVectors(output, wait_checks, offset); | ||
| 114 | offset = WriteVectors(output, fences, offset); | ||
| 115 | |||
| 116 | return NvResult::Success; | ||
| 117 | } | ||
| 118 | |||
| 119 | NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 120 | IoctlGetSyncpoint params{}; | ||
| 121 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); | ||
| 122 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); | ||
| 123 | |||
| 124 | if (device_syncpoints[params.param] == 0 && system.GPU().UseNvdec()) { | ||
| 125 | device_syncpoints[params.param] = syncpoint_manager.AllocateSyncpoint(); | ||
| 126 | } | ||
| 127 | params.value = device_syncpoints[params.param]; | ||
| 128 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); | ||
| 129 | |||
| 130 | return NvResult::Success; | ||
| 131 | } | ||
| 132 | |||
| 133 | NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 134 | IoctlGetWaitbase params{}; | ||
| 135 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | ||
| 136 | params.value = 0; // Seems to be hard coded at 0 | ||
| 137 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); | ||
| 138 | return NvResult::Success; | ||
| 139 | } | ||
| 140 | |||
| 141 | NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 142 | IoctlMapBuffer params{}; | ||
| 143 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | ||
| 144 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | ||
| 145 | |||
| 146 | SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); | ||
| 147 | |||
| 148 | auto& gpu = system.GPU(); | ||
| 149 | |||
| 150 | for (auto& cmf_buff : cmd_buffer_handles) { | ||
| 151 | auto object{nvmap_dev->GetObject(cmf_buff.map_handle)}; | ||
| 152 | if (!object) { | ||
| 153 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | ||
| 154 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 155 | return NvResult::InvalidState; | ||
| 156 | } | ||
| 157 | if (object->dma_map_addr == 0) { | ||
| 158 | // NVDEC and VIC memory is in the 32-bit address space | ||
| 159 | // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space | ||
| 160 | const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size); | ||
| 161 | object->dma_map_addr = static_cast<u32>(low_addr); | ||
| 162 | // Ensure that the dma_map_addr is indeed in the lower 32-bit address space. | ||
| 163 | ASSERT(object->dma_map_addr == low_addr); | ||
| 164 | } | ||
| 165 | if (!object->dma_map_addr) { | ||
| 166 | LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size); | ||
| 167 | } else { | ||
| 168 | cmf_buff.map_address = object->dma_map_addr; | ||
| 169 | AddBufferMap(object->dma_map_addr, object->size, object->addr, | ||
| 170 | object->status == nvmap::Object::Status::Allocated); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer)); | ||
| 174 | std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), | ||
| 175 | cmd_buffer_handles.size() * sizeof(MapBufferEntry)); | ||
| 176 | |||
| 177 | return NvResult::Success; | ||
| 178 | } | ||
| 179 | |||
| 180 | NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 181 | IoctlMapBuffer params{}; | ||
| 182 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | ||
| 183 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | ||
| 184 | SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); | ||
| 185 | |||
| 186 | auto& gpu = system.GPU(); | ||
| 187 | |||
| 188 | for (auto& cmf_buff : cmd_buffer_handles) { | ||
| 189 | const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)}; | ||
| 190 | if (!object) { | ||
| 191 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | ||
| 192 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 193 | return NvResult::InvalidState; | ||
| 194 | } | ||
| 195 | if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { | ||
| 196 | gpu.MemoryManager().Unmap(object->dma_map_addr, *size); | ||
| 197 | } else { | ||
| 198 | // This occurs quite frequently, however does not seem to impact functionality | ||
| 199 | LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr, | ||
| 200 | object->dma_map_addr); | ||
| 201 | } | ||
| 202 | object->dma_map_addr = 0; | ||
| 203 | } | ||
| 204 | std::memset(output.data(), 0, output.size()); | ||
| 205 | return NvResult::Success; | ||
| 206 | } | ||
| 207 | |||
| 208 | NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, | ||
| 209 | std::vector<u8>& output) { | ||
| 210 | std::memcpy(&submit_timeout, input.data(), input.size()); | ||
| 211 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 212 | return NvResult::Success; | ||
| 213 | } | ||
| 214 | |||
| 215 | std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( | ||
| 216 | GPUVAddr gpu_addr) const { | ||
| 217 | const auto it = std::find_if( | ||
| 218 | buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) { | ||
| 219 | return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr()); | ||
| 220 | }); | ||
| 221 | |||
| 222 | ASSERT(it != buffer_mappings.end()); | ||
| 223 | return it->second; | ||
| 224 | } | ||
| 225 | |||
| 226 | void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, | ||
| 227 | bool is_allocated) { | ||
| 228 | buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated}); | ||
| 229 | } | ||
| 230 | |||
| 231 | std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) { | ||
| 232 | const auto iter{buffer_mappings.find(gpu_addr)}; | ||
| 233 | if (iter == buffer_mappings.end()) { | ||
| 234 | return std::nullopt; | ||
| 235 | } | ||
| 236 | std::size_t size = 0; | ||
| 237 | if (iter->second.IsAllocated()) { | ||
| 238 | size = iter->second.Size(); | ||
| 239 | } | ||
| 240 | buffer_mappings.erase(iter); | ||
| 241 | return size; | ||
| 242 | } | ||
| 243 | |||
| 244 | } // namespace Service::Nvidia::Devices | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h new file mode 100644 index 000000000..4c9d4ba41 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | ||
| 12 | |||
| 13 | namespace Service::Nvidia { | ||
| 14 | class SyncpointManager; | ||
| 15 | |||
| 16 | namespace Devices { | ||
| 17 | class nvmap; | ||
| 18 | |||
| 19 | class nvhost_nvdec_common : public nvdevice { | ||
| 20 | public: | ||
| 21 | explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | ||
| 22 | SyncpointManager& syncpoint_manager); | ||
| 23 | ~nvhost_nvdec_common() override; | ||
| 24 | |||
| 25 | protected: | ||
| 26 | class BufferMap final { | ||
| 27 | public: | ||
| 28 | constexpr BufferMap() = default; | ||
| 29 | |||
| 30 | constexpr BufferMap(GPUVAddr start_addr, std::size_t size) | ||
| 31 | : start_addr{start_addr}, end_addr{start_addr + size} {} | ||
| 32 | |||
| 33 | constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr, | ||
| 34 | bool is_allocated) | ||
| 35 | : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr}, | ||
| 36 | is_allocated{is_allocated} {} | ||
| 37 | |||
| 38 | constexpr VAddr StartAddr() const { | ||
| 39 | return start_addr; | ||
| 40 | } | ||
| 41 | |||
| 42 | constexpr VAddr EndAddr() const { | ||
| 43 | return end_addr; | ||
| 44 | } | ||
| 45 | |||
| 46 | constexpr std::size_t Size() const { | ||
| 47 | return end_addr - start_addr; | ||
| 48 | } | ||
| 49 | |||
| 50 | constexpr VAddr CpuAddr() const { | ||
| 51 | return cpu_addr; | ||
| 52 | } | ||
| 53 | |||
| 54 | constexpr bool IsAllocated() const { | ||
| 55 | return is_allocated; | ||
| 56 | } | ||
| 57 | |||
| 58 | private: | ||
| 59 | GPUVAddr start_addr{}; | ||
| 60 | GPUVAddr end_addr{}; | ||
| 61 | VAddr cpu_addr{}; | ||
| 62 | bool is_allocated{}; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct IoctlSetNvmapFD { | ||
| 66 | s32_le nvmap_fd{}; | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | ||
| 69 | |||
| 70 | struct IoctlSubmitCommandBuffer { | ||
| 71 | u32_le id{}; | ||
| 72 | u32_le offset{}; | ||
| 73 | u32_le count{}; | ||
| 74 | }; | ||
| 75 | static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, | ||
| 76 | "IoctlSubmitCommandBuffer is incorrect size"); | ||
| 77 | struct IoctlSubmit { | ||
| 78 | u32_le cmd_buffer_count{}; | ||
| 79 | u32_le relocation_count{}; | ||
| 80 | u32_le syncpoint_count{}; | ||
| 81 | u32_le fence_count{}; | ||
| 82 | }; | ||
| 83 | static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); | ||
| 84 | |||
| 85 | struct CommandBuffer { | ||
| 86 | s32 memory_id{}; | ||
| 87 | u32 offset{}; | ||
| 88 | s32 word_count{}; | ||
| 89 | }; | ||
| 90 | static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); | ||
| 91 | |||
| 92 | struct Reloc { | ||
| 93 | s32 cmdbuffer_memory{}; | ||
| 94 | s32 cmdbuffer_offset{}; | ||
| 95 | s32 target{}; | ||
| 96 | s32 target_offset{}; | ||
| 97 | }; | ||
| 98 | static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); | ||
| 99 | |||
| 100 | struct SyncptIncr { | ||
| 101 | u32 id{}; | ||
| 102 | u32 increments{}; | ||
| 103 | }; | ||
| 104 | static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); | ||
| 105 | |||
| 106 | struct Fence { | ||
| 107 | u32 id{}; | ||
| 108 | u32 value{}; | ||
| 109 | }; | ||
| 110 | static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); | ||
| 111 | |||
| 112 | struct IoctlGetSyncpoint { | ||
| 113 | // Input | ||
| 114 | u32_le param{}; | ||
| 115 | // Output | ||
| 116 | u32_le value{}; | ||
| 117 | }; | ||
| 118 | static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); | ||
| 119 | |||
| 120 | struct IoctlGetWaitbase { | ||
| 121 | u32_le unknown{}; // seems to be ignored? Nintendo added this | ||
| 122 | u32_le value{}; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); | ||
| 125 | |||
| 126 | struct IoctlMapBuffer { | ||
| 127 | u32_le num_entries{}; | ||
| 128 | u32_le data_address{}; // Ignored by the driver. | ||
| 129 | u32_le attach_host_ch_das{}; | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | ||
| 132 | |||
| 133 | struct IocGetIdParams { | ||
| 134 | // Input | ||
| 135 | u32_le param{}; | ||
| 136 | // Output | ||
| 137 | u32_le value{}; | ||
| 138 | }; | ||
| 139 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | ||
| 140 | |||
| 141 | // Used for mapping and unmapping command buffers | ||
| 142 | struct MapBufferEntry { | ||
| 143 | u32_le map_handle{}; | ||
| 144 | u32_le map_address{}; | ||
| 145 | }; | ||
| 146 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | ||
| 147 | |||
| 148 | /// Ioctl command implementations | ||
| 149 | NvResult SetNVMAPfd(const std::vector<u8>& input); | ||
| 150 | NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 151 | NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 152 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 153 | NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 154 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 155 | NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 156 | |||
| 157 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | ||
| 158 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | ||
| 159 | std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); | ||
| 160 | |||
| 161 | s32_le nvmap_fd{}; | ||
| 162 | u32_le submit_timeout{}; | ||
| 163 | std::shared_ptr<nvmap> nvmap_dev; | ||
| 164 | SyncpointManager& syncpoint_manager; | ||
| 165 | std::array<u32, MaxSyncPoints> device_syncpoints{}; | ||
| 166 | // This is expected to be ordered, therefore we must use a map, not unordered_map | ||
| 167 | std::map<GPUVAddr, BufferMap> buffer_mappings; | ||
| 168 | }; | ||
| 169 | }; // namespace Devices | ||
| 170 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 96e7b7dab..2d06955c0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} | 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 16 | NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 17 | std::vector<u8>& output) { |
| 18 | IoctlVersion version) { | 18 | switch (command.group) { |
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | case 'H': |
| 20 | command.raw, input.size(), output.size()); | 20 | switch (command.cmd) { |
| 21 | 21 | case 0x1: | |
| 22 | switch (static_cast<IoctlCommand>(command.raw)) { | 22 | return SetNVMAPfd(input, output); |
| 23 | case IoctlCommand::IocSetNVMAPfdCommand: | 23 | default: |
| 24 | return SetNVMAPfd(input, output); | 24 | break; |
| 25 | } | ||
| 26 | break; | ||
| 27 | default: | ||
| 28 | break; | ||
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 31 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 28 | return 0; | 32 | return NvResult::NotImplemented; |
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 35 | NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 36 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 37 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 38 | return NvResult::NotImplemented; | ||
| 39 | } | ||
| 40 | |||
| 41 | NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 42 | std::vector<u8>& inline_output) { | ||
| 43 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 44 | return NvResult::NotImplemented; | ||
| 45 | } | ||
| 46 | |||
| 47 | NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 32 | IoctlSetNvmapFD params{}; | 48 | IoctlSetNvmapFD params{}; |
| 33 | std::memcpy(¶ms, input.data(), input.size()); | 49 | std::memcpy(¶ms, input.data(), input.size()); |
| 34 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 50 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 35 | 51 | ||
| 36 | nvmap_fd = params.nvmap_fd; | 52 | nvmap_fd = params.nvmap_fd; |
| 37 | return 0; | 53 | return NvResult::Success; |
| 38 | } | 54 | } |
| 39 | 55 | ||
| 40 | } // namespace Service::Nvidia::Devices | 56 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 98dcac52f..43948d18d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -16,23 +16,21 @@ public: | |||
| 16 | explicit nvhost_nvjpg(Core::System& system); | 16 | explicit nvhost_nvjpg(Core::System& system); |
| 17 | ~nvhost_nvjpg() override; | 17 | ~nvhost_nvjpg() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct IoctlSetNvmapFD { | 26 | struct IoctlSetNvmapFD { |
| 29 | u32_le nvmap_fd; | 27 | s32_le nvmap_fd{}; |
| 30 | }; | 28 | }; |
| 31 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 29 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 32 | 30 | ||
| 33 | u32_le nvmap_fd{}; | 31 | s32_le nvmap_fd{}; |
| 34 | 32 | ||
| 35 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 33 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | } // namespace Service::Nvidia::Devices | 36 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index c695b8863..72499654c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -2,39 +2,64 @@ | |||
| 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> | ||
| 6 | |||
| 7 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_vic.h" | 8 | #include "core/hle/service/nvdrv/devices/nvhost_vic.h" |
| 9 | #include "video_core/memory_manager.h" | ||
| 10 | #include "video_core/renderer_base.h" | ||
| 10 | 11 | ||
| 11 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | ||
| 14 | SyncpointManager& syncpoint_manager) | ||
| 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} | ||
| 12 | 16 | ||
| 13 | nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} | ||
| 14 | nvhost_vic::~nvhost_vic() = default; | 17 | nvhost_vic::~nvhost_vic() = default; |
| 15 | 18 | ||
| 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | switch (command.group) { |
| 18 | IoctlVersion version) { | 21 | case 0x0: |
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 22 | switch (command.cmd) { |
| 20 | command.raw, input.size(), output.size()); | 23 | case 0x1: |
| 21 | 24 | return Submit(input, output); | |
| 22 | switch (static_cast<IoctlCommand>(command.raw)) { | 25 | case 0x2: |
| 23 | case IoctlCommand::IocSetNVMAPfdCommand: | 26 | return GetSyncpoint(input, output); |
| 24 | return SetNVMAPfd(input, output); | 27 | case 0x3: |
| 28 | return GetWaitbase(input, output); | ||
| 29 | case 0x9: | ||
| 30 | return MapBuffer(input, output); | ||
| 31 | case 0xa: | ||
| 32 | return UnmapBuffer(input, output); | ||
| 33 | default: | ||
| 34 | break; | ||
| 35 | } | ||
| 36 | break; | ||
| 37 | case 'H': | ||
| 38 | switch (command.cmd) { | ||
| 39 | case 0x1: | ||
| 40 | return SetNVMAPfd(input); | ||
| 41 | default: | ||
| 42 | break; | ||
| 43 | } | ||
| 44 | break; | ||
| 45 | default: | ||
| 46 | break; | ||
| 25 | } | 47 | } |
| 26 | 48 | ||
| 27 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 49 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 28 | return 0; | 50 | return NvResult::NotImplemented; |
| 29 | } | 51 | } |
| 30 | 52 | ||
| 31 | u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 53 | NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 32 | IoctlSetNvmapFD params{}; | 54 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 33 | std::memcpy(¶ms, input.data(), input.size()); | 55 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 34 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 56 | return NvResult::NotImplemented; |
| 57 | } | ||
| 35 | 58 | ||
| 36 | nvmap_fd = params.nvmap_fd; | 59 | NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 37 | return 0; | 60 | std::vector<u8>& inline_output) { |
| 61 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 62 | return NvResult::NotImplemented; | ||
| 38 | } | 63 | } |
| 39 | 64 | ||
| 40 | } // namespace Service::Nvidia::Devices | 65 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index bec32bea1..f401c61fa 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -4,35 +4,20 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | 7 | #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" |
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | ||
| 11 | 8 | ||
| 12 | namespace Service::Nvidia::Devices { | 9 | namespace Service::Nvidia::Devices { |
| 13 | 10 | ||
| 14 | class nvhost_vic final : public nvdevice { | 11 | class nvhost_vic final : public nvhost_nvdec_common { |
| 15 | public: | 12 | public: |
| 16 | explicit nvhost_vic(Core::System& system); | 13 | explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 17 | ~nvhost_vic() override; | 14 | SyncpointManager& syncpoint_manager); |
| 18 | 15 | ~nvhost_vic(); | |
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 16 | |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 17 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 21 | IoctlVersion version) override; | 18 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 22 | 19 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; | |
| 23 | private: | 20 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 24 | enum class IoctlCommand : u32_le { | 21 | std::vector<u8>& inline_output) override; |
| 25 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct IoctlSetNvmapFD { | ||
| 29 | u32_le nvmap_fd; | ||
| 30 | }; | ||
| 31 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | ||
| 32 | |||
| 33 | u32_le nvmap_fd{}; | ||
| 34 | |||
| 35 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 36 | }; | 22 | }; |
| 37 | |||
| 38 | } // namespace Service::Nvidia::Devices | 23 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 9436e16ad..4015a2740 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -11,13 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | 13 | ||
| 14 | namespace NvErrCodes { | ||
| 15 | enum { | ||
| 16 | OperationNotPermitted = -1, | ||
| 17 | InvalidValue = -22, | ||
| 18 | }; | ||
| 19 | } | ||
| 20 | |||
| 21 | nvmap::nvmap(Core::System& system) : nvdevice(system) { | 14 | nvmap::nvmap(Core::System& system) : nvdevice(system) { |
| 22 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to | 15 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to |
| 23 | // represent this. | 16 | // represent this. |
| @@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) { | |||
| 26 | 19 | ||
| 27 | nvmap::~nvmap() = default; | 20 | nvmap::~nvmap() = default; |
| 28 | 21 | ||
| 22 | NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 23 | switch (command.group) { | ||
| 24 | case 0x1: | ||
| 25 | switch (command.cmd) { | ||
| 26 | case 0x1: | ||
| 27 | return IocCreate(input, output); | ||
| 28 | case 0x3: | ||
| 29 | return IocFromId(input, output); | ||
| 30 | case 0x4: | ||
| 31 | return IocAlloc(input, output); | ||
| 32 | case 0x5: | ||
| 33 | return IocFree(input, output); | ||
| 34 | case 0x9: | ||
| 35 | return IocParam(input, output); | ||
| 36 | case 0xe: | ||
| 37 | return IocGetId(input, output); | ||
| 38 | default: | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | break; | ||
| 42 | default: | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | |||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 57 | std::vector<u8>& inline_output) { | ||
| 58 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 59 | return NvResult::NotImplemented; | ||
| 60 | } | ||
| 61 | |||
| 29 | VAddr nvmap::GetObjectAddress(u32 handle) const { | 62 | VAddr nvmap::GetObjectAddress(u32 handle) const { |
| 30 | auto object = GetObject(handle); | 63 | auto object = GetObject(handle); |
| 31 | ASSERT(object); | 64 | ASSERT(object); |
| @@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { | |||
| 33 | return object->addr; | 66 | return object->addr; |
| 34 | } | 67 | } |
| 35 | 68 | ||
| 36 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 37 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 38 | IoctlVersion version) { | ||
| 39 | switch (static_cast<IoctlCommand>(command.raw)) { | ||
| 40 | case IoctlCommand::Create: | ||
| 41 | return IocCreate(input, output); | ||
| 42 | case IoctlCommand::Alloc: | ||
| 43 | return IocAlloc(input, output); | ||
| 44 | case IoctlCommand::GetId: | ||
| 45 | return IocGetId(input, output); | ||
| 46 | case IoctlCommand::FromId: | ||
| 47 | return IocFromId(input, output); | ||
| 48 | case IoctlCommand::Param: | ||
| 49 | return IocParam(input, output); | ||
| 50 | case IoctlCommand::Free: | ||
| 51 | return IocFree(input, output); | ||
| 52 | } | ||
| 53 | |||
| 54 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | u32 nvmap::CreateObject(u32 size) { | 69 | u32 nvmap::CreateObject(u32 size) { |
| 59 | // Create a new nvmap object and obtain a handle to it. | 70 | // Create a new nvmap object and obtain a handle to it. |
| 60 | auto object = std::make_shared<Object>(); | 71 | auto object = std::make_shared<Object>(); |
| @@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) { | |||
| 70 | return handle; | 81 | return handle; |
| 71 | } | 82 | } |
| 72 | 83 | ||
| 73 | u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | 84 | NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { |
| 74 | IocCreateParams params; | 85 | IocCreateParams params; |
| 75 | std::memcpy(¶ms, input.data(), sizeof(params)); | 86 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 76 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 87 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 77 | 88 | ||
| 78 | if (!params.size) { | 89 | if (!params.size) { |
| 79 | LOG_ERROR(Service_NVDRV, "Size is 0"); | 90 | LOG_ERROR(Service_NVDRV, "Size is 0"); |
| 80 | return static_cast<u32>(NvErrCodes::InvalidValue); | 91 | return NvResult::BadValue; |
| 81 | } | 92 | } |
| 82 | 93 | ||
| 83 | params.handle = CreateObject(params.size); | 94 | params.handle = CreateObject(params.size); |
| 84 | 95 | ||
| 85 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 96 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 86 | return 0; | 97 | return NvResult::Success; |
| 87 | } | 98 | } |
| 88 | 99 | ||
| 89 | u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | 100 | NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { |
| 90 | IocAllocParams params; | 101 | IocAllocParams params; |
| 91 | std::memcpy(¶ms, input.data(), sizeof(params)); | 102 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 92 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 103 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 93 | 104 | ||
| 94 | if (!params.handle) { | 105 | if (!params.handle) { |
| 95 | LOG_ERROR(Service_NVDRV, "Handle is 0"); | 106 | LOG_ERROR(Service_NVDRV, "Handle is 0"); |
| 96 | return static_cast<u32>(NvErrCodes::InvalidValue); | 107 | return NvResult::BadValue; |
| 97 | } | 108 | } |
| 98 | 109 | ||
| 99 | if ((params.align - 1) & params.align) { | 110 | if ((params.align - 1) & params.align) { |
| 100 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); | 111 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); |
| 101 | return static_cast<u32>(NvErrCodes::InvalidValue); | 112 | return NvResult::BadValue; |
| 102 | } | 113 | } |
| 103 | 114 | ||
| 104 | const u32 min_alignment = 0x1000; | 115 | const u32 min_alignment = 0x1000; |
| @@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 109 | auto object = GetObject(params.handle); | 120 | auto object = GetObject(params.handle); |
| 110 | if (!object) { | 121 | if (!object) { |
| 111 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 122 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 112 | return static_cast<u32>(NvErrCodes::InvalidValue); | 123 | return NvResult::BadValue; |
| 113 | } | 124 | } |
| 114 | 125 | ||
| 115 | if (object->status == Object::Status::Allocated) { | 126 | if (object->status == Object::Status::Allocated) { |
| 116 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); | 127 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); |
| 117 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 128 | return NvResult::InsufficientMemory; |
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | object->flags = params.flags; | 131 | object->flags = params.flags; |
| @@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 124 | object->status = Object::Status::Allocated; | 135 | object->status = Object::Status::Allocated; |
| 125 | 136 | ||
| 126 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 137 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 127 | return 0; | 138 | return NvResult::Success; |
| 128 | } | 139 | } |
| 129 | 140 | ||
| 130 | u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | 141 | NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 131 | IocGetIdParams params; | 142 | IocGetIdParams params; |
| 132 | std::memcpy(¶ms, input.data(), sizeof(params)); | 143 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 133 | 144 | ||
| @@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 135 | 146 | ||
| 136 | if (!params.handle) { | 147 | if (!params.handle) { |
| 137 | LOG_ERROR(Service_NVDRV, "Handle is zero"); | 148 | LOG_ERROR(Service_NVDRV, "Handle is zero"); |
| 138 | return static_cast<u32>(NvErrCodes::InvalidValue); | 149 | return NvResult::BadValue; |
| 139 | } | 150 | } |
| 140 | 151 | ||
| 141 | auto object = GetObject(params.handle); | 152 | auto object = GetObject(params.handle); |
| 142 | if (!object) { | 153 | if (!object) { |
| 143 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 154 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 144 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 155 | return NvResult::BadValue; |
| 145 | } | 156 | } |
| 146 | 157 | ||
| 147 | params.id = object->id; | 158 | params.id = object->id; |
| 148 | 159 | ||
| 149 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 160 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 150 | return 0; | 161 | return NvResult::Success; |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 154 | IocFromIdParams params; | 165 | IocFromIdParams params; |
| 155 | std::memcpy(¶ms, input.data(), sizeof(params)); | 166 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 156 | 167 | ||
| @@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 160 | [&](const auto& entry) { return entry.second->id == params.id; }); | 171 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 161 | if (itr == handles.end()) { | 172 | if (itr == handles.end()) { |
| 162 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 173 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 163 | return static_cast<u32>(NvErrCodes::InvalidValue); | 174 | return NvResult::BadValue; |
| 164 | } | 175 | } |
| 165 | 176 | ||
| 166 | auto& object = itr->second; | 177 | auto& object = itr->second; |
| 167 | if (object->status != Object::Status::Allocated) { | 178 | if (object->status != Object::Status::Allocated) { |
| 168 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 179 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 169 | return static_cast<u32>(NvErrCodes::InvalidValue); | 180 | return NvResult::BadValue; |
| 170 | } | 181 | } |
| 171 | 182 | ||
| 172 | itr->second->refcount++; | 183 | itr->second->refcount++; |
| @@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 175 | params.handle = itr->first; | 186 | params.handle = itr->first; |
| 176 | 187 | ||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 188 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 178 | return 0; | 189 | return NvResult::Success; |
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | 192 | NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { |
| 182 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; | 193 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; |
| 183 | 194 | ||
| 184 | IocParamParams params; | 195 | IocParamParams params; |
| @@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 189 | auto object = GetObject(params.handle); | 200 | auto object = GetObject(params.handle); |
| 190 | if (!object) { | 201 | if (!object) { |
| 191 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 202 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 192 | return static_cast<u32>(NvErrCodes::InvalidValue); | 203 | return NvResult::BadValue; |
| 193 | } | 204 | } |
| 194 | 205 | ||
| 195 | if (object->status != Object::Status::Allocated) { | 206 | if (object->status != Object::Status::Allocated) { |
| 196 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 207 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 197 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 208 | return NvResult::BadValue; |
| 198 | } | 209 | } |
| 199 | 210 | ||
| 200 | switch (static_cast<ParamTypes>(params.param)) { | 211 | switch (static_cast<ParamTypes>(params.param)) { |
| @@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 216 | } | 227 | } |
| 217 | 228 | ||
| 218 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 229 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 219 | return 0; | 230 | return NvResult::Success; |
| 220 | } | 231 | } |
| 221 | 232 | ||
| 222 | u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | 233 | NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { |
| 223 | // TODO(Subv): These flags are unconfirmed. | 234 | // TODO(Subv): These flags are unconfirmed. |
| 224 | enum FreeFlags { | 235 | enum FreeFlags { |
| 225 | Freed = 0, | 236 | Freed = 0, |
| @@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 234 | auto itr = handles.find(params.handle); | 245 | auto itr = handles.find(params.handle); |
| 235 | if (itr == handles.end()) { | 246 | if (itr == handles.end()) { |
| 236 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 247 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 237 | return static_cast<u32>(NvErrCodes::InvalidValue); | 248 | return NvResult::BadValue; |
| 238 | } | 249 | } |
| 239 | if (!itr->second->refcount) { | 250 | if (!itr->second->refcount) { |
| 240 | LOG_ERROR( | 251 | LOG_ERROR( |
| 241 | Service_NVDRV, | 252 | Service_NVDRV, |
| 242 | "There is no references to this object. The object is already freed. handle={:08X}", | 253 | "There is no references to this object. The object is already freed. handle={:08X}", |
| 243 | params.handle); | 254 | params.handle); |
| 244 | return static_cast<u32>(NvErrCodes::InvalidValue); | 255 | return NvResult::BadValue; |
| 245 | } | 256 | } |
| 246 | 257 | ||
| 247 | itr->second->refcount--; | 258 | itr->second->refcount--; |
| @@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 261 | handles.erase(params.handle); | 272 | handles.erase(params.handle); |
| 262 | 273 | ||
| 263 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 274 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 264 | return 0; | 275 | return NvResult::Success; |
| 265 | } | 276 | } |
| 266 | 277 | ||
| 267 | } // namespace Service::Nvidia::Devices | 278 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 84624be00..4484bd79f 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -19,13 +19,15 @@ public: | |||
| 19 | explicit nvmap(Core::System& system); | 19 | explicit nvmap(Core::System& system); |
| 20 | ~nvmap() override; | 20 | ~nvmap() override; |
| 21 | 21 | ||
| 22 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | ||
| 23 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 24 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; | ||
| 25 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 26 | std::vector<u8>& inline_output) override; | ||
| 27 | |||
| 22 | /// Returns the allocated address of an nvmap object given its handle. | 28 | /// Returns the allocated address of an nvmap object given its handle. |
| 23 | VAddr GetObjectAddress(u32 handle) const; | 29 | VAddr GetObjectAddress(u32 handle) const; |
| 24 | 30 | ||
| 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 26 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 27 | IoctlVersion version) override; | ||
| 28 | |||
| 29 | /// Represents an nvmap object. | 31 | /// Represents an nvmap object. |
| 30 | struct Object { | 32 | struct Object { |
| 31 | enum class Status { Created, Allocated }; | 33 | enum class Status { Created, Allocated }; |
| @@ -37,6 +39,7 @@ public: | |||
| 37 | VAddr addr; | 39 | VAddr addr; |
| 38 | Status status; | 40 | Status status; |
| 39 | u32 refcount; | 41 | u32 refcount; |
| 42 | u32 dma_map_addr; | ||
| 40 | }; | 43 | }; |
| 41 | 44 | ||
| 42 | std::shared_ptr<Object> GetObject(u32 handle) const { | 45 | std::shared_ptr<Object> GetObject(u32 handle) const { |
| @@ -57,76 +60,68 @@ private: | |||
| 57 | /// Mapping of currently allocated handles to the objects they represent. | 60 | /// Mapping of currently allocated handles to the objects they represent. |
| 58 | std::unordered_map<u32, std::shared_ptr<Object>> handles; | 61 | std::unordered_map<u32, std::shared_ptr<Object>> handles; |
| 59 | 62 | ||
| 60 | enum class IoctlCommand : u32 { | ||
| 61 | Create = 0xC0080101, | ||
| 62 | FromId = 0xC0080103, | ||
| 63 | Alloc = 0xC0200104, | ||
| 64 | Free = 0xC0180105, | ||
| 65 | Param = 0xC00C0109, | ||
| 66 | GetId = 0xC008010E, | ||
| 67 | }; | ||
| 68 | struct IocCreateParams { | 63 | struct IocCreateParams { |
| 69 | // Input | 64 | // Input |
| 70 | u32_le size; | 65 | u32_le size{}; |
| 71 | // Output | 66 | // Output |
| 72 | u32_le handle; | 67 | u32_le handle{}; |
| 73 | }; | 68 | }; |
| 74 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); | 69 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); |
| 75 | 70 | ||
| 76 | struct IocFromIdParams { | 71 | struct IocFromIdParams { |
| 77 | // Input | 72 | // Input |
| 78 | u32_le id; | 73 | u32_le id{}; |
| 79 | // Output | 74 | // Output |
| 80 | u32_le handle; | 75 | u32_le handle{}; |
| 81 | }; | 76 | }; |
| 82 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); | 77 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); |
| 83 | 78 | ||
| 84 | struct IocAllocParams { | 79 | struct IocAllocParams { |
| 85 | // Input | 80 | // Input |
| 86 | u32_le handle; | 81 | u32_le handle{}; |
| 87 | u32_le heap_mask; | 82 | u32_le heap_mask{}; |
| 88 | u32_le flags; | 83 | u32_le flags{}; |
| 89 | u32_le align; | 84 | u32_le align{}; |
| 90 | u8 kind; | 85 | u8 kind{}; |
| 91 | INSERT_PADDING_BYTES(7); | 86 | INSERT_PADDING_BYTES(7); |
| 92 | u64_le addr; | 87 | u64_le addr{}; |
| 93 | }; | 88 | }; |
| 94 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); | 89 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); |
| 95 | 90 | ||
| 96 | struct IocFreeParams { | 91 | struct IocFreeParams { |
| 97 | u32_le handle; | 92 | u32_le handle{}; |
| 98 | INSERT_PADDING_BYTES(4); | 93 | INSERT_PADDING_BYTES(4); |
| 99 | u64_le address; | 94 | u64_le address{}; |
| 100 | u32_le size; | 95 | u32_le size{}; |
| 101 | u32_le flags; | 96 | u32_le flags{}; |
| 102 | }; | 97 | }; |
| 103 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); | 98 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); |
| 104 | 99 | ||
| 105 | struct IocParamParams { | 100 | struct IocParamParams { |
| 106 | // Input | 101 | // Input |
| 107 | u32_le handle; | 102 | u32_le handle{}; |
| 108 | u32_le param; | 103 | u32_le param{}; |
| 109 | // Output | 104 | // Output |
| 110 | u32_le result; | 105 | u32_le result{}; |
| 111 | }; | 106 | }; |
| 112 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); | 107 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); |
| 113 | 108 | ||
| 114 | struct IocGetIdParams { | 109 | struct IocGetIdParams { |
| 115 | // Output | 110 | // Output |
| 116 | u32_le id; | 111 | u32_le id{}; |
| 117 | // Input | 112 | // Input |
| 118 | u32_le handle; | 113 | u32_le handle{}; |
| 119 | }; | 114 | }; |
| 120 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 115 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 121 | 116 | ||
| 122 | u32 CreateObject(u32 size); | 117 | u32 CreateObject(u32 size); |
| 123 | 118 | ||
| 124 | u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); | 119 | NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); |
| 125 | u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); | 120 | NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); |
| 126 | u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); | 121 | NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); |
| 127 | u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); | 122 | NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); |
| 128 | u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); |
| 129 | u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); | 124 | NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output); |
| 130 | }; | 125 | }; |
| 131 | 126 | ||
| 132 | } // namespace Service::Nvidia::Devices | 127 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 88fbfa9b0..cc23b001c 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -23,124 +23,167 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 24 | LOG_DEBUG(Service_NVDRV, "called"); | 24 | LOG_DEBUG(Service_NVDRV, "called"); |
| 25 | 25 | ||
| 26 | if (!is_initialized) { | ||
| 27 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 28 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 26 | const auto& buffer = ctx.ReadBuffer(); | 32 | const auto& buffer = ctx.ReadBuffer(); |
| 27 | std::string device_name(buffer.begin(), buffer.end()); | 33 | const std::string device_name(buffer.begin(), buffer.end()); |
| 34 | DeviceFD fd = nvdrv->Open(device_name); | ||
| 28 | 35 | ||
| 29 | u32 fd = nvdrv->Open(device_name); | ||
| 30 | IPC::ResponseBuilder rb{ctx, 4}; | 36 | IPC::ResponseBuilder rb{ctx, 4}; |
| 31 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 32 | rb.Push<u32>(fd); | 38 | rb.Push<DeviceFD>(fd); |
| 33 | rb.Push<u32>(0); | 39 | rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); |
| 40 | } | ||
| 41 | |||
| 42 | void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { | ||
| 43 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 44 | rb.Push(RESULT_SUCCESS); | ||
| 45 | rb.PushEnum(result); | ||
| 34 | } | 46 | } |
| 35 | 47 | ||
| 36 | void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { | 48 | void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { |
| 37 | IPC::RequestParser rp{ctx}; | 49 | IPC::RequestParser rp{ctx}; |
| 38 | u32 fd = rp.Pop<u32>(); | 50 | const auto fd = rp.Pop<DeviceFD>(); |
| 39 | u32 command = rp.Pop<u32>(); | 51 | const auto command = rp.PopRaw<Ioctl>(); |
| 40 | 52 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | |
| 41 | /// Ioctl 3 has 2 outputs, first in the input params, second is the result | 53 | |
| 42 | std::vector<u8> output(ctx.GetWriteBufferSize(0)); | 54 | if (!is_initialized) { |
| 43 | std::vector<u8> output2; | 55 | ServiceError(ctx, NvResult::NotInitialized); |
| 44 | if (version == IoctlVersion::Version3) { | 56 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); |
| 45 | output2.resize((ctx.GetWriteBufferSize(1))); | 57 | return; |
| 46 | } | 58 | } |
| 47 | 59 | ||
| 48 | /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. | 60 | // Check device |
| 49 | /// KickOfPB uses this | 61 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); |
| 50 | auto input = ctx.ReadBuffer(0); | 62 | const auto input_buffer = ctx.ReadBuffer(0); |
| 51 | 63 | ||
| 52 | std::vector<u8> input2; | 64 | const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); |
| 53 | if (version == IoctlVersion::Version2) { | 65 | if (command.is_out != 0) { |
| 54 | input2 = ctx.ReadBuffer(1); | 66 | ctx.WriteBuffer(output_buffer); |
| 55 | } | 67 | } |
| 56 | 68 | ||
| 57 | IoctlCtrl ctrl{}; | ||
| 58 | |||
| 59 | u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); | ||
| 60 | |||
| 61 | if (ctrl.must_delay) { | ||
| 62 | ctrl.fresh_call = false; | ||
| 63 | ctx.SleepClientThread( | ||
| 64 | "NVServices::DelayedResponse", ctrl.timeout, | ||
| 65 | [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_, | ||
| 66 | Kernel::ThreadWakeupReason reason) { | ||
| 67 | IoctlCtrl ctrl2{ctrl}; | ||
| 68 | std::vector<u8> tmp_output = output; | ||
| 69 | std::vector<u8> tmp_output2 = output2; | ||
| 70 | const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, | ||
| 71 | tmp_output2, ctrl2, version); | ||
| 72 | ctx_.WriteBuffer(tmp_output, 0); | ||
| 73 | if (version == IoctlVersion::Version3) { | ||
| 74 | ctx_.WriteBuffer(tmp_output2, 1); | ||
| 75 | } | ||
| 76 | IPC::ResponseBuilder rb{ctx_, 3}; | ||
| 77 | rb.Push(RESULT_SUCCESS); | ||
| 78 | rb.Push(ioctl_result); | ||
| 79 | }, | ||
| 80 | nvdrv->GetEventWriteable(ctrl.event_id)); | ||
| 81 | } else { | ||
| 82 | ctx.WriteBuffer(output); | ||
| 83 | if (version == IoctlVersion::Version3) { | ||
| 84 | ctx.WriteBuffer(output2, 1); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | 69 | IPC::ResponseBuilder rb{ctx, 3}; |
| 88 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.Push(result); | 71 | rb.PushEnum(nv_result); |
| 90 | } | ||
| 91 | |||
| 92 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | ||
| 93 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 94 | IoctlBase(ctx, IoctlVersion::Version1); | ||
| 95 | } | 72 | } |
| 96 | 73 | ||
| 97 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { | 74 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { |
| 98 | LOG_DEBUG(Service_NVDRV, "called"); | 75 | IPC::RequestParser rp{ctx}; |
| 99 | IoctlBase(ctx, IoctlVersion::Version2); | 76 | const auto fd = rp.Pop<DeviceFD>(); |
| 77 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 78 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 79 | |||
| 80 | if (!is_initialized) { | ||
| 81 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 82 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 87 | const auto input_inlined_buffer = ctx.ReadBuffer(1); | ||
| 88 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 89 | |||
| 90 | const auto nv_result = | ||
| 91 | nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); | ||
| 92 | if (command.is_out != 0) { | ||
| 93 | ctx.WriteBuffer(output_buffer); | ||
| 94 | } | ||
| 95 | |||
| 96 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 97 | rb.Push(RESULT_SUCCESS); | ||
| 98 | rb.PushEnum(nv_result); | ||
| 100 | } | 99 | } |
| 101 | 100 | ||
| 102 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { | 101 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { |
| 103 | LOG_DEBUG(Service_NVDRV, "called"); | 102 | IPC::RequestParser rp{ctx}; |
| 104 | IoctlBase(ctx, IoctlVersion::Version3); | 103 | const auto fd = rp.Pop<DeviceFD>(); |
| 104 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 105 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 106 | |||
| 107 | if (!is_initialized) { | ||
| 108 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 109 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | |||
| 113 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 114 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 115 | std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); | ||
| 116 | |||
| 117 | const auto nv_result = | ||
| 118 | nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); | ||
| 119 | if (command.is_out != 0) { | ||
| 120 | ctx.WriteBuffer(output_buffer, 0); | ||
| 121 | ctx.WriteBuffer(output_buffer_inline, 1); | ||
| 122 | } | ||
| 123 | |||
| 124 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 125 | rb.Push(RESULT_SUCCESS); | ||
| 126 | rb.PushEnum(nv_result); | ||
| 105 | } | 127 | } |
| 106 | 128 | ||
| 107 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 129 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| 108 | LOG_DEBUG(Service_NVDRV, "called"); | 130 | LOG_DEBUG(Service_NVDRV, "called"); |
| 109 | 131 | ||
| 110 | IPC::RequestParser rp{ctx}; | 132 | if (!is_initialized) { |
| 111 | u32 fd = rp.Pop<u32>(); | 133 | ServiceError(ctx, NvResult::NotInitialized); |
| 134 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 135 | return; | ||
| 136 | } | ||
| 112 | 137 | ||
| 113 | auto result = nvdrv->Close(fd); | 138 | IPC::RequestParser rp{ctx}; |
| 139 | const auto fd = rp.Pop<DeviceFD>(); | ||
| 140 | const auto result = nvdrv->Close(fd); | ||
| 114 | 141 | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 142 | IPC::ResponseBuilder rb{ctx, 3}; |
| 116 | rb.Push(result); | 143 | rb.Push(RESULT_SUCCESS); |
| 144 | rb.PushEnum(result); | ||
| 117 | } | 145 | } |
| 118 | 146 | ||
| 119 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 147 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 120 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 148 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 121 | 149 | ||
| 150 | is_initialized = true; | ||
| 151 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 3}; | 152 | IPC::ResponseBuilder rb{ctx, 3}; |
| 123 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| 124 | rb.Push<u32>(0); | 154 | rb.PushEnum(NvResult::Success); |
| 125 | } | 155 | } |
| 126 | 156 | ||
| 127 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | 157 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { |
| 128 | IPC::RequestParser rp{ctx}; | 158 | IPC::RequestParser rp{ctx}; |
| 129 | u32 fd = rp.Pop<u32>(); | 159 | const auto fd = rp.Pop<DeviceFD>(); |
| 130 | // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 | 160 | const auto event_id = rp.Pop<u32>() & 0x00FF; |
| 131 | u32 event_id = rp.Pop<u32>() & 0x000000FF; | ||
| 132 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); | 161 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); |
| 133 | 162 | ||
| 134 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 163 | if (!is_initialized) { |
| 135 | rb.Push(RESULT_SUCCESS); | 164 | ServiceError(ctx, NvResult::NotInitialized); |
| 165 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 166 | return; | ||
| 167 | } | ||
| 168 | |||
| 169 | const auto nv_result = nvdrv->VerifyFD(fd); | ||
| 170 | if (nv_result != NvResult::Success) { | ||
| 171 | LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); | ||
| 172 | ServiceError(ctx, nv_result); | ||
| 173 | return; | ||
| 174 | } | ||
| 175 | |||
| 136 | if (event_id < MaxNvEvents) { | 176 | if (event_id < MaxNvEvents) { |
| 177 | IPC::ResponseBuilder rb{ctx, 3, 1}; | ||
| 178 | rb.Push(RESULT_SUCCESS); | ||
| 137 | auto event = nvdrv->GetEvent(event_id); | 179 | auto event = nvdrv->GetEvent(event_id); |
| 138 | event->Clear(); | 180 | event->Clear(); |
| 139 | rb.PushCopyObjects(event); | 181 | rb.PushCopyObjects(event); |
| 140 | rb.Push<u32>(NvResult::Success); | 182 | rb.PushEnum(NvResult::Success); |
| 141 | } else { | 183 | } else { |
| 142 | rb.Push<u32>(0); | 184 | IPC::ResponseBuilder rb{ctx, 3}; |
| 143 | rb.Push<u32>(NvResult::BadParameter); | 185 | rb.Push(RESULT_SUCCESS); |
| 186 | rb.PushEnum(NvResult::BadParameter); | ||
| 144 | } | 187 | } |
| 145 | } | 188 | } |
| 146 | 189 | ||
| @@ -151,7 +194,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { | |||
| 151 | 194 | ||
| 152 | IPC::ResponseBuilder rb{ctx, 3}; | 195 | IPC::ResponseBuilder rb{ctx, 3}; |
| 153 | rb.Push(RESULT_SUCCESS); | 196 | rb.Push(RESULT_SUCCESS); |
| 154 | rb.Push<u32>(0); | 197 | rb.PushEnum(NvResult::Success); |
| 155 | } | 198 | } |
| 156 | 199 | ||
| 157 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { | 200 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -164,8 +207,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct | |||
| 164 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { | 207 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 208 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 166 | 209 | ||
| 167 | IPC::ResponseBuilder rb{ctx, 2}; | 210 | IPC::ResponseBuilder rb{ctx, 3}; |
| 168 | rb.Push(RESULT_SUCCESS); | 211 | rb.Push(RESULT_SUCCESS); |
| 212 | rb.PushEnum(NvResult::Success); | ||
| 169 | } | 213 | } |
| 170 | 214 | ||
| 171 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | 215 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { |
| @@ -177,11 +221,11 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | |||
| 177 | rb.Push(RESULT_SUCCESS); | 221 | rb.Push(RESULT_SUCCESS); |
| 178 | } | 222 | } |
| 179 | 223 | ||
| 180 | NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | 224 | NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name) |
| 181 | : ServiceFramework(name), nvdrv(std::move(nvdrv)) { | 225 | : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} { |
| 182 | static const FunctionInfo functions[] = { | 226 | static const FunctionInfo functions[] = { |
| 183 | {0, &NVDRV::Open, "Open"}, | 227 | {0, &NVDRV::Open, "Open"}, |
| 184 | {1, &NVDRV::Ioctl, "Ioctl"}, | 228 | {1, &NVDRV::Ioctl1, "Ioctl"}, |
| 185 | {2, &NVDRV::Close, "Close"}, | 229 | {2, &NVDRV::Close, "Close"}, |
| 186 | {3, &NVDRV::Initialize, "Initialize"}, | 230 | {3, &NVDRV::Initialize, "Initialize"}, |
| 187 | {4, &NVDRV::QueryEvent, "QueryEvent"}, | 231 | {4, &NVDRV::QueryEvent, "QueryEvent"}, |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 72e17a728..5c777c59b 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -16,14 +16,14 @@ namespace Service::Nvidia { | |||
| 16 | 16 | ||
| 17 | class NVDRV final : public ServiceFramework<NVDRV> { | 17 | class NVDRV final : public ServiceFramework<NVDRV> { |
| 18 | public: | 18 | public: |
| 19 | NVDRV(std::shared_ptr<Module> nvdrv, const char* name); | 19 | explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name); |
| 20 | ~NVDRV() override; | 20 | ~NVDRV() override; |
| 21 | 21 | ||
| 22 | void SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value); | 22 | void SignalGPUInterruptSyncpt(u32 syncpoint_id, u32 value); |
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void Open(Kernel::HLERequestContext& ctx); | 25 | void Open(Kernel::HLERequestContext& ctx); |
| 26 | void Ioctl(Kernel::HLERequestContext& ctx); | 26 | void Ioctl1(Kernel::HLERequestContext& ctx); |
| 27 | void Ioctl2(Kernel::HLERequestContext& ctx); | 27 | void Ioctl2(Kernel::HLERequestContext& ctx); |
| 28 | void Ioctl3(Kernel::HLERequestContext& ctx); | 28 | void Ioctl3(Kernel::HLERequestContext& ctx); |
| 29 | void Close(Kernel::HLERequestContext& ctx); | 29 | void Close(Kernel::HLERequestContext& ctx); |
| @@ -33,11 +33,13 @@ private: | |||
| 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); | 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); |
| 34 | void GetStatus(Kernel::HLERequestContext& ctx); | 34 | void GetStatus(Kernel::HLERequestContext& ctx); |
| 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); |
| 36 | void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); | 36 | |
| 37 | void ServiceError(Kernel::HLERequestContext& ctx, NvResult result); | ||
| 37 | 38 | ||
| 38 | std::shared_ptr<Module> nvdrv; | 39 | std::shared_ptr<Module> nvdrv; |
| 39 | 40 | ||
| 40 | u64 pid{}; | 41 | u64 pid{}; |
| 42 | bool is_initialized{}; | ||
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 43 | } // namespace Service::Nvidia | 45 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 529b03471..3294bc0e7 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include <array> | 3 | #include <array> |
| 4 | #include "common/bit_field.h" | ||
| 4 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 5 | 6 | ||
| 6 | namespace Service::Nvidia { | 7 | namespace Service::Nvidia { |
| 7 | 8 | ||
| 8 | constexpr u32 MaxSyncPoints = 192; | 9 | constexpr u32 MaxSyncPoints = 192; |
| 9 | constexpr u32 MaxNvEvents = 64; | 10 | constexpr u32 MaxNvEvents = 64; |
| 11 | using DeviceFD = s32; | ||
| 12 | |||
| 13 | constexpr DeviceFD INVALID_NVDRV_FD = -1; | ||
| 10 | 14 | ||
| 11 | struct Fence { | 15 | struct Fence { |
| 12 | s32 id; | 16 | s32 id; |
| @@ -20,11 +24,61 @@ struct MultiFence { | |||
| 20 | std::array<Fence, 4> fences; | 24 | std::array<Fence, 4> fences; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | enum NvResult : u32 { | 27 | enum class NvResult : u32 { |
| 24 | Success = 0, | 28 | Success = 0x0, |
| 25 | BadParameter = 4, | 29 | NotImplemented = 0x1, |
| 26 | Timeout = 5, | 30 | NotSupported = 0x2, |
| 27 | ResourceError = 15, | 31 | NotInitialized = 0x3, |
| 32 | BadParameter = 0x4, | ||
| 33 | Timeout = 0x5, | ||
| 34 | InsufficientMemory = 0x6, | ||
| 35 | ReadOnlyAttribute = 0x7, | ||
| 36 | InvalidState = 0x8, | ||
| 37 | InvalidAddress = 0x9, | ||
| 38 | InvalidSize = 0xA, | ||
| 39 | BadValue = 0xB, | ||
| 40 | AlreadyAllocated = 0xD, | ||
| 41 | Busy = 0xE, | ||
| 42 | ResourceError = 0xF, | ||
| 43 | CountMismatch = 0x10, | ||
| 44 | OverFlow = 0x11, | ||
| 45 | InsufficientTransferMemory = 0x1000, | ||
| 46 | InsufficientVideoMemory = 0x10000, | ||
| 47 | BadSurfaceColorScheme = 0x10001, | ||
| 48 | InvalidSurface = 0x10002, | ||
| 49 | SurfaceNotSupported = 0x10003, | ||
| 50 | DispInitFailed = 0x20000, | ||
| 51 | DispAlreadyAttached = 0x20001, | ||
| 52 | DispTooManyDisplays = 0x20002, | ||
| 53 | DispNoDisplaysAttached = 0x20003, | ||
| 54 | DispModeNotSupported = 0x20004, | ||
| 55 | DispNotFound = 0x20005, | ||
| 56 | DispAttachDissallowed = 0x20006, | ||
| 57 | DispTypeNotSupported = 0x20007, | ||
| 58 | DispAuthenticationFailed = 0x20008, | ||
| 59 | DispNotAttached = 0x20009, | ||
| 60 | DispSamePwrState = 0x2000A, | ||
| 61 | DispEdidFailure = 0x2000B, | ||
| 62 | DispDsiReadAckError = 0x2000C, | ||
| 63 | DispDsiReadInvalidResp = 0x2000D, | ||
| 64 | FileWriteFailed = 0x30000, | ||
| 65 | FileReadFailed = 0x30001, | ||
| 66 | EndOfFile = 0x30002, | ||
| 67 | FileOperationFailed = 0x30003, | ||
| 68 | DirOperationFailed = 0x30004, | ||
| 69 | EndOfDirList = 0x30005, | ||
| 70 | ConfigVarNotFound = 0x30006, | ||
| 71 | InvalidConfigVar = 0x30007, | ||
| 72 | LibraryNotFound = 0x30008, | ||
| 73 | SymbolNotFound = 0x30009, | ||
| 74 | MemoryMapFailed = 0x3000A, | ||
| 75 | IoctlFailed = 0x3000F, | ||
| 76 | AccessDenied = 0x30010, | ||
| 77 | DeviceNotFound = 0x30011, | ||
| 78 | KernelDriverNotFound = 0x30012, | ||
| 79 | FileNotFound = 0x30013, | ||
| 80 | PathAlreadyExists = 0x30014, | ||
| 81 | ModuleNotPresent = 0xA000E, | ||
| 28 | }; | 82 | }; |
| 29 | 83 | ||
| 30 | enum class EventState { | 84 | enum class EventState { |
| @@ -34,21 +88,13 @@ enum class EventState { | |||
| 34 | Busy = 3, | 88 | Busy = 3, |
| 35 | }; | 89 | }; |
| 36 | 90 | ||
| 37 | enum class IoctlVersion : u32 { | 91 | union Ioctl { |
| 38 | Version1, | 92 | u32_le raw; |
| 39 | Version2, | 93 | BitField<0, 8, u32> cmd; |
| 40 | Version3, | 94 | BitField<8, 8, u32> group; |
| 41 | }; | 95 | BitField<16, 14, u32> length; |
| 42 | 96 | BitField<30, 1, u32> is_in; | |
| 43 | struct IoctlCtrl { | 97 | BitField<31, 1, u32> is_out; |
| 44 | // First call done to the servioce for services that call itself again after a call. | ||
| 45 | bool fresh_call{true}; | ||
| 46 | // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep | ||
| 47 | bool must_delay{}; | ||
| 48 | // Timeout for the delay | ||
| 49 | s64 timeout{}; | ||
| 50 | // NV Event Id | ||
| 51 | s32 event_id{-1}; | ||
| 52 | }; | 98 | }; |
| 53 | 99 | ||
| 54 | } // namespace Service::Nvidia | 100 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 197c77db0..620c18728 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <utility> | 5 | #include <utility> |
| 6 | 6 | ||
| 7 | #include <fmt/format.h> | 7 | #include <fmt/format.h> |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/readable_event.h" | 10 | #include "core/hle/kernel/readable_event.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/writable_event.h" |
| @@ -21,6 +22,7 @@ | |||
| 21 | #include "core/hle/service/nvdrv/interface.h" | 22 | #include "core/hle/service/nvdrv/interface.h" |
| 22 | #include "core/hle/service/nvdrv/nvdrv.h" | 23 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 23 | #include "core/hle/service/nvdrv/nvmemp.h" | 24 | #include "core/hle/service/nvdrv/nvmemp.h" |
| 25 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 24 | #include "core/hle/service/nvflinger/nvflinger.h" | 26 | #include "core/hle/service/nvflinger/nvflinger.h" |
| 25 | 27 | ||
| 26 | namespace Service::Nvidia { | 28 | namespace Service::Nvidia { |
| @@ -28,66 +30,135 @@ namespace Service::Nvidia { | |||
| 28 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, | 30 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 29 | Core::System& system) { | 31 | Core::System& system) { |
| 30 | auto module_ = std::make_shared<Module>(system); | 32 | auto module_ = std::make_shared<Module>(system); |
| 31 | std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); | 33 | std::make_shared<NVDRV>(system, module_, "nvdrv")->InstallAsService(service_manager); |
| 32 | std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); | 34 | std::make_shared<NVDRV>(system, module_, "nvdrv:a")->InstallAsService(service_manager); |
| 33 | std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); | 35 | std::make_shared<NVDRV>(system, module_, "nvdrv:s")->InstallAsService(service_manager); |
| 34 | std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); | 36 | std::make_shared<NVDRV>(system, module_, "nvdrv:t")->InstallAsService(service_manager); |
| 35 | std::make_shared<NVMEMP>()->InstallAsService(service_manager); | 37 | std::make_shared<NVMEMP>(system)->InstallAsService(service_manager); |
| 36 | nvflinger.SetNVDrvInstance(module_); | 38 | nvflinger.SetNVDrvInstance(module_); |
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | Module::Module(Core::System& system) { | 41 | Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { |
| 40 | auto& kernel = system.Kernel(); | 42 | auto& kernel = system.Kernel(); |
| 41 | for (u32 i = 0; i < MaxNvEvents; i++) { | 43 | for (u32 i = 0; i < MaxNvEvents; i++) { |
| 42 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); | 44 | std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); |
| 43 | events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label); | 45 | events_interface.events[i] = {Kernel::WritableEvent::CreateEventPair(kernel, event_label)}; |
| 44 | events_interface.status[i] = EventState::Free; | 46 | events_interface.status[i] = EventState::Free; |
| 45 | events_interface.registered[i] = false; | 47 | events_interface.registered[i] = false; |
| 46 | } | 48 | } |
| 47 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); | 49 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); |
| 48 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); | 50 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); |
| 49 | devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev); | 51 | devices["/dev/nvhost-gpu"] = |
| 52 | std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager); | ||
| 50 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); | 53 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); |
| 51 | devices["/dev/nvmap"] = nvmap_dev; | 54 | devices["/dev/nvmap"] = nvmap_dev; |
| 52 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); | 55 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); |
| 53 | devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); | 56 | devices["/dev/nvhost-ctrl"] = |
| 54 | devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system); | 57 | std::make_shared<Devices::nvhost_ctrl>(system, events_interface, syncpoint_manager); |
| 58 | devices["/dev/nvhost-nvdec"] = | ||
| 59 | std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev, syncpoint_manager); | ||
| 55 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); | 60 | devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); |
| 56 | devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system); | 61 | devices["/dev/nvhost-vic"] = |
| 62 | std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager); | ||
| 57 | } | 63 | } |
| 58 | 64 | ||
| 59 | Module::~Module() = default; | 65 | Module::~Module() = default; |
| 60 | 66 | ||
| 61 | u32 Module::Open(const std::string& device_name) { | 67 | NvResult Module::VerifyFD(DeviceFD fd) const { |
| 62 | ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", | 68 | if (fd < 0) { |
| 63 | device_name); | 69 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 70 | return NvResult::InvalidState; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (open_files.find(fd) == open_files.end()) { | ||
| 74 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 75 | return NvResult::NotImplemented; | ||
| 76 | } | ||
| 77 | |||
| 78 | return NvResult::Success; | ||
| 79 | } | ||
| 80 | |||
| 81 | DeviceFD Module::Open(const std::string& device_name) { | ||
| 82 | if (devices.find(device_name) == devices.end()) { | ||
| 83 | LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); | ||
| 84 | return INVALID_NVDRV_FD; | ||
| 85 | } | ||
| 64 | 86 | ||
| 65 | auto device = devices[device_name]; | 87 | auto device = devices[device_name]; |
| 66 | const u32 fd = next_fd++; | 88 | const DeviceFD fd = next_fd++; |
| 67 | 89 | ||
| 68 | open_files[fd] = std::move(device); | 90 | open_files[fd] = std::move(device); |
| 69 | 91 | ||
| 70 | return fd; | 92 | return fd; |
| 71 | } | 93 | } |
| 72 | 94 | ||
| 73 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 95 | NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 74 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 96 | std::vector<u8>& output) { |
| 75 | IoctlVersion version) { | 97 | if (fd < 0) { |
| 76 | auto itr = open_files.find(fd); | 98 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 77 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 99 | return NvResult::InvalidState; |
| 100 | } | ||
| 78 | 101 | ||
| 79 | auto& device = itr->second; | 102 | const auto itr = open_files.find(fd); |
| 80 | return device->ioctl({command}, input, input2, output, output2, ctrl, version); | 103 | |
| 104 | if (itr == open_files.end()) { | ||
| 105 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 106 | return NvResult::NotImplemented; | ||
| 107 | } | ||
| 108 | |||
| 109 | return itr->second->Ioctl1(command, input, output); | ||
| 81 | } | 110 | } |
| 82 | 111 | ||
| 83 | ResultCode Module::Close(u32 fd) { | 112 | NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 84 | auto itr = open_files.find(fd); | 113 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 85 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 114 | if (fd < 0) { |
| 115 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 116 | return NvResult::InvalidState; | ||
| 117 | } | ||
| 118 | |||
| 119 | const auto itr = open_files.find(fd); | ||
| 120 | |||
| 121 | if (itr == open_files.end()) { | ||
| 122 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 123 | return NvResult::NotImplemented; | ||
| 124 | } | ||
| 125 | |||
| 126 | return itr->second->Ioctl2(command, input, inline_input, output); | ||
| 127 | } | ||
| 128 | |||
| 129 | NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 130 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 131 | if (fd < 0) { | ||
| 132 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 133 | return NvResult::InvalidState; | ||
| 134 | } | ||
| 135 | |||
| 136 | const auto itr = open_files.find(fd); | ||
| 137 | |||
| 138 | if (itr == open_files.end()) { | ||
| 139 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 140 | return NvResult::NotImplemented; | ||
| 141 | } | ||
| 142 | |||
| 143 | return itr->second->Ioctl3(command, input, output, inline_output); | ||
| 144 | } | ||
| 145 | |||
| 146 | NvResult Module::Close(DeviceFD fd) { | ||
| 147 | if (fd < 0) { | ||
| 148 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 149 | return NvResult::InvalidState; | ||
| 150 | } | ||
| 151 | |||
| 152 | const auto itr = open_files.find(fd); | ||
| 153 | |||
| 154 | if (itr == open_files.end()) { | ||
| 155 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 156 | return NvResult::NotImplemented; | ||
| 157 | } | ||
| 86 | 158 | ||
| 87 | open_files.erase(itr); | 159 | open_files.erase(itr); |
| 88 | 160 | ||
| 89 | // TODO(flerovium): return correct result code if operation failed. | 161 | return NvResult::Success; |
| 90 | return RESULT_SUCCESS; | ||
| 91 | } | 162 | } |
| 92 | 163 | ||
| 93 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | 164 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { |
| @@ -95,17 +166,17 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 95 | if (events_interface.assigned_syncpt[i] == syncpoint_id && | 166 | if (events_interface.assigned_syncpt[i] == syncpoint_id && |
| 96 | events_interface.assigned_value[i] == value) { | 167 | events_interface.assigned_value[i] == value) { |
| 97 | events_interface.LiberateEvent(i); | 168 | events_interface.LiberateEvent(i); |
| 98 | events_interface.events[i].writable->Signal(); | 169 | events_interface.events[i].event.writable->Signal(); |
| 99 | } | 170 | } |
| 100 | } | 171 | } |
| 101 | } | 172 | } |
| 102 | 173 | ||
| 103 | std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { | 174 | std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { |
| 104 | return events_interface.events[event_id].readable; | 175 | return events_interface.events[event_id].event.readable; |
| 105 | } | 176 | } |
| 106 | 177 | ||
| 107 | std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { | 178 | std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { |
| 108 | return events_interface.events[event_id].writable; | 179 | return events_interface.events[event_id].event.writable; |
| 109 | } | 180 | } |
| 110 | 181 | ||
| 111 | } // namespace Service::Nvidia | 182 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 7706a5590..144e657e5 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/writable_event.h" | 11 | #include "core/hle/kernel/writable_event.h" |
| 12 | #include "core/hle/service/nvdrv/nvdata.h" | 12 | #include "core/hle/service/nvdrv/nvdata.h" |
| 13 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 13 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 14 | 15 | ||
| 15 | namespace Core { | 16 | namespace Core { |
| @@ -22,15 +23,23 @@ class NVFlinger; | |||
| 22 | 23 | ||
| 23 | namespace Service::Nvidia { | 24 | namespace Service::Nvidia { |
| 24 | 25 | ||
| 26 | class SyncpointManager; | ||
| 27 | |||
| 25 | namespace Devices { | 28 | namespace Devices { |
| 26 | class nvdevice; | 29 | class nvdevice; |
| 27 | } | 30 | } |
| 28 | 31 | ||
| 32 | /// Represents an Nvidia event | ||
| 33 | struct NvEvent { | ||
| 34 | Kernel::EventPair event; | ||
| 35 | Fence fence{}; | ||
| 36 | }; | ||
| 37 | |||
| 29 | struct EventInterface { | 38 | struct EventInterface { |
| 30 | // Mask representing currently busy events | 39 | // Mask representing currently busy events |
| 31 | u64 events_mask{}; | 40 | u64 events_mask{}; |
| 32 | // Each kernel event associated to an NV event | 41 | // Each kernel event associated to an NV event |
| 33 | std::array<Kernel::EventPair, MaxNvEvents> events; | 42 | std::array<NvEvent, MaxNvEvents> events; |
| 34 | // The status of the current NVEvent | 43 | // The status of the current NVEvent |
| 35 | std::array<EventState, MaxNvEvents> status{}; | 44 | std::array<EventState, MaxNvEvents> status{}; |
| 36 | // Tells if an NVEvent is registered or not | 45 | // Tells if an NVEvent is registered or not |
| @@ -91,7 +100,7 @@ struct EventInterface { | |||
| 91 | 100 | ||
| 92 | class Module final { | 101 | class Module final { |
| 93 | public: | 102 | public: |
| 94 | Module(Core::System& system); | 103 | explicit Module(Core::System& system_); |
| 95 | ~Module(); | 104 | ~Module(); |
| 96 | 105 | ||
| 97 | /// Returns a pointer to one of the available devices, identified by its name. | 106 | /// Returns a pointer to one of the available devices, identified by its name. |
| @@ -103,14 +112,23 @@ public: | |||
| 103 | return std::static_pointer_cast<T>(itr->second); | 112 | return std::static_pointer_cast<T>(itr->second); |
| 104 | } | 113 | } |
| 105 | 114 | ||
| 115 | NvResult VerifyFD(DeviceFD fd) const; | ||
| 116 | |||
| 106 | /// Opens a device node and returns a file descriptor to it. | 117 | /// Opens a device node and returns a file descriptor to it. |
| 107 | u32 Open(const std::string& device_name); | 118 | DeviceFD Open(const std::string& device_name); |
| 119 | |||
| 108 | /// Sends an ioctl command to the specified file descriptor. | 120 | /// Sends an ioctl command to the specified file descriptor. |
| 109 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 121 | NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 110 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 122 | std::vector<u8>& output); |
| 111 | IoctlVersion version); | 123 | |
| 124 | NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 125 | const std::vector<u8>& inline_input, std::vector<u8>& output); | ||
| 126 | |||
| 127 | NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 128 | std::vector<u8>& output, std::vector<u8>& inline_output); | ||
| 129 | |||
| 112 | /// Closes a device file descriptor and returns operation success. | 130 | /// Closes a device file descriptor and returns operation success. |
| 113 | ResultCode Close(u32 fd); | 131 | NvResult Close(DeviceFD fd); |
| 114 | 132 | ||
| 115 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); | 133 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); |
| 116 | 134 | ||
| @@ -119,11 +137,14 @@ public: | |||
| 119 | std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; | 137 | std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; |
| 120 | 138 | ||
| 121 | private: | 139 | private: |
| 140 | /// Manages syncpoints on the host | ||
| 141 | SyncpointManager syncpoint_manager; | ||
| 142 | |||
| 122 | /// Id to use for the next open file descriptor. | 143 | /// Id to use for the next open file descriptor. |
| 123 | u32 next_fd = 1; | 144 | DeviceFD next_fd = 1; |
| 124 | 145 | ||
| 125 | /// Mapping of file descriptors to the devices they reference. | 146 | /// Mapping of file descriptors to the devices they reference. |
| 126 | std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; | 147 | std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; |
| 127 | 148 | ||
| 128 | /// Mapping of device node names to their implementation. | 149 | /// Mapping of device node names to their implementation. |
| 129 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 150 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; |
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index 73b37e805..331c02243 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::Nvidia { | 9 | namespace Service::Nvidia { |
| 10 | 10 | ||
| 11 | NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { | 11 | NVMEMP::NVMEMP(Core::System& system_) : ServiceFramework{system_, "nvmemp"} { |
| 12 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 13 | {0, &NVMEMP::Open, "Open"}, | 13 | {0, &NVMEMP::Open, "Open"}, |
| 14 | {1, &NVMEMP::GetAruid, "GetAruid"}, | 14 | {1, &NVMEMP::GetAruid, "GetAruid"}, |
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index c453ee4db..724c27ef9 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Nvidia { | 13 | namespace Service::Nvidia { |
| 10 | 14 | ||
| 11 | class NVMEMP final : public ServiceFramework<NVMEMP> { | 15 | class NVMEMP final : public ServiceFramework<NVMEMP> { |
| 12 | public: | 16 | public: |
| 13 | NVMEMP(); | 17 | explicit NVMEMP(Core::System& system_); |
| 14 | ~NVMEMP() override; | 18 | ~NVMEMP() override; |
| 15 | 19 | ||
| 16 | private: | 20 | private: |
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp new file mode 100644 index 000000000..0151a03b7 --- /dev/null +++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // Copyright 2020 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/hle/service/nvdrv/syncpoint_manager.h" | ||
| 7 | #include "video_core/gpu.h" | ||
| 8 | |||
| 9 | namespace Service::Nvidia { | ||
| 10 | |||
| 11 | SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {} | ||
| 12 | |||
| 13 | SyncpointManager::~SyncpointManager() = default; | ||
| 14 | |||
| 15 | u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) { | ||
| 16 | syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id); | ||
| 17 | return GetSyncpointMin(syncpoint_id); | ||
| 18 | } | ||
| 19 | |||
| 20 | u32 SyncpointManager::AllocateSyncpoint() { | ||
| 21 | for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) { | ||
| 22 | if (!syncpoints[syncpoint_id].is_allocated) { | ||
| 23 | syncpoints[syncpoint_id].is_allocated = true; | ||
| 24 | return syncpoint_id; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | UNREACHABLE_MSG("No more available syncpoints!"); | ||
| 28 | return {}; | ||
| 29 | } | ||
| 30 | |||
| 31 | u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) { | ||
| 32 | for (u32 index = 0; index < value; ++index) { | ||
| 33 | syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed); | ||
| 34 | } | ||
| 35 | |||
| 36 | return GetSyncpointMax(syncpoint_id); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h new file mode 100644 index 000000000..d395c5d0b --- /dev/null +++ b/src/core/hle/service/nvdrv/syncpoint_manager.h | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | // Copyright 2020 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 <atomic> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/service/nvdrv/nvdata.h" | ||
| 12 | |||
| 13 | namespace Tegra { | ||
| 14 | class GPU; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Service::Nvidia { | ||
| 18 | |||
| 19 | class SyncpointManager final { | ||
| 20 | public: | ||
| 21 | explicit SyncpointManager(Tegra::GPU& gpu); | ||
| 22 | ~SyncpointManager(); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Returns true if the specified syncpoint is expired for the given value. | ||
| 26 | * @param syncpoint_id Syncpoint ID to check. | ||
| 27 | * @param value Value to check against the specified syncpoint. | ||
| 28 | * @returns True if the specified syncpoint is expired for the given value, otherwise False. | ||
| 29 | */ | ||
| 30 | bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const { | ||
| 31 | return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value); | ||
| 32 | } | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Gets the lower bound for the specified syncpoint. | ||
| 36 | * @param syncpoint_id Syncpoint ID to get the lower bound for. | ||
| 37 | * @returns The lower bound for the specified syncpoint. | ||
| 38 | */ | ||
| 39 | u32 GetSyncpointMin(u32 syncpoint_id) const { | ||
| 40 | return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed); | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Gets the uper bound for the specified syncpoint. | ||
| 45 | * @param syncpoint_id Syncpoint ID to get the upper bound for. | ||
| 46 | * @returns The upper bound for the specified syncpoint. | ||
| 47 | */ | ||
| 48 | u32 GetSyncpointMax(u32 syncpoint_id) const { | ||
| 49 | return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed); | ||
| 50 | } | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Refreshes the minimum value for the specified syncpoint. | ||
| 54 | * @param syncpoint_id Syncpoint ID to be refreshed. | ||
| 55 | * @returns The new syncpoint minimum value. | ||
| 56 | */ | ||
| 57 | u32 RefreshSyncpoint(u32 syncpoint_id); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Allocates a new syncoint. | ||
| 61 | * @returns The syncpoint ID for the newly allocated syncpoint. | ||
| 62 | */ | ||
| 63 | u32 AllocateSyncpoint(); | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Increases the maximum value for the specified syncpoint. | ||
| 67 | * @param syncpoint_id Syncpoint ID to be increased. | ||
| 68 | * @param value Value to increase the specified syncpoint by. | ||
| 69 | * @returns The new syncpoint maximum value. | ||
| 70 | */ | ||
| 71 | u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value); | ||
| 72 | |||
| 73 | private: | ||
| 74 | struct Syncpoint { | ||
| 75 | std::atomic<u32> min; | ||
| 76 | std::atomic<u32> max; | ||
| 77 | std::atomic<bool> is_allocated; | ||
| 78 | }; | ||
| 79 | |||
| 80 | std::array<Syncpoint, MaxSyncPoints> syncpoints{}; | ||
| 81 | |||
| 82 | Tegra::GPU& gpu; | ||
| 83 | }; | ||
| 84 | |||
| 85 | } // namespace Service::Nvidia | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 637b310d7..5578181a4 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -22,127 +22,169 @@ BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) | |||
| 22 | BufferQueue::~BufferQueue() = default; | 22 | BufferQueue::~BufferQueue() = default; |
| 23 | 23 | ||
| 24 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { | 24 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { |
| 25 | ASSERT(slot < buffer_slots); | ||
| 25 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | 26 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); |
| 26 | 27 | ||
| 27 | free_buffers.push_back(slot); | 28 | { |
| 28 | queue.push_back({ | 29 | std::unique_lock lock{free_buffers_mutex}; |
| 30 | free_buffers.push_back(slot); | ||
| 31 | } | ||
| 32 | free_buffers_condition.notify_one(); | ||
| 33 | |||
| 34 | buffers[slot] = { | ||
| 29 | .slot = slot, | 35 | .slot = slot, |
| 30 | .status = Buffer::Status::Free, | 36 | .status = Buffer::Status::Free, |
| 31 | .igbp_buffer = igbp_buffer, | 37 | .igbp_buffer = igbp_buffer, |
| 32 | }); | 38 | .transform = {}, |
| 39 | .crop_rect = {}, | ||
| 40 | .swap_interval = 0, | ||
| 41 | .multi_fence = {}, | ||
| 42 | }; | ||
| 33 | 43 | ||
| 34 | buffer_wait_event.writable->Signal(); | 44 | buffer_wait_event.writable->Signal(); |
| 35 | } | 45 | } |
| 36 | 46 | ||
| 37 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, | 47 | std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, |
| 38 | u32 height) { | 48 | u32 height) { |
| 49 | // Wait for first request before trying to dequeue | ||
| 50 | { | ||
| 51 | std::unique_lock lock{free_buffers_mutex}; | ||
| 52 | free_buffers_condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; }); | ||
| 53 | } | ||
| 39 | 54 | ||
| 40 | if (free_buffers.empty()) { | 55 | if (!is_connect) { |
| 56 | // Buffer was disconnected while the thread was blocked, this is most likely due to | ||
| 57 | // emulation being stopped | ||
| 41 | return std::nullopt; | 58 | return std::nullopt; |
| 42 | } | 59 | } |
| 43 | 60 | ||
| 61 | std::unique_lock lock{free_buffers_mutex}; | ||
| 62 | |||
| 44 | auto f_itr = free_buffers.begin(); | 63 | auto f_itr = free_buffers.begin(); |
| 45 | auto itr = queue.end(); | 64 | auto slot = buffers.size(); |
| 46 | 65 | ||
| 47 | while (f_itr != free_buffers.end()) { | 66 | while (f_itr != free_buffers.end()) { |
| 48 | auto slot = *f_itr; | 67 | const Buffer& buffer = buffers[*f_itr]; |
| 49 | itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | 68 | if (buffer.status == Buffer::Status::Free && buffer.igbp_buffer.width == width && |
| 50 | // Only consider free buffers. Buffers become free once again after they've been | 69 | buffer.igbp_buffer.height == height) { |
| 51 | // Acquired and Released by the compositor, see the NVFlinger::Compose method. | 70 | slot = *f_itr; |
| 52 | if (buffer.status != Buffer::Status::Free) { | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | |||
| 56 | if (buffer.slot != slot) { | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | |||
| 60 | // Make sure that the parameters match. | ||
| 61 | return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height; | ||
| 62 | }); | ||
| 63 | |||
| 64 | if (itr != queue.end()) { | ||
| 65 | free_buffers.erase(f_itr); | 71 | free_buffers.erase(f_itr); |
| 66 | break; | 72 | break; |
| 67 | } | 73 | } |
| 68 | ++f_itr; | 74 | ++f_itr; |
| 69 | } | 75 | } |
| 70 | 76 | if (slot == buffers.size()) { | |
| 71 | if (itr == queue.end()) { | ||
| 72 | return std::nullopt; | 77 | return std::nullopt; |
| 73 | } | 78 | } |
| 74 | 79 | buffers[slot].status = Buffer::Status::Dequeued; | |
| 75 | itr->status = Buffer::Status::Dequeued; | 80 | return {{buffers[slot].slot, &buffers[slot].multi_fence}}; |
| 76 | return {{itr->slot, &itr->multi_fence}}; | ||
| 77 | } | 81 | } |
| 78 | 82 | ||
| 79 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | 83 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { |
| 80 | auto itr = std::find_if(queue.begin(), queue.end(), | 84 | ASSERT(slot < buffers.size()); |
| 81 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | 85 | ASSERT(buffers[slot].status == Buffer::Status::Dequeued); |
| 82 | ASSERT(itr != queue.end()); | 86 | ASSERT(buffers[slot].slot == slot); |
| 83 | ASSERT(itr->status == Buffer::Status::Dequeued); | 87 | |
| 84 | return itr->igbp_buffer; | 88 | return buffers[slot].igbp_buffer; |
| 85 | } | 89 | } |
| 86 | 90 | ||
| 87 | void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, | 91 | void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, |
| 88 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, | 92 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, |
| 89 | Service::Nvidia::MultiFence& multi_fence) { | 93 | Service::Nvidia::MultiFence& multi_fence) { |
| 90 | auto itr = std::find_if(queue.begin(), queue.end(), | 94 | ASSERT(slot < buffers.size()); |
| 91 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | 95 | ASSERT(buffers[slot].status == Buffer::Status::Dequeued); |
| 92 | ASSERT(itr != queue.end()); | 96 | ASSERT(buffers[slot].slot == slot); |
| 93 | ASSERT(itr->status == Buffer::Status::Dequeued); | 97 | |
| 94 | itr->status = Buffer::Status::Queued; | 98 | buffers[slot].status = Buffer::Status::Queued; |
| 95 | itr->transform = transform; | 99 | buffers[slot].transform = transform; |
| 96 | itr->crop_rect = crop_rect; | 100 | buffers[slot].crop_rect = crop_rect; |
| 97 | itr->swap_interval = swap_interval; | 101 | buffers[slot].swap_interval = swap_interval; |
| 98 | itr->multi_fence = multi_fence; | 102 | buffers[slot].multi_fence = multi_fence; |
| 103 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 99 | queue_sequence.push_back(slot); | 104 | queue_sequence.push_back(slot); |
| 100 | } | 105 | } |
| 101 | 106 | ||
| 107 | void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) { | ||
| 108 | ASSERT(slot < buffers.size()); | ||
| 109 | ASSERT(buffers[slot].status != Buffer::Status::Free); | ||
| 110 | ASSERT(buffers[slot].slot == slot); | ||
| 111 | |||
| 112 | buffers[slot].status = Buffer::Status::Free; | ||
| 113 | buffers[slot].multi_fence = multi_fence; | ||
| 114 | buffers[slot].swap_interval = 0; | ||
| 115 | |||
| 116 | { | ||
| 117 | std::unique_lock lock{free_buffers_mutex}; | ||
| 118 | free_buffers.push_back(slot); | ||
| 119 | } | ||
| 120 | free_buffers_condition.notify_one(); | ||
| 121 | |||
| 122 | buffer_wait_event.writable->Signal(); | ||
| 123 | } | ||
| 124 | |||
| 102 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { | 125 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { |
| 103 | auto itr = queue.end(); | 126 | std::unique_lock lock{queue_sequence_mutex}; |
| 127 | std::size_t buffer_slot = buffers.size(); | ||
| 104 | // Iterate to find a queued buffer matching the requested slot. | 128 | // Iterate to find a queued buffer matching the requested slot. |
| 105 | while (itr == queue.end() && !queue_sequence.empty()) { | 129 | while (buffer_slot == buffers.size() && !queue_sequence.empty()) { |
| 106 | const u32 slot = queue_sequence.front(); | 130 | const auto slot = static_cast<std::size_t>(queue_sequence.front()); |
| 107 | itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) { | 131 | ASSERT(slot < buffers.size()); |
| 108 | return buffer.status == Buffer::Status::Queued && buffer.slot == slot; | 132 | if (buffers[slot].status == Buffer::Status::Queued) { |
| 109 | }); | 133 | ASSERT(buffers[slot].slot == slot); |
| 134 | buffer_slot = slot; | ||
| 135 | } | ||
| 110 | queue_sequence.pop_front(); | 136 | queue_sequence.pop_front(); |
| 111 | } | 137 | } |
| 112 | if (itr == queue.end()) { | 138 | if (buffer_slot == buffers.size()) { |
| 113 | return std::nullopt; | 139 | return std::nullopt; |
| 114 | } | 140 | } |
| 115 | itr->status = Buffer::Status::Acquired; | 141 | buffers[buffer_slot].status = Buffer::Status::Acquired; |
| 116 | return *itr; | 142 | return {{buffers[buffer_slot]}}; |
| 117 | } | 143 | } |
| 118 | 144 | ||
| 119 | void BufferQueue::ReleaseBuffer(u32 slot) { | 145 | void BufferQueue::ReleaseBuffer(u32 slot) { |
| 120 | auto itr = std::find_if(queue.begin(), queue.end(), | 146 | ASSERT(slot < buffers.size()); |
| 121 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | 147 | ASSERT(buffers[slot].status == Buffer::Status::Acquired); |
| 122 | ASSERT(itr != queue.end()); | 148 | ASSERT(buffers[slot].slot == slot); |
| 123 | ASSERT(itr->status == Buffer::Status::Acquired); | 149 | |
| 124 | itr->status = Buffer::Status::Free; | 150 | buffers[slot].status = Buffer::Status::Free; |
| 125 | free_buffers.push_back(slot); | 151 | { |
| 152 | std::unique_lock lock{free_buffers_mutex}; | ||
| 153 | free_buffers.push_back(slot); | ||
| 154 | } | ||
| 155 | free_buffers_condition.notify_one(); | ||
| 126 | 156 | ||
| 127 | buffer_wait_event.writable->Signal(); | 157 | buffer_wait_event.writable->Signal(); |
| 128 | } | 158 | } |
| 129 | 159 | ||
| 130 | void BufferQueue::Disconnect() { | 160 | void BufferQueue::Connect() { |
| 131 | queue.clear(); | 161 | std::unique_lock lock{queue_sequence_mutex}; |
| 132 | queue_sequence.clear(); | 162 | queue_sequence.clear(); |
| 133 | id = 1; | 163 | is_connect = true; |
| 134 | layer_id = 1; | 164 | } |
| 165 | |||
| 166 | void BufferQueue::Disconnect() { | ||
| 167 | buffers.fill({}); | ||
| 168 | { | ||
| 169 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 170 | queue_sequence.clear(); | ||
| 171 | } | ||
| 172 | buffer_wait_event.writable->Signal(); | ||
| 173 | is_connect = false; | ||
| 174 | free_buffers_condition.notify_one(); | ||
| 135 | } | 175 | } |
| 136 | 176 | ||
| 137 | u32 BufferQueue::Query(QueryType type) { | 177 | u32 BufferQueue::Query(QueryType type) { |
| 138 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); | 178 | LOG_WARNING(Service, "(STUBBED) called type={}", type); |
| 139 | 179 | ||
| 140 | switch (type) { | 180 | switch (type) { |
| 141 | case QueryType::NativeWindowFormat: | 181 | case QueryType::NativeWindowFormat: |
| 142 | return static_cast<u32>(PixelFormat::RGBA8888); | 182 | return static_cast<u32>(PixelFormat::RGBA8888); |
| 183 | case QueryType::NativeWindowWidth: | ||
| 184 | case QueryType::NativeWindowHeight: | ||
| 185 | break; | ||
| 143 | } | 186 | } |
| 144 | 187 | UNIMPLEMENTED_MSG("Unimplemented query type={}", type); | |
| 145 | UNIMPLEMENTED(); | ||
| 146 | return 0; | 188 | return 0; |
| 147 | } | 189 | } |
| 148 | 190 | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 8a837e5aa..ad7469277 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -4,7 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <condition_variable> | ||
| 7 | #include <list> | 8 | #include <list> |
| 9 | #include <mutex> | ||
| 8 | #include <optional> | 10 | #include <optional> |
| 9 | #include <vector> | 11 | #include <vector> |
| 10 | 12 | ||
| @@ -21,6 +23,7 @@ class KernelCore; | |||
| 21 | 23 | ||
| 22 | namespace Service::NVFlinger { | 24 | namespace Service::NVFlinger { |
| 23 | 25 | ||
| 26 | constexpr u32 buffer_slots = 0x40; | ||
| 24 | struct IGBPBuffer { | 27 | struct IGBPBuffer { |
| 25 | u32_le magic; | 28 | u32_le magic; |
| 26 | u32_le width; | 29 | u32_le width; |
| @@ -95,8 +98,10 @@ public: | |||
| 95 | void QueueBuffer(u32 slot, BufferTransformFlags transform, | 98 | void QueueBuffer(u32 slot, BufferTransformFlags transform, |
| 96 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, | 99 | const Common::Rectangle<int>& crop_rect, u32 swap_interval, |
| 97 | Service::Nvidia::MultiFence& multi_fence); | 100 | Service::Nvidia::MultiFence& multi_fence); |
| 101 | void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence); | ||
| 98 | std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); | 102 | std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); |
| 99 | void ReleaseBuffer(u32 slot); | 103 | void ReleaseBuffer(u32 slot); |
| 104 | void Connect(); | ||
| 100 | void Disconnect(); | 105 | void Disconnect(); |
| 101 | u32 Query(QueryType type); | 106 | u32 Query(QueryType type); |
| 102 | 107 | ||
| @@ -104,18 +109,30 @@ public: | |||
| 104 | return id; | 109 | return id; |
| 105 | } | 110 | } |
| 106 | 111 | ||
| 112 | bool IsConnected() const { | ||
| 113 | return is_connect; | ||
| 114 | } | ||
| 115 | |||
| 107 | std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; | 116 | std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; |
| 108 | 117 | ||
| 109 | std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const; | 118 | std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const; |
| 110 | 119 | ||
| 111 | private: | 120 | private: |
| 112 | u32 id; | 121 | BufferQueue(const BufferQueue&) = delete; |
| 113 | u64 layer_id; | 122 | |
| 123 | u32 id{}; | ||
| 124 | u64 layer_id{}; | ||
| 125 | std::atomic_bool is_connect{}; | ||
| 114 | 126 | ||
| 115 | std::list<u32> free_buffers; | 127 | std::list<u32> free_buffers; |
| 116 | std::vector<Buffer> queue; | 128 | std::array<Buffer, buffer_slots> buffers; |
| 117 | std::list<u32> queue_sequence; | 129 | std::list<u32> queue_sequence; |
| 118 | Kernel::EventPair buffer_wait_event; | 130 | Kernel::EventPair buffer_wait_event; |
| 131 | |||
| 132 | std::mutex free_buffers_mutex; | ||
| 133 | std::condition_variable free_buffers_condition; | ||
| 134 | |||
| 135 | std::mutex queue_sequence_mutex; | ||
| 119 | }; | 136 | }; |
| 120 | 137 | ||
| 121 | } // namespace Service::NVFlinger | 138 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c64673dba..4b3581949 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -88,6 +88,10 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | NVFlinger::~NVFlinger() { | 90 | NVFlinger::~NVFlinger() { |
| 91 | for (auto& buffer_queue : buffer_queues) { | ||
| 92 | buffer_queue->Disconnect(); | ||
| 93 | } | ||
| 94 | |||
| 91 | if (system.IsMulticore()) { | 95 | if (system.IsMulticore()) { |
| 92 | is_running = false; | 96 | is_running = false; |
| 93 | wait_event->Set(); | 97 | wait_event->Set(); |
| @@ -104,6 +108,8 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | |||
| 104 | } | 108 | } |
| 105 | 109 | ||
| 106 | std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | 110 | std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { |
| 111 | const auto guard = Lock(); | ||
| 112 | |||
| 107 | LOG_DEBUG(Service, "Opening \"{}\" display", name); | 113 | LOG_DEBUG(Service, "Opening \"{}\" display", name); |
| 108 | 114 | ||
| 109 | // TODO(Subv): Currently we only support the Default display. | 115 | // TODO(Subv): Currently we only support the Default display. |
| @@ -121,6 +127,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | |||
| 121 | } | 127 | } |
| 122 | 128 | ||
| 123 | std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { | 129 | std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { |
| 130 | const auto guard = Lock(); | ||
| 124 | auto* const display = FindDisplay(display_id); | 131 | auto* const display = FindDisplay(display_id); |
| 125 | 132 | ||
| 126 | if (display == nullptr) { | 133 | if (display == nullptr) { |
| @@ -129,18 +136,22 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { | |||
| 129 | 136 | ||
| 130 | const u64 layer_id = next_layer_id++; | 137 | const u64 layer_id = next_layer_id++; |
| 131 | const u32 buffer_queue_id = next_buffer_queue_id++; | 138 | const u32 buffer_queue_id = next_buffer_queue_id++; |
| 132 | buffer_queues.emplace_back(system.Kernel(), buffer_queue_id, layer_id); | 139 | buffer_queues.emplace_back( |
| 133 | display->CreateLayer(layer_id, buffer_queues.back()); | 140 | std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id)); |
| 141 | display->CreateLayer(layer_id, *buffer_queues.back()); | ||
| 134 | return layer_id; | 142 | return layer_id; |
| 135 | } | 143 | } |
| 136 | 144 | ||
| 137 | void NVFlinger::CloseLayer(u64 layer_id) { | 145 | void NVFlinger::CloseLayer(u64 layer_id) { |
| 146 | const auto guard = Lock(); | ||
| 147 | |||
| 138 | for (auto& display : displays) { | 148 | for (auto& display : displays) { |
| 139 | display.CloseLayer(layer_id); | 149 | display.CloseLayer(layer_id); |
| 140 | } | 150 | } |
| 141 | } | 151 | } |
| 142 | 152 | ||
| 143 | std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const { | 153 | std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const { |
| 154 | const auto guard = Lock(); | ||
| 144 | const auto* const layer = FindLayer(display_id, layer_id); | 155 | const auto* const layer = FindLayer(display_id, layer_id); |
| 145 | 156 | ||
| 146 | if (layer == nullptr) { | 157 | if (layer == nullptr) { |
| @@ -151,6 +162,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co | |||
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { | 164 | std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { |
| 165 | const auto guard = Lock(); | ||
| 154 | auto* const display = FindDisplay(display_id); | 166 | auto* const display = FindDisplay(display_id); |
| 155 | 167 | ||
| 156 | if (display == nullptr) { | 168 | if (display == nullptr) { |
| @@ -160,20 +172,16 @@ std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) | |||
| 160 | return display->GetVSyncEvent(); | 172 | return display->GetVSyncEvent(); |
| 161 | } | 173 | } |
| 162 | 174 | ||
| 163 | BufferQueue& NVFlinger::FindBufferQueue(u32 id) { | 175 | BufferQueue* NVFlinger::FindBufferQueue(u32 id) { |
| 176 | const auto guard = Lock(); | ||
| 164 | const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), | 177 | const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), |
| 165 | [id](const auto& queue) { return queue.GetId() == id; }); | 178 | [id](const auto& queue) { return queue->GetId() == id; }); |
| 166 | |||
| 167 | ASSERT(itr != buffer_queues.end()); | ||
| 168 | return *itr; | ||
| 169 | } | ||
| 170 | 179 | ||
| 171 | const BufferQueue& NVFlinger::FindBufferQueue(u32 id) const { | 180 | if (itr == buffer_queues.end()) { |
| 172 | const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), | 181 | return nullptr; |
| 173 | [id](const auto& queue) { return queue.GetId() == id; }); | 182 | } |
| 174 | 183 | ||
| 175 | ASSERT(itr != buffer_queues.end()); | 184 | return itr->get(); |
| 176 | return *itr; | ||
| 177 | } | 185 | } |
| 178 | 186 | ||
| 179 | VI::Display* NVFlinger::FindDisplay(u64 display_id) { | 187 | VI::Display* NVFlinger::FindDisplay(u64 display_id) { |
| @@ -242,6 +250,10 @@ void NVFlinger::Compose() { | |||
| 242 | 250 | ||
| 243 | const auto& igbp_buffer = buffer->get().igbp_buffer; | 251 | const auto& igbp_buffer = buffer->get().igbp_buffer; |
| 244 | 252 | ||
| 253 | if (!system.IsPoweredOn()) { | ||
| 254 | return; // We are likely shutting down | ||
| 255 | } | ||
| 256 | |||
| 245 | auto& gpu = system.GPU(); | 257 | auto& gpu = system.GPU(); |
| 246 | const auto& multi_fence = buffer->get().multi_fence; | 258 | const auto& multi_fence = buffer->get().multi_fence; |
| 247 | guard->unlock(); | 259 | guard->unlock(); |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 1ebe949c0..c6765259f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -75,10 +75,7 @@ public: | |||
| 75 | [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; | 75 | [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; |
| 76 | 76 | ||
| 77 | /// Obtains a buffer queue identified by the ID. | 77 | /// Obtains a buffer queue identified by the ID. |
| 78 | [[nodiscard]] BufferQueue& FindBufferQueue(u32 id); | 78 | [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); |
| 79 | |||
| 80 | /// Obtains a buffer queue identified by the ID. | ||
| 81 | [[nodiscard]] const BufferQueue& FindBufferQueue(u32 id) const; | ||
| 82 | 79 | ||
| 83 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when | 80 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when |
| 84 | /// finished. | 81 | /// finished. |
| @@ -86,11 +83,11 @@ public: | |||
| 86 | 83 | ||
| 87 | [[nodiscard]] s64 GetNextTicks() const; | 84 | [[nodiscard]] s64 GetNextTicks() const; |
| 88 | 85 | ||
| 86 | private: | ||
| 89 | [[nodiscard]] std::unique_lock<std::mutex> Lock() const { | 87 | [[nodiscard]] std::unique_lock<std::mutex> Lock() const { |
| 90 | return std::unique_lock{*guard}; | 88 | return std::unique_lock{*guard}; |
| 91 | } | 89 | } |
| 92 | 90 | ||
| 93 | private: | ||
| 94 | /// Finds the display identified by the specified ID. | 91 | /// Finds the display identified by the specified ID. |
| 95 | [[nodiscard]] VI::Display* FindDisplay(u64 display_id); | 92 | [[nodiscard]] VI::Display* FindDisplay(u64 display_id); |
| 96 | 93 | ||
| @@ -110,7 +107,7 @@ private: | |||
| 110 | std::shared_ptr<Nvidia::Module> nvdrv; | 107 | std::shared_ptr<Nvidia::Module> nvdrv; |
| 111 | 108 | ||
| 112 | std::vector<VI::Display> displays; | 109 | std::vector<VI::Display> displays; |
| 113 | std::vector<BufferQueue> buffer_queues; | 110 | std::vector<std::unique_ptr<BufferQueue>> buffer_queues; |
| 114 | 111 | ||
| 115 | /// Id to use for the next layer that is created, this counter is shared among all displays. | 112 | /// Id to use for the next layer that is created, this counter is shared among all displays. |
| 116 | u64 next_layer_id = 1; | 113 | u64 next_layer_id = 1; |
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp new file mode 100644 index 000000000..4440135ed --- /dev/null +++ b/src/core/hle/service/olsc/olsc.cpp | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/ipc_helpers.h" | ||
| 6 | #include "core/hle/kernel/hle_ipc.h" | ||
| 7 | #include "core/hle/service/olsc/olsc.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | namespace Service::OLSC { | ||
| 12 | |||
| 13 | class OLSC final : public ServiceFramework<OLSC> { | ||
| 14 | public: | ||
| 15 | explicit OLSC(Core::System& system_) : ServiceFramework{system_, "olsc:u"} { | ||
| 16 | // clang-format off | ||
| 17 | static const FunctionInfo functions[] = { | ||
| 18 | {0, &OLSC::Initialize, "Initialize"}, | ||
| 19 | {10, nullptr, "VerifySaveDataBackupLicenseAsync"}, | ||
| 20 | {13, nullptr, "GetSaveDataBackupSetting"}, | ||
| 21 | {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"}, | ||
| 22 | {15, nullptr, "SetCustomData"}, | ||
| 23 | {16, nullptr, "DeleteSaveDataBackupSetting"}, | ||
| 24 | {18, nullptr, "GetSaveDataBackupInfoCache"}, | ||
| 25 | {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"}, | ||
| 26 | {22, nullptr, "DeleteSaveDataBackupAsync"}, | ||
| 27 | {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"}, | ||
| 28 | {26, nullptr, "DownloadSaveDataBackupAsync"}, | ||
| 29 | {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"}, | ||
| 30 | {9013, nullptr, "GetSaveDataBackupSettingForDebug"}, | ||
| 31 | {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"}, | ||
| 32 | {9015, nullptr, "SetCustomDataForDebug"}, | ||
| 33 | {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"}, | ||
| 34 | {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"}, | ||
| 35 | {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"}, | ||
| 36 | {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"}, | ||
| 37 | {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"}, | ||
| 38 | {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"}, | ||
| 39 | }; | ||
| 40 | // clang-format on | ||
| 41 | |||
| 42 | RegisterHandlers(functions); | ||
| 43 | } | ||
| 44 | |||
| 45 | private: | ||
| 46 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 47 | LOG_WARNING(Service_OLSC, "(STUBBED) called"); | ||
| 48 | |||
| 49 | initialized = true; | ||
| 50 | |||
| 51 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 52 | rb.Push(RESULT_SUCCESS); | ||
| 53 | } | ||
| 54 | |||
| 55 | void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) { | ||
| 56 | LOG_WARNING(Service_OLSC, "(STUBBED) called"); | ||
| 57 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 59 | rb.Push(RESULT_SUCCESS); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool initialized{}; | ||
| 63 | }; | ||
| 64 | |||
| 65 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | ||
| 66 | std::make_shared<OLSC>(system)->InstallAsService(service_manager); | ||
| 67 | } | ||
| 68 | |||
| 69 | } // namespace Service::OLSC | ||
diff --git a/src/core/hle/service/olsc/olsc.h b/src/core/hle/service/olsc/olsc.h new file mode 100644 index 000000000..24f24ca6b --- /dev/null +++ b/src/core/hle/service/olsc/olsc.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // Copyright 2020 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 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::OLSC { | ||
| 16 | |||
| 17 | /// Registers all SSL services with the specified service manager. | ||
| 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); | ||
| 19 | |||
| 20 | } // namespace Service::OLSC | ||
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp index c568a0adc..f6686fc4d 100644 --- a/src/core/hle/service/pcie/pcie.cpp +++ b/src/core/hle/service/pcie/pcie.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::PCIe { | |||
| 12 | 12 | ||
| 13 | class ISession final : public ServiceFramework<ISession> { | 13 | class ISession final : public ServiceFramework<ISession> { |
| 14 | public: | 14 | public: |
| 15 | explicit ISession() : ServiceFramework{"ISession"} { | 15 | explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "QueryFunctions"}, | 18 | {0, nullptr, "QueryFunctions"}, |
| @@ -48,7 +48,7 @@ public: | |||
| 48 | 48 | ||
| 49 | class PCIe final : public ServiceFramework<PCIe> { | 49 | class PCIe final : public ServiceFramework<PCIe> { |
| 50 | public: | 50 | public: |
| 51 | explicit PCIe() : ServiceFramework{"pcie"} { | 51 | explicit PCIe(Core::System& system_) : ServiceFramework{system_, "pcie"} { |
| 52 | // clang-format off | 52 | // clang-format off |
| 53 | static const FunctionInfo functions[] = { | 53 | static const FunctionInfo functions[] = { |
| 54 | {0, nullptr, "RegisterClassDriver"}, | 54 | {0, nullptr, "RegisterClassDriver"}, |
| @@ -60,8 +60,8 @@ public: | |||
| 60 | } | 60 | } |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | void InstallInterfaces(SM::ServiceManager& sm) { | 63 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 64 | std::make_shared<PCIe>()->InstallAsService(sm); | 64 | std::make_shared<PCIe>(system)->InstallAsService(sm); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | } // namespace Service::PCIe | 67 | } // namespace Service::PCIe |
diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h index 59c22ca45..e5709a72f 100644 --- a/src/core/hle/service/pcie/pcie.h +++ b/src/core/hle/service/pcie/pcie.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::PCIe { | 15 | namespace Service::PCIe { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::PCIe | 19 | } // namespace Service::PCIe |
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index caf14ed61..6ab1e4124 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -11,7 +11,8 @@ namespace Service::PCTL { | |||
| 11 | 11 | ||
| 12 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { | 12 | class IParentalControlService final : public ServiceFramework<IParentalControlService> { |
| 13 | public: | 13 | public: |
| 14 | IParentalControlService() : ServiceFramework("IParentalControlService") { | 14 | explicit IParentalControlService(Core::System& system_) |
| 15 | : ServiceFramework{system_, "IParentalControlService"} { | ||
| 15 | // clang-format off | 16 | // clang-format off |
| 16 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 17 | {1, &IParentalControlService::Initialize, "Initialize"}, | 18 | {1, &IParentalControlService::Initialize, "Initialize"}, |
| @@ -137,7 +138,7 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | |||
| 137 | 138 | ||
| 138 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 139 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 139 | rb.Push(RESULT_SUCCESS); | 140 | rb.Push(RESULT_SUCCESS); |
| 140 | rb.PushIpcInterface<IParentalControlService>(); | 141 | rb.PushIpcInterface<IParentalControlService>(system); |
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { | 144 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { |
| @@ -145,20 +146,20 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext | |||
| 145 | 146 | ||
| 146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 147 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 147 | rb.Push(RESULT_SUCCESS); | 148 | rb.Push(RESULT_SUCCESS); |
| 148 | rb.PushIpcInterface<IParentalControlService>(); | 149 | rb.PushIpcInterface<IParentalControlService>(system); |
| 149 | } | 150 | } |
| 150 | 151 | ||
| 151 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 152 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name) |
| 152 | : ServiceFramework(name), module(std::move(module)) {} | 153 | : ServiceFramework{system_, name}, module{std::move(module_)} {} |
| 153 | 154 | ||
| 154 | Module::Interface::~Interface() = default; | 155 | Module::Interface::~Interface() = default; |
| 155 | 156 | ||
| 156 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 157 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 157 | auto module = std::make_shared<Module>(); | 158 | auto module = std::make_shared<Module>(); |
| 158 | std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); | 159 | std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager); |
| 159 | std::make_shared<PCTL>(module, "pctl:a")->InstallAsService(service_manager); | 160 | std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager); |
| 160 | std::make_shared<PCTL>(module, "pctl:r")->InstallAsService(service_manager); | 161 | std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager); |
| 161 | std::make_shared<PCTL>(module, "pctl:s")->InstallAsService(service_manager); | 162 | std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager); |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | } // namespace Service::PCTL | 165 | } // namespace Service::PCTL |
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h index 3e449110d..4c7e09a3b 100644 --- a/src/core/hle/service/pctl/module.h +++ b/src/core/hle/service/pctl/module.h | |||
| @@ -6,13 +6,18 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::PCTL { | 13 | namespace Service::PCTL { |
| 10 | 14 | ||
| 11 | class Module final { | 15 | class Module final { |
| 12 | public: | 16 | public: |
| 13 | class Interface : public ServiceFramework<Interface> { | 17 | class Interface : public ServiceFramework<Interface> { |
| 14 | public: | 18 | public: |
| 15 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 19 | explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 20 | const char* name); | ||
| 16 | ~Interface() override; | 21 | ~Interface() override; |
| 17 | 22 | ||
| 18 | void CreateService(Kernel::HLERequestContext& ctx); | 23 | void CreateService(Kernel::HLERequestContext& ctx); |
| @@ -24,6 +29,6 @@ public: | |||
| 24 | }; | 29 | }; |
| 25 | 30 | ||
| 26 | /// Registers all PCTL services with the specified service manager. | 31 | /// Registers all PCTL services with the specified service manager. |
| 27 | void InstallInterfaces(SM::ServiceManager& service_manager); | 32 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 28 | 33 | ||
| 29 | } // namespace Service::PCTL | 34 | } // namespace Service::PCTL |
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp index af9d1433a..16dd34f90 100644 --- a/src/core/hle/service/pctl/pctl.cpp +++ b/src/core/hle/service/pctl/pctl.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::PCTL { | 7 | namespace Service::PCTL { |
| 8 | 8 | ||
| 9 | PCTL::PCTL(std::shared_ptr<Module> module, const char* name) | 9 | PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name) |
| 10 | : Module::Interface(std::move(module), name) { | 10 | : Interface{system_, std::move(module_), name} { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &PCTL::CreateService, "CreateService"}, | 12 | {0, &PCTL::CreateService, "CreateService"}, |
| 13 | {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, | 13 | {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, |
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h index c33ea80b6..275d23007 100644 --- a/src/core/hle/service/pctl/pctl.h +++ b/src/core/hle/service/pctl/pctl.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/pctl/module.h" | 7 | #include "core/hle/service/pctl/module.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::PCTL { | 13 | namespace Service::PCTL { |
| 10 | 14 | ||
| 11 | class PCTL final : public Module::Interface { | 15 | class PCTL final : public Module::Interface { |
| 12 | public: | 16 | public: |
| 13 | explicit PCTL(std::shared_ptr<Module> module, const char* name); | 17 | explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name); |
| 14 | ~PCTL() override; | 18 | ~PCTL() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index 8bfc0276e..68b2c4178 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::PCV { | |||
| 12 | 12 | ||
| 13 | class PCV final : public ServiceFramework<PCV> { | 13 | class PCV final : public ServiceFramework<PCV> { |
| 14 | public: | 14 | public: |
| 15 | explicit PCV() : ServiceFramework{"pcv"} { | 15 | explicit PCV(Core::System& system_) : ServiceFramework{system_, "pcv"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SetPowerEnabled"}, | 18 | {0, nullptr, "SetPowerEnabled"}, |
| @@ -54,7 +54,7 @@ public: | |||
| 54 | 54 | ||
| 55 | class PCV_ARB final : public ServiceFramework<PCV_ARB> { | 55 | class PCV_ARB final : public ServiceFramework<PCV_ARB> { |
| 56 | public: | 56 | public: |
| 57 | explicit PCV_ARB() : ServiceFramework{"pcv:arb"} { | 57 | explicit PCV_ARB(Core::System& system_) : ServiceFramework{system_, "pcv:arb"} { |
| 58 | // clang-format off | 58 | // clang-format off |
| 59 | static const FunctionInfo functions[] = { | 59 | static const FunctionInfo functions[] = { |
| 60 | {0, nullptr, "ReleaseControl"}, | 60 | {0, nullptr, "ReleaseControl"}, |
| @@ -67,7 +67,7 @@ public: | |||
| 67 | 67 | ||
| 68 | class PCV_IMM final : public ServiceFramework<PCV_IMM> { | 68 | class PCV_IMM final : public ServiceFramework<PCV_IMM> { |
| 69 | public: | 69 | public: |
| 70 | explicit PCV_IMM() : ServiceFramework{"pcv:imm"} { | 70 | explicit PCV_IMM(Core::System& system_) : ServiceFramework{system_, "pcv:imm"} { |
| 71 | // clang-format off | 71 | // clang-format off |
| 72 | static const FunctionInfo functions[] = { | 72 | static const FunctionInfo functions[] = { |
| 73 | {0, nullptr, "SetClockRate"}, | 73 | {0, nullptr, "SetClockRate"}, |
| @@ -78,10 +78,10 @@ public: | |||
| 78 | } | 78 | } |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | void InstallInterfaces(SM::ServiceManager& sm) { | 81 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 82 | std::make_shared<PCV>()->InstallAsService(sm); | 82 | std::make_shared<PCV>(system)->InstallAsService(sm); |
| 83 | std::make_shared<PCV_ARB>()->InstallAsService(sm); | 83 | std::make_shared<PCV_ARB>(system)->InstallAsService(sm); |
| 84 | std::make_shared<PCV_IMM>()->InstallAsService(sm); | 84 | std::make_shared<PCV_IMM>(system)->InstallAsService(sm); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | } // namespace Service::PCV | 87 | } // namespace Service::PCV |
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h index 219a893c3..c61a0b591 100644 --- a/src/core/hle/service/pcv/pcv.h +++ b/src/core/hle/service/pcv/pcv.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::PCV { | 15 | namespace Service::PCV { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::PCV | 19 | } // namespace Service::PCV |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index f43122ad2..68736c40c 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 "core/core.h" | ||
| 5 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 6 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 7 | #include "core/hle/kernel/process.h" | 8 | #include "core/hle/kernel/process.h" |
| @@ -43,7 +44,7 @@ void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx, | |||
| 43 | 44 | ||
| 44 | class BootMode final : public ServiceFramework<BootMode> { | 45 | class BootMode final : public ServiceFramework<BootMode> { |
| 45 | public: | 46 | public: |
| 46 | explicit BootMode() : ServiceFramework{"pm:bm"} { | 47 | explicit BootMode(Core::System& system_) : ServiceFramework{system_, "pm:bm"} { |
| 47 | static const FunctionInfo functions[] = { | 48 | static const FunctionInfo functions[] = { |
| 48 | {0, &BootMode::GetBootMode, "GetBootMode"}, | 49 | {0, &BootMode::GetBootMode, "GetBootMode"}, |
| 49 | {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"}, | 50 | {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"}, |
| @@ -74,8 +75,8 @@ private: | |||
| 74 | 75 | ||
| 75 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 76 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 76 | public: | 77 | public: |
| 77 | explicit DebugMonitor(const Kernel::KernelCore& kernel) | 78 | explicit DebugMonitor(Core::System& system_) |
| 78 | : ServiceFramework{"pm:dmnt"}, kernel(kernel) { | 79 | : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { |
| 79 | // clang-format off | 80 | // clang-format off |
| 80 | static const FunctionInfo functions[] = { | 81 | static const FunctionInfo functions[] = { |
| 81 | {0, nullptr, "GetJitDebugProcessIdList"}, | 82 | {0, nullptr, "GetJitDebugProcessIdList"}, |
| @@ -124,8 +125,9 @@ private: | |||
| 124 | 125 | ||
| 125 | class Info final : public ServiceFramework<Info> { | 126 | class Info final : public ServiceFramework<Info> { |
| 126 | public: | 127 | public: |
| 127 | explicit Info(const std::vector<std::shared_ptr<Kernel::Process>>& process_list) | 128 | explicit Info(Core::System& system_, |
| 128 | : ServiceFramework{"pm:info"}, process_list(process_list) { | 129 | const std::vector<std::shared_ptr<Kernel::Process>>& process_list_) |
| 130 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | ||
| 129 | static const FunctionInfo functions[] = { | 131 | static const FunctionInfo functions[] = { |
| 130 | {0, &Info::GetTitleId, "GetTitleId"}, | 132 | {0, &Info::GetTitleId, "GetTitleId"}, |
| 131 | }; | 133 | }; |
| @@ -159,8 +161,8 @@ private: | |||
| 159 | 161 | ||
| 160 | class Shell final : public ServiceFramework<Shell> { | 162 | class Shell final : public ServiceFramework<Shell> { |
| 161 | public: | 163 | public: |
| 162 | explicit Shell(const Kernel::KernelCore& kernel) | 164 | explicit Shell(Core::System& system_) |
| 163 | : ServiceFramework{"pm:shell"}, kernel(kernel) { | 165 | : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { |
| 164 | // clang-format off | 166 | // clang-format off |
| 165 | static const FunctionInfo functions[] = { | 167 | static const FunctionInfo functions[] = { |
| 166 | {0, nullptr, "LaunchProgram"}, | 168 | {0, nullptr, "LaunchProgram"}, |
| @@ -189,11 +191,11 @@ private: | |||
| 189 | }; | 191 | }; |
| 190 | 192 | ||
| 191 | void InstallInterfaces(Core::System& system) { | 193 | void InstallInterfaces(Core::System& system) { |
| 192 | std::make_shared<BootMode>()->InstallAsService(system.ServiceManager()); | 194 | std::make_shared<BootMode>(system)->InstallAsService(system.ServiceManager()); |
| 193 | std::make_shared<DebugMonitor>(system.Kernel())->InstallAsService(system.ServiceManager()); | 195 | std::make_shared<DebugMonitor>(system)->InstallAsService(system.ServiceManager()); |
| 194 | std::make_shared<Info>(system.Kernel().GetProcessList()) | 196 | std::make_shared<Info>(system, system.Kernel().GetProcessList()) |
| 195 | ->InstallAsService(system.ServiceManager()); | 197 | ->InstallAsService(system.ServiceManager()); |
| 196 | std::make_shared<Shell>(system.Kernel())->InstallAsService(system.ServiceManager()); | 198 | std::make_shared<Shell>(system)->InstallAsService(system.ServiceManager()); |
| 197 | } | 199 | } |
| 198 | 200 | ||
| 199 | } // namespace Service::PM | 201 | } // namespace Service::PM |
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index cde3312da..b417624c9 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/hex_util.h" | 5 | #include "common/hex_util.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/process.h" | 9 | #include "core/hle/kernel/process.h" |
| 9 | #include "core/hle/service/acc/profile_manager.h" | 10 | #include "core/hle/service/acc/profile_manager.h" |
| @@ -15,8 +16,7 @@ namespace Service::PlayReport { | |||
| 15 | 16 | ||
| 16 | class PlayReport final : public ServiceFramework<PlayReport> { | 17 | class PlayReport final : public ServiceFramework<PlayReport> { |
| 17 | public: | 18 | public: |
| 18 | explicit PlayReport(const char* name, Core::System& system) | 19 | explicit PlayReport(const char* name, Core::System& system_) : ServiceFramework{system_, name} { |
| 19 | : ServiceFramework{name}, system(system) { | ||
| 20 | // clang-format off | 20 | // clang-format off |
| 21 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 22 | {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"}, | 22 | {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"}, |
| @@ -65,7 +65,7 @@ private: | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", | 67 | LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", |
| 68 | static_cast<u8>(Type), process_id, data[0].size()); | 68 | Type, process_id, data[0].size()); |
| 69 | 69 | ||
| 70 | const auto& reporter{system.GetReporter()}; | 70 | const auto& reporter{system.GetReporter()}; |
| 71 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); | 71 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); |
| @@ -92,7 +92,7 @@ private: | |||
| 92 | LOG_DEBUG( | 92 | LOG_DEBUG( |
| 93 | Service_PREPO, | 93 | Service_PREPO, |
| 94 | "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", | 94 | "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", |
| 95 | static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size()); | 95 | Type, user_id[1], user_id[0], process_id, data[0].size()); |
| 96 | 96 | ||
| 97 | const auto& reporter{system.GetReporter()}; | 97 | const auto& reporter{system.GetReporter()}; |
| 98 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, | 98 | reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, |
| @@ -139,8 +139,6 @@ private: | |||
| 139 | IPC::ResponseBuilder rb{ctx, 2}; | 139 | IPC::ResponseBuilder rb{ctx, 2}; |
| 140 | rb.Push(RESULT_SUCCESS); | 140 | rb.Push(RESULT_SUCCESS); |
| 141 | } | 141 | } |
| 142 | |||
| 143 | Core::System& system; | ||
| 144 | }; | 142 | }; |
| 145 | 143 | ||
| 146 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 144 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h index a5682ee26..395b57ead 100644 --- a/src/core/hle/service/prepo/prepo.h +++ b/src/core/hle/service/prepo/prepo.h | |||
| @@ -4,14 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Service::SM { | ||
| 8 | class ServiceManager; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Core { | 7 | namespace Core { |
| 12 | class System; | 8 | class System; |
| 13 | } | 9 | } |
| 14 | 10 | ||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::PlayReport { | 15 | namespace Service::PlayReport { |
| 16 | 16 | ||
| 17 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); | 17 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index 99e1c9042..5a52b2b05 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp | |||
| @@ -14,7 +14,7 @@ namespace Service::PSC { | |||
| 14 | 14 | ||
| 15 | class PSC_C final : public ServiceFramework<PSC_C> { | 15 | class PSC_C final : public ServiceFramework<PSC_C> { |
| 16 | public: | 16 | public: |
| 17 | explicit PSC_C() : ServiceFramework{"psc:c"} { | 17 | explicit PSC_C(Core::System& system_) : ServiceFramework{system_, "psc:c"} { |
| 18 | // clang-format off | 18 | // clang-format off |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {0, nullptr, "Initialize"}, | 20 | {0, nullptr, "Initialize"}, |
| @@ -35,7 +35,7 @@ public: | |||
| 35 | 35 | ||
| 36 | class IPmModule final : public ServiceFramework<IPmModule> { | 36 | class IPmModule final : public ServiceFramework<IPmModule> { |
| 37 | public: | 37 | public: |
| 38 | explicit IPmModule() : ServiceFramework{"IPmModule"} { | 38 | explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} { |
| 39 | // clang-format off | 39 | // clang-format off |
| 40 | static const FunctionInfo functions[] = { | 40 | static const FunctionInfo functions[] = { |
| 41 | {0, nullptr, "Initialize"}, | 41 | {0, nullptr, "Initialize"}, |
| @@ -52,7 +52,7 @@ public: | |||
| 52 | 52 | ||
| 53 | class PSC_M final : public ServiceFramework<PSC_M> { | 53 | class PSC_M final : public ServiceFramework<PSC_M> { |
| 54 | public: | 54 | public: |
| 55 | explicit PSC_M() : ServiceFramework{"psc:m"} { | 55 | explicit PSC_M(Core::System& system_) : ServiceFramework{system_, "psc:m"} { |
| 56 | // clang-format off | 56 | // clang-format off |
| 57 | static const FunctionInfo functions[] = { | 57 | static const FunctionInfo functions[] = { |
| 58 | {0, &PSC_M::GetPmModule, "GetPmModule"}, | 58 | {0, &PSC_M::GetPmModule, "GetPmModule"}, |
| @@ -68,13 +68,13 @@ private: | |||
| 68 | 68 | ||
| 69 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 69 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 70 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 71 | rb.PushIpcInterface<IPmModule>(); | 71 | rb.PushIpcInterface<IPmModule>(system); |
| 72 | } | 72 | } |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | void InstallInterfaces(SM::ServiceManager& sm) { | 75 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 76 | std::make_shared<PSC_C>()->InstallAsService(sm); | 76 | std::make_shared<PSC_C>(system)->InstallAsService(sm); |
| 77 | std::make_shared<PSC_M>()->InstallAsService(sm); | 77 | std::make_shared<PSC_M>(system)->InstallAsService(sm); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | } // namespace Service::PSC | 80 | } // namespace Service::PSC |
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h index 5052eb02c..89344f32d 100644 --- a/src/core/hle/service/psc/psc.h +++ b/src/core/hle/service/psc/psc.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::PSC { | 15 | namespace Service::PSC { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::PSC | 19 | } // namespace Service::PSC |
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp index 6d9e6bd09..b4b0dd241 100644 --- a/src/core/hle/service/ptm/psm.cpp +++ b/src/core/hle/service/ptm/psm.cpp | |||
| @@ -14,7 +14,7 @@ namespace Service::PSM { | |||
| 14 | 14 | ||
| 15 | class PSM final : public ServiceFramework<PSM> { | 15 | class PSM final : public ServiceFramework<PSM> { |
| 16 | public: | 16 | public: |
| 17 | explicit PSM() : ServiceFramework{"psm"} { | 17 | explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} { |
| 18 | // clang-format off | 18 | // clang-format off |
| 19 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 20 | {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"}, | 20 | {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"}, |
| @@ -72,8 +72,8 @@ private: | |||
| 72 | ChargerType charger_type{ChargerType::RegularCharger}; | 72 | ChargerType charger_type{ChargerType::RegularCharger}; |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | void InstallInterfaces(SM::ServiceManager& sm) { | 75 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 76 | std::make_shared<PSM>()->InstallAsService(sm); | 76 | std::make_shared<PSM>(system)->InstallAsService(sm); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | } // namespace Service::PSM | 79 | } // namespace Service::PSM |
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h index a286793ae..2930ce26a 100644 --- a/src/core/hle/service/ptm/psm.h +++ b/src/core/hle/service/ptm/psm.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::PSM { | 15 | namespace Service::PSM { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::PSM | 19 | } // namespace Service::PSM |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 76b3533ec..ff2a5b1db 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include "core/hle/service/ns/ns.h" | 51 | #include "core/hle/service/ns/ns.h" |
| 52 | #include "core/hle/service/nvdrv/nvdrv.h" | 52 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 53 | #include "core/hle/service/nvflinger/nvflinger.h" | 53 | #include "core/hle/service/nvflinger/nvflinger.h" |
| 54 | #include "core/hle/service/olsc/olsc.h" | ||
| 54 | #include "core/hle/service/pcie/pcie.h" | 55 | #include "core/hle/service/pcie/pcie.h" |
| 55 | #include "core/hle/service/pctl/module.h" | 56 | #include "core/hle/service/pctl/module.h" |
| 56 | #include "core/hle/service/pcv/pcv.h" | 57 | #include "core/hle/service/pcv/pcv.h" |
| @@ -72,13 +73,36 @@ | |||
| 72 | 73 | ||
| 73 | namespace Service { | 74 | namespace Service { |
| 74 | 75 | ||
| 75 | ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, | 76 | /** |
| 76 | InvokerFn* handler_invoker) | 77 | * Creates a function string for logging, complete with the name (or header code, depending |
| 77 | : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} | 78 | * on what's passed in) the port name, and all the cmd_buff arguments. |
| 79 | */ | ||
| 80 | [[maybe_unused]] static std::string MakeFunctionString(std::string_view name, | ||
| 81 | std::string_view port_name, | ||
| 82 | const u32* cmd_buff) { | ||
| 83 | // Number of params == bits 0-5 + bits 6-11 | ||
| 84 | int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); | ||
| 78 | 85 | ||
| 79 | ServiceFrameworkBase::~ServiceFrameworkBase() = default; | 86 | std::string function_string = fmt::format("function '{}': port={}", name, port_name); |
| 87 | for (int i = 1; i <= num_params; ++i) { | ||
| 88 | function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]); | ||
| 89 | } | ||
| 90 | return function_string; | ||
| 91 | } | ||
| 92 | |||
| 93 | ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, | ||
| 94 | u32 max_sessions_, InvokerFn* handler_invoker_) | ||
| 95 | : system{system_}, service_name{service_name_}, max_sessions{max_sessions_}, | ||
| 96 | handler_invoker{handler_invoker_} {} | ||
| 97 | |||
| 98 | ServiceFrameworkBase::~ServiceFrameworkBase() { | ||
| 99 | // Wait for other threads to release access before destroying | ||
| 100 | const auto guard = LockService(); | ||
| 101 | } | ||
| 80 | 102 | ||
| 81 | void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { | 103 | void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { |
| 104 | const auto guard = LockService(); | ||
| 105 | |||
| 82 | ASSERT(!port_installed); | 106 | ASSERT(!port_installed); |
| 83 | 107 | ||
| 84 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); | 108 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); |
| @@ -87,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | |||
| 87 | } | 111 | } |
| 88 | 112 | ||
| 89 | void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | 113 | void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { |
| 114 | const auto guard = LockService(); | ||
| 115 | |||
| 90 | ASSERT(!port_installed); | 116 | ASSERT(!port_installed); |
| 91 | 117 | ||
| 92 | auto [server_port, client_port] = | 118 | auto [server_port, client_port] = |
| @@ -96,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { | |||
| 96 | port_installed = true; | 122 | port_installed = true; |
| 97 | } | 123 | } |
| 98 | 124 | ||
| 99 | std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) { | ||
| 100 | ASSERT(!port_installed); | ||
| 101 | |||
| 102 | auto [server_port, client_port] = | ||
| 103 | Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); | ||
| 104 | auto port = MakeResult(std::move(server_port)).Unwrap(); | ||
| 105 | port->SetHleHandler(shared_from_this()); | ||
| 106 | port_installed = true; | ||
| 107 | return client_port; | ||
| 108 | } | ||
| 109 | |||
| 110 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { | 125 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { |
| 111 | handlers.reserve(handlers.size() + n); | 126 | handlers.reserve(handlers.size() + n); |
| 112 | for (std::size_t i = 0; i < n; ++i) { | 127 | for (std::size_t i = 0; i < n; ++i) { |
| @@ -128,8 +143,8 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext | |||
| 128 | } | 143 | } |
| 129 | buf.push_back('}'); | 144 | buf.push_back('}'); |
| 130 | 145 | ||
| 131 | Core::System::GetInstance().GetReporter().SaveUnimplementedFunctionReport( | 146 | system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, |
| 132 | ctx, ctx.GetCommand(), function_name, service_name); | 147 | service_name); |
| 133 | UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); | 148 | UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); |
| 134 | } | 149 | } |
| 135 | 150 | ||
| @@ -145,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { | |||
| 145 | } | 160 | } |
| 146 | 161 | ||
| 147 | ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { | 162 | ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { |
| 163 | const auto guard = LockService(); | ||
| 164 | |||
| 148 | switch (context.GetCommandType()) { | 165 | switch (context.GetCommandType()) { |
| 149 | case IPC::CommandType::Close: { | 166 | case IPC::CommandType::Close: { |
| 150 | IPC::ResponseBuilder rb{context, 2}; | 167 | IPC::ResponseBuilder rb{context, 2}; |
| @@ -153,7 +170,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 153 | } | 170 | } |
| 154 | case IPC::CommandType::ControlWithContext: | 171 | case IPC::CommandType::ControlWithContext: |
| 155 | case IPC::CommandType::Control: { | 172 | case IPC::CommandType::Control: { |
| 156 | Core::System::GetInstance().ServiceManager().InvokeControlRequest(context); | 173 | system.ServiceManager().InvokeControlRequest(context); |
| 157 | break; | 174 | break; |
| 158 | } | 175 | } |
| 159 | case IPC::CommandType::RequestWithContext: | 176 | case IPC::CommandType::RequestWithContext: |
| @@ -162,79 +179,82 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 162 | break; | 179 | break; |
| 163 | } | 180 | } |
| 164 | default: | 181 | default: |
| 165 | UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType())); | 182 | UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType()); |
| 166 | } | 183 | } |
| 167 | 184 | ||
| 168 | context.WriteToOutgoingCommandBuffer(context.GetThread()); | 185 | // If emulation was shutdown, we are closing service threads, do not write the response back to |
| 186 | // memory that may be shutting down as well. | ||
| 187 | if (system.IsPoweredOn()) { | ||
| 188 | context.WriteToOutgoingCommandBuffer(context.GetThread()); | ||
| 189 | } | ||
| 169 | 190 | ||
| 170 | return RESULT_SUCCESS; | 191 | return RESULT_SUCCESS; |
| 171 | } | 192 | } |
| 172 | 193 | ||
| 173 | /// Initialize ServiceManager | 194 | /// Initialize Services |
| 174 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | 195 | Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) |
| 196 | : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} { | ||
| 197 | |||
| 175 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it | 198 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it |
| 176 | // here and pass it into the respective InstallInterfaces functions. | 199 | // here and pass it into the respective InstallInterfaces functions. |
| 177 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); | 200 | |
| 178 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | 201 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); |
| 179 | 202 | ||
| 180 | SM::ServiceManager::InstallInterfaces(sm, system.Kernel()); | 203 | SM::ServiceManager::InstallInterfaces(sm, system); |
| 181 | 204 | ||
| 182 | Account::InstallInterfaces(system); | 205 | Account::InstallInterfaces(system); |
| 183 | AM::InstallInterfaces(*sm, nv_flinger, system); | 206 | AM::InstallInterfaces(*sm, *nv_flinger, system); |
| 184 | AOC::InstallInterfaces(*sm, system); | 207 | AOC::InstallInterfaces(*sm, system); |
| 185 | APM::InstallInterfaces(system); | 208 | APM::InstallInterfaces(system); |
| 186 | Audio::InstallInterfaces(*sm, system); | 209 | Audio::InstallInterfaces(*sm, system); |
| 187 | BCAT::InstallInterfaces(system); | 210 | BCAT::InstallInterfaces(system); |
| 188 | BPC::InstallInterfaces(*sm); | 211 | BPC::InstallInterfaces(*sm, system); |
| 189 | BtDrv::InstallInterfaces(*sm, system); | 212 | BtDrv::InstallInterfaces(*sm, system); |
| 190 | BTM::InstallInterfaces(*sm, system); | 213 | BTM::InstallInterfaces(*sm, system); |
| 191 | Capture::InstallInterfaces(*sm); | 214 | Capture::InstallInterfaces(*sm, system); |
| 192 | ERPT::InstallInterfaces(*sm); | 215 | ERPT::InstallInterfaces(*sm, system); |
| 193 | ES::InstallInterfaces(*sm); | 216 | ES::InstallInterfaces(*sm, system); |
| 194 | EUPLD::InstallInterfaces(*sm); | 217 | EUPLD::InstallInterfaces(*sm, system); |
| 195 | Fatal::InstallInterfaces(*sm, system); | 218 | Fatal::InstallInterfaces(*sm, system); |
| 196 | FGM::InstallInterfaces(*sm); | 219 | FGM::InstallInterfaces(*sm, system); |
| 197 | FileSystem::InstallInterfaces(system); | 220 | FileSystem::InstallInterfaces(system); |
| 198 | Friend::InstallInterfaces(*sm, system); | 221 | Friend::InstallInterfaces(*sm, system); |
| 199 | Glue::InstallInterfaces(system); | 222 | Glue::InstallInterfaces(system); |
| 200 | GRC::InstallInterfaces(*sm); | 223 | GRC::InstallInterfaces(*sm, system); |
| 201 | HID::InstallInterfaces(*sm, system); | 224 | HID::InstallInterfaces(*sm, system); |
| 202 | LBL::InstallInterfaces(*sm); | 225 | LBL::InstallInterfaces(*sm, system); |
| 203 | LDN::InstallInterfaces(*sm); | 226 | LDN::InstallInterfaces(*sm, system); |
| 204 | LDR::InstallInterfaces(*sm, system); | 227 | LDR::InstallInterfaces(*sm, system); |
| 205 | LM::InstallInterfaces(system); | 228 | LM::InstallInterfaces(system); |
| 206 | Migration::InstallInterfaces(*sm); | 229 | Migration::InstallInterfaces(*sm, system); |
| 207 | Mii::InstallInterfaces(*sm); | 230 | Mii::InstallInterfaces(*sm, system); |
| 208 | MM::InstallInterfaces(*sm); | 231 | MM::InstallInterfaces(*sm, system); |
| 209 | NCM::InstallInterfaces(*sm); | 232 | NCM::InstallInterfaces(*sm, system); |
| 210 | NFC::InstallInterfaces(*sm); | 233 | NFC::InstallInterfaces(*sm, system); |
| 211 | NFP::InstallInterfaces(*sm, system); | 234 | NFP::InstallInterfaces(*sm, system); |
| 212 | NIFM::InstallInterfaces(*sm, system); | 235 | NIFM::InstallInterfaces(*sm, system); |
| 213 | NIM::InstallInterfaces(*sm, system); | 236 | NIM::InstallInterfaces(*sm, system); |
| 214 | NPNS::InstallInterfaces(*sm); | 237 | NPNS::InstallInterfaces(*sm, system); |
| 215 | NS::InstallInterfaces(*sm, system); | 238 | NS::InstallInterfaces(*sm, system); |
| 216 | Nvidia::InstallInterfaces(*sm, *nv_flinger, system); | 239 | Nvidia::InstallInterfaces(*sm, *nv_flinger, system); |
| 217 | PCIe::InstallInterfaces(*sm); | 240 | OLSC::InstallInterfaces(*sm, system); |
| 218 | PCTL::InstallInterfaces(*sm); | 241 | PCIe::InstallInterfaces(*sm, system); |
| 219 | PCV::InstallInterfaces(*sm); | 242 | PCTL::InstallInterfaces(*sm, system); |
| 243 | PCV::InstallInterfaces(*sm, system); | ||
| 220 | PlayReport::InstallInterfaces(*sm, system); | 244 | PlayReport::InstallInterfaces(*sm, system); |
| 221 | PM::InstallInterfaces(system); | 245 | PM::InstallInterfaces(system); |
| 222 | PSC::InstallInterfaces(*sm); | 246 | PSC::InstallInterfaces(*sm, system); |
| 223 | PSM::InstallInterfaces(*sm); | 247 | PSM::InstallInterfaces(*sm, system); |
| 224 | Set::InstallInterfaces(*sm); | 248 | Set::InstallInterfaces(*sm, system); |
| 225 | Sockets::InstallInterfaces(*sm, system); | 249 | Sockets::InstallInterfaces(*sm, system); |
| 226 | SPL::InstallInterfaces(*sm); | 250 | SPL::InstallInterfaces(*sm, system); |
| 227 | SSL::InstallInterfaces(*sm); | 251 | SSL::InstallInterfaces(*sm, system); |
| 228 | Time::InstallInterfaces(system); | 252 | Time::InstallInterfaces(system); |
| 229 | USB::InstallInterfaces(*sm); | 253 | USB::InstallInterfaces(*sm, system); |
| 230 | VI::InstallInterfaces(*sm, nv_flinger); | 254 | VI::InstallInterfaces(*sm, system, *nv_flinger); |
| 231 | WLAN::InstallInterfaces(*sm); | 255 | WLAN::InstallInterfaces(*sm, system); |
| 232 | |||
| 233 | LOG_DEBUG(Service, "initialized OK"); | ||
| 234 | } | 256 | } |
| 235 | 257 | ||
| 236 | /// Shutdown ServiceManager | 258 | Services::~Services() = default; |
| 237 | void Shutdown() { | 259 | |
| 238 | LOG_DEBUG(Service, "shutdown OK"); | ||
| 239 | } | ||
| 240 | } // namespace Service | 260 | } // namespace Service |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index a01ef3353..916445517 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -5,9 +5,11 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <mutex> | ||
| 8 | #include <string> | 9 | #include <string> |
| 9 | #include <boost/container/flat_map.hpp> | 10 | #include <boost/container/flat_map.hpp> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/spin_lock.h" | ||
| 11 | #include "core/hle/kernel/hle_ipc.h" | 13 | #include "core/hle/kernel/hle_ipc.h" |
| 12 | #include "core/hle/kernel/object.h" | 14 | #include "core/hle/kernel/object.h" |
| 13 | 15 | ||
| @@ -29,7 +31,11 @@ namespace Service { | |||
| 29 | 31 | ||
| 30 | namespace FileSystem { | 32 | namespace FileSystem { |
| 31 | class FileSystemController; | 33 | class FileSystemController; |
| 32 | } // namespace FileSystem | 34 | } |
| 35 | |||
| 36 | namespace NVFlinger { | ||
| 37 | class NVFlinger; | ||
| 38 | } | ||
| 33 | 39 | ||
| 34 | namespace SM { | 40 | namespace SM { |
| 35 | class ServiceManager; | 41 | class ServiceManager; |
| @@ -64,11 +70,9 @@ public: | |||
| 64 | void InstallAsService(SM::ServiceManager& service_manager); | 70 | void InstallAsService(SM::ServiceManager& service_manager); |
| 65 | /// Creates a port pair and registers it on the kernel's global port registry. | 71 | /// Creates a port pair and registers it on the kernel's global port registry. |
| 66 | void InstallAsNamedPort(Kernel::KernelCore& kernel); | 72 | void InstallAsNamedPort(Kernel::KernelCore& kernel); |
| 67 | /// Creates and returns an unregistered port for the service. | 73 | /// Invokes a service request routine. |
| 68 | std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel); | ||
| 69 | |||
| 70 | void InvokeRequest(Kernel::HLERequestContext& ctx); | 74 | void InvokeRequest(Kernel::HLERequestContext& ctx); |
| 71 | 75 | /// Handles a synchronization request for the service. | |
| 72 | ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; | 76 | ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; |
| 73 | 77 | ||
| 74 | protected: | 78 | protected: |
| @@ -76,6 +80,14 @@ protected: | |||
| 76 | template <typename Self> | 80 | template <typename Self> |
| 77 | using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); | 81 | using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); |
| 78 | 82 | ||
| 83 | /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. | ||
| 84 | [[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() { | ||
| 85 | return std::scoped_lock{lock_service}; | ||
| 86 | } | ||
| 87 | |||
| 88 | /// System context that the service operates under. | ||
| 89 | Core::System& system; | ||
| 90 | |||
| 79 | private: | 91 | private: |
| 80 | template <typename T> | 92 | template <typename T> |
| 81 | friend class ServiceFramework; | 93 | friend class ServiceFramework; |
| @@ -89,7 +101,8 @@ private: | |||
| 89 | using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, | 101 | using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, |
| 90 | Kernel::HLERequestContext& ctx); | 102 | Kernel::HLERequestContext& ctx); |
| 91 | 103 | ||
| 92 | ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); | 104 | explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_, |
| 105 | u32 max_sessions_, InvokerFn* handler_invoker_); | ||
| 93 | ~ServiceFrameworkBase() override; | 106 | ~ServiceFrameworkBase() override; |
| 94 | 107 | ||
| 95 | void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); | 108 | void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); |
| @@ -107,6 +120,9 @@ private: | |||
| 107 | /// Function used to safely up-cast pointers to the derived class before invoking a handler. | 120 | /// Function used to safely up-cast pointers to the derived class before invoking a handler. |
| 108 | InvokerFn* handler_invoker; | 121 | InvokerFn* handler_invoker; |
| 109 | boost::container::flat_map<u32, FunctionInfoBase> handlers; | 122 | boost::container::flat_map<u32, FunctionInfoBase> handlers; |
| 123 | |||
| 124 | /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. | ||
| 125 | Common::SpinLock lock_service; | ||
| 110 | }; | 126 | }; |
| 111 | 127 | ||
| 112 | /** | 128 | /** |
| @@ -147,11 +163,15 @@ protected: | |||
| 147 | 163 | ||
| 148 | /** | 164 | /** |
| 149 | * Initializes the handler with no functions installed. | 165 | * Initializes the handler with no functions installed. |
| 150 | * @param max_sessions Maximum number of sessions that can be | 166 | * |
| 151 | * connected to this service at the same time. | 167 | * @param system_ The system context to construct this service under. |
| 168 | * @param service_name_ Name of the service. | ||
| 169 | * @param max_sessions_ Maximum number of sessions that can be | ||
| 170 | * connected to this service at the same time. | ||
| 152 | */ | 171 | */ |
| 153 | explicit ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) | 172 | explicit ServiceFramework(Core::System& system_, const char* service_name_, |
| 154 | : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} | 173 | u32 max_sessions_ = DefaultMaxSessions) |
| 174 | : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} | ||
| 155 | 175 | ||
| 156 | /// Registers handlers in the service. | 176 | /// Registers handlers in the service. |
| 157 | template <std::size_t N> | 177 | template <std::size_t N> |
| @@ -181,10 +201,17 @@ private: | |||
| 181 | } | 201 | } |
| 182 | }; | 202 | }; |
| 183 | 203 | ||
| 184 | /// Initialize ServiceManager | 204 | /** |
| 185 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | 205 | * The purpose of this class is to own any objects that need to be shared across the other service |
| 206 | * implementations. Will be torn down when the global system instance is shutdown. | ||
| 207 | */ | ||
| 208 | class Services final { | ||
| 209 | public: | ||
| 210 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | ||
| 211 | ~Services(); | ||
| 186 | 212 | ||
| 187 | /// Shutdown ServiceManager | 213 | private: |
| 188 | void Shutdown(); | 214 | std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 215 | }; | ||
| 189 | 216 | ||
| 190 | } // namespace Service | 217 | } // namespace Service |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index e64777668..d953b4303 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -188,7 +188,7 @@ void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) { | |||
| 188 | GetKeyCodeMapImpl(ctx); | 188 | GetKeyCodeMapImpl(ctx); |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | SET::SET() : ServiceFramework("set") { | 191 | SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { |
| 192 | // clang-format off | 192 | // clang-format off |
| 193 | static const FunctionInfo functions[] = { | 193 | static const FunctionInfo functions[] = { |
| 194 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, | 194 | {0, &SET::GetLanguageCode, "GetLanguageCode"}, |
| @@ -202,6 +202,7 @@ SET::SET() : ServiceFramework("set") { | |||
| 202 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, | 202 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, |
| 203 | {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, | 203 | {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, |
| 204 | {10, nullptr, "GetFirmwareVersionForDebug"}, | 204 | {10, nullptr, "GetFirmwareVersionForDebug"}, |
| 205 | {11, nullptr, "GetDeviceNickName"}, | ||
| 205 | }; | 206 | }; |
| 206 | // clang-format on | 207 | // clang-format on |
| 207 | 208 | ||
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 8ac9c169d..d5bd7828d 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Set { | 13 | namespace Service::Set { |
| 10 | 14 | ||
| 11 | /// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. | 15 | /// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. |
| @@ -32,7 +36,7 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t idx); | |||
| 32 | 36 | ||
| 33 | class SET final : public ServiceFramework<SET> { | 37 | class SET final : public ServiceFramework<SET> { |
| 34 | public: | 38 | public: |
| 35 | explicit SET(); | 39 | explicit SET(Core::System& system_); |
| 36 | ~SET() override; | 40 | ~SET() override; |
| 37 | 41 | ||
| 38 | private: | 42 | private: |
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp index 3fbfecc9e..b2aa7bc0c 100644 --- a/src/core/hle/service/set/set_cal.cpp +++ b/src/core/hle/service/set/set_cal.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Set { | 7 | namespace Service::Set { |
| 8 | 8 | ||
| 9 | SET_CAL::SET_CAL() : ServiceFramework("set:cal") { | 9 | SET_CAL::SET_CAL(Core::System& system_) : ServiceFramework{system_, "set:cal"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "GetBluetoothBdAddress"}, | 12 | {0, nullptr, "GetBluetoothBdAddress"}, |
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h index a0677e815..a29fc3ddd 100644 --- a/src/core/hle/service/set/set_cal.h +++ b/src/core/hle/service/set/set_cal.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Set { | 13 | namespace Service::Set { |
| 10 | 14 | ||
| 11 | class SET_CAL final : public ServiceFramework<SET_CAL> { | 15 | class SET_CAL final : public ServiceFramework<SET_CAL> { |
| 12 | public: | 16 | public: |
| 13 | explicit SET_CAL(); | 17 | explicit SET_CAL(Core::System& system_); |
| 14 | ~SET_CAL() override; | 18 | ~SET_CAL() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp index 565882a31..f04dc5047 100644 --- a/src/core/hle/service/set/set_fd.cpp +++ b/src/core/hle/service/set/set_fd.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Set { | 7 | namespace Service::Set { |
| 8 | 8 | ||
| 9 | SET_FD::SET_FD() : ServiceFramework("set:fd") { | 9 | SET_FD::SET_FD(Core::System& system_) : ServiceFramework{system_, "set:fd"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {2, nullptr, "SetSettingsItemValue"}, | 12 | {2, nullptr, "SetSettingsItemValue"}, |
diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h index 216e65f1f..c28cb301e 100644 --- a/src/core/hle/service/set/set_fd.h +++ b/src/core/hle/service/set/set_fd.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Set { | 13 | namespace Service::Set { |
| 10 | 14 | ||
| 11 | class SET_FD final : public ServiceFramework<SET_FD> { | 15 | class SET_FD final : public ServiceFramework<SET_FD> { |
| 12 | public: | 16 | public: |
| 13 | explicit SET_FD(); | 17 | explicit SET_FD(Core::System& system_); |
| 14 | ~SET_FD() override; | 18 | ~SET_FD() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 8bd4c7e79..b58b2c8c5 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -34,9 +34,9 @@ void GetFirmwareVersionImpl(Kernel::HLERequestContext& ctx, GetFirmwareVersionTy | |||
| 34 | // consistence (currently reports as 5.1.0-0.0) | 34 | // consistence (currently reports as 5.1.0-0.0) |
| 35 | const auto archive = FileSys::SystemArchive::SystemVersion(); | 35 | const auto archive = FileSys::SystemArchive::SystemVersion(); |
| 36 | 36 | ||
| 37 | const auto early_exit_failure = [&ctx](const std::string& desc, ResultCode code) { | 37 | const auto early_exit_failure = [&ctx](std::string_view desc, ResultCode code) { |
| 38 | LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", | 38 | LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", |
| 39 | desc.c_str()); | 39 | desc); |
| 40 | IPC::ResponseBuilder rb{ctx, 2}; | 40 | IPC::ResponseBuilder rb{ctx, 2}; |
| 41 | rb.Push(code); | 41 | rb.Push(code); |
| 42 | }; | 42 | }; |
| @@ -103,7 +103,7 @@ void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { | |||
| 103 | rb.Push(RESULT_SUCCESS); | 103 | rb.Push(RESULT_SUCCESS); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | 106 | SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { |
| 107 | // clang-format off | 107 | // clang-format off |
| 108 | static const FunctionInfo functions[] = { | 108 | static const FunctionInfo functions[] = { |
| 109 | {0, nullptr, "SetLanguageCode"}, | 109 | {0, nullptr, "SetLanguageCode"}, |
| @@ -300,6 +300,8 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | |||
| 300 | {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, | 300 | {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, |
| 301 | {199, nullptr, "GetButtonConfigRegisteredSettings"}, | 301 | {199, nullptr, "GetButtonConfigRegisteredSettings"}, |
| 302 | {200, nullptr, "SetButtonConfigRegisteredSettings"}, | 302 | {200, nullptr, "SetButtonConfigRegisteredSettings"}, |
| 303 | {201, nullptr, "GetFieldTestingFlag"}, | ||
| 304 | {202, nullptr, "SetFieldTestingFlag"}, | ||
| 303 | }; | 305 | }; |
| 304 | // clang-format on | 306 | // clang-format on |
| 305 | 307 | ||
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index 13ee2cf46..edb185a68 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Set { | 13 | namespace Service::Set { |
| 10 | 14 | ||
| 11 | class SET_SYS final : public ServiceFramework<SET_SYS> { | 15 | class SET_SYS final : public ServiceFramework<SET_SYS> { |
| 12 | public: | 16 | public: |
| 13 | explicit SET_SYS(); | 17 | explicit SET_SYS(Core::System& system_); |
| 14 | ~SET_SYS() override; | 18 | ~SET_SYS() override; |
| 15 | 19 | ||
| 16 | private: | 20 | private: |
diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp index cf5541ca8..212ebc427 100644 --- a/src/core/hle/service/set/settings.cpp +++ b/src/core/hle/service/set/settings.cpp | |||
| @@ -7,14 +7,15 @@ | |||
| 7 | #include "core/hle/service/set/set_fd.h" | 7 | #include "core/hle/service/set/set_fd.h" |
| 8 | #include "core/hle/service/set/set_sys.h" | 8 | #include "core/hle/service/set/set_sys.h" |
| 9 | #include "core/hle/service/set/settings.h" | 9 | #include "core/hle/service/set/settings.h" |
| 10 | #include "core/hle/service/sm/sm.h" | ||
| 10 | 11 | ||
| 11 | namespace Service::Set { | 12 | namespace Service::Set { |
| 12 | 13 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 14 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 14 | std::make_shared<SET>()->InstallAsService(service_manager); | 15 | std::make_shared<SET>(system)->InstallAsService(service_manager); |
| 15 | std::make_shared<SET_CAL>()->InstallAsService(service_manager); | 16 | std::make_shared<SET_CAL>(system)->InstallAsService(service_manager); |
| 16 | std::make_shared<SET_FD>()->InstallAsService(service_manager); | 17 | std::make_shared<SET_FD>(system)->InstallAsService(service_manager); |
| 17 | std::make_shared<SET_SYS>()->InstallAsService(service_manager); | 18 | std::make_shared<SET_SYS>(system)->InstallAsService(service_manager); |
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | } // namespace Service::Set | 21 | } // namespace Service::Set |
diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h index 6606ce776..7a6950dd0 100644 --- a/src/core/hle/service/set/settings.h +++ b/src/core/hle/service/set/settings.h | |||
| @@ -4,11 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | namespace Core { |
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Service::SM { | ||
| 12 | class ServiceManager; | ||
| 13 | } | ||
| 8 | 14 | ||
| 9 | namespace Service::Set { | 15 | namespace Service::Set { |
| 10 | 16 | ||
| 11 | /// Registers all Settings services with the specified service manager. | 17 | /// Registers all Settings services with the specified service manager. |
| 12 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 13 | 19 | ||
| 14 | } // namespace Service::Set | 20 | } // namespace Service::Set |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 972aaa6d9..916177efd 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -48,7 +48,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | // https://switchbrew.org/wiki/IPC_Marshalling | 50 | // https://switchbrew.org/wiki/IPC_Marshalling |
| 51 | Controller::Controller() : ServiceFramework("IpcController") { | 51 | Controller::Controller(Core::System& system_) : ServiceFramework{system_, "IpcController"} { |
| 52 | static const FunctionInfo functions[] = { | 52 | static const FunctionInfo functions[] = { |
| 53 | {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, | 53 | {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, |
| 54 | {1, nullptr, "CopyFromCurrentDomain"}, | 54 | {1, nullptr, "CopyFromCurrentDomain"}, |
diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h index 180c6da50..7494f898d 100644 --- a/src/core/hle/service/sm/controller.h +++ b/src/core/hle/service/sm/controller.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::SM { | 13 | namespace Service::SM { |
| 10 | 14 | ||
| 11 | class Controller final : public ServiceFramework<Controller> { | 15 | class Controller final : public ServiceFramework<Controller> { |
| 12 | public: | 16 | public: |
| 13 | Controller(); | 17 | explicit Controller(Core::System& system_); |
| 14 | ~Controller() override; | 18 | ~Controller() override; |
| 15 | 19 | ||
| 16 | private: | 20 | private: |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 9c1da361b..4da69f503 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -38,14 +38,13 @@ static ResultCode ValidateServiceName(const std::string& name) { | |||
| 38 | return RESULT_SUCCESS; | 38 | return RESULT_SUCCESS; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, | 41 | void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { |
| 42 | Kernel::KernelCore& kernel) { | ||
| 43 | ASSERT(self->sm_interface.expired()); | 42 | ASSERT(self->sm_interface.expired()); |
| 44 | 43 | ||
| 45 | auto sm = std::make_shared<SM>(self, kernel); | 44 | auto sm = std::make_shared<SM>(self, system); |
| 46 | sm->InstallAsNamedPort(kernel); | 45 | sm->InstallAsNamedPort(system.Kernel()); |
| 47 | self->sm_interface = sm; | 46 | self->sm_interface = sm; |
| 48 | self->controller_interface = std::make_unique<Controller>(); | 47 | self->controller_interface = std::make_unique<Controller>(system); |
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, | 50 | ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, |
| @@ -190,8 +189,9 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | |||
| 190 | rb.Push(service_manager->UnregisterService(name)); | 189 | rb.Push(service_manager->UnregisterService(name)); |
| 191 | } | 190 | } |
| 192 | 191 | ||
| 193 | SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel) | 192 | SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) |
| 194 | : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} { | 193 | : ServiceFramework{system_, "sm:", 4}, |
| 194 | service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { | ||
| 195 | static const FunctionInfo functions[] = { | 195 | static const FunctionInfo functions[] = { |
| 196 | {0x00000000, &SM::Initialize, "Initialize"}, | 196 | {0x00000000, &SM::Initialize, "Initialize"}, |
| 197 | {0x00000001, &SM::GetService, "GetService"}, | 197 | {0x00000001, &SM::GetService, "GetService"}, |
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 6790c86f0..3f46ae44f 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -16,6 +16,10 @@ | |||
| 16 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 17 | #include "core/hle/service/service.h" | 17 | #include "core/hle/service/service.h" |
| 18 | 18 | ||
| 19 | namespace Core { | ||
| 20 | class System; | ||
| 21 | } | ||
| 22 | |||
| 19 | namespace Kernel { | 23 | namespace Kernel { |
| 20 | class ClientPort; | 24 | class ClientPort; |
| 21 | class ClientSession; | 25 | class ClientSession; |
| @@ -31,7 +35,7 @@ class Controller; | |||
| 31 | /// Interface to "sm:" service | 35 | /// Interface to "sm:" service |
| 32 | class SM final : public ServiceFramework<SM> { | 36 | class SM final : public ServiceFramework<SM> { |
| 33 | public: | 37 | public: |
| 34 | explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel); | 38 | explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); |
| 35 | ~SM() override; | 39 | ~SM() override; |
| 36 | 40 | ||
| 37 | private: | 41 | private: |
| @@ -46,7 +50,7 @@ private: | |||
| 46 | 50 | ||
| 47 | class ServiceManager { | 51 | class ServiceManager { |
| 48 | public: | 52 | public: |
| 49 | static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel); | 53 | static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); |
| 50 | 54 | ||
| 51 | explicit ServiceManager(Kernel::KernelCore& kernel_); | 55 | explicit ServiceManager(Kernel::KernelCore& kernel_); |
| 52 | ~ServiceManager(); | 56 | ~ServiceManager(); |
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h deleted file mode 100644 index 2d53e52b6..000000000 --- a/src/core/hle/service/sockets/blocking_worker.h +++ /dev/null | |||
| @@ -1,161 +0,0 @@ | |||
| 1 | // Copyright 2020 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 <atomic> | ||
| 8 | #include <memory> | ||
| 9 | #include <string> | ||
| 10 | #include <string_view> | ||
| 11 | #include <thread> | ||
| 12 | #include <variant> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | #include <fmt/format.h> | ||
| 16 | |||
| 17 | #include "common/assert.h" | ||
| 18 | #include "common/microprofile.h" | ||
| 19 | #include "common/thread.h" | ||
| 20 | #include "core/core.h" | ||
| 21 | #include "core/hle/kernel/hle_ipc.h" | ||
| 22 | #include "core/hle/kernel/kernel.h" | ||
| 23 | #include "core/hle/kernel/thread.h" | ||
| 24 | #include "core/hle/kernel/writable_event.h" | ||
| 25 | |||
| 26 | namespace Service::Sockets { | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Worker abstraction to execute blocking calls on host without blocking the guest thread | ||
| 30 | * | ||
| 31 | * @tparam Service Service where the work is executed | ||
| 32 | * @tparam Types Types of work to execute | ||
| 33 | */ | ||
| 34 | template <class Service, class... Types> | ||
| 35 | class BlockingWorker { | ||
| 36 | using This = BlockingWorker<Service, Types...>; | ||
| 37 | using WorkVariant = std::variant<std::monostate, Types...>; | ||
| 38 | |||
| 39 | public: | ||
| 40 | /// Create a new worker | ||
| 41 | static std::unique_ptr<This> Create(Core::System& system, Service* service, | ||
| 42 | std::string_view name) { | ||
| 43 | return std::unique_ptr<This>(new This(system, service, name)); | ||
| 44 | } | ||
| 45 | |||
| 46 | ~BlockingWorker() { | ||
| 47 | while (!is_available.load(std::memory_order_relaxed)) { | ||
| 48 | // Busy wait until work is finished | ||
| 49 | std::this_thread::yield(); | ||
| 50 | } | ||
| 51 | // Monostate means to exit the thread | ||
| 52 | work = std::monostate{}; | ||
| 53 | work_event.Set(); | ||
| 54 | thread.join(); | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Try to capture the worker to send work after a success | ||
| 59 | * @returns True when the worker has been successfully captured | ||
| 60 | */ | ||
| 61 | bool TryCapture() { | ||
| 62 | bool expected = true; | ||
| 63 | return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed, | ||
| 64 | std::memory_order_relaxed); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Send work to this worker abstraction | ||
| 69 | * @see TryCapture must be called before attempting to call this function | ||
| 70 | */ | ||
| 71 | template <class Work> | ||
| 72 | void SendWork(Work new_work) { | ||
| 73 | ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured"); | ||
| 74 | work = std::move(new_work); | ||
| 75 | work_event.Set(); | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Generate a callback for @see SleepClientThread | ||
| 79 | template <class Work> | ||
| 80 | auto Callback() { | ||
| 81 | return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx, | ||
| 82 | Kernel::ThreadWakeupReason reason) { | ||
| 83 | ASSERT(reason == Kernel::ThreadWakeupReason::Signal); | ||
| 84 | std::get<Work>(work).Response(ctx); | ||
| 85 | is_available.store(true); | ||
| 86 | }; | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Get kernel event that will be signalled by the worker when the host operation finishes | ||
| 90 | std::shared_ptr<Kernel::WritableEvent> KernelEvent() const { | ||
| 91 | return kernel_event; | ||
| 92 | } | ||
| 93 | |||
| 94 | private: | ||
| 95 | explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) { | ||
| 96 | auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name)); | ||
| 97 | kernel_event = std::move(pair.writable); | ||
| 98 | thread = std::thread([this, &system, service, name] { Run(system, service, name); }); | ||
| 99 | } | ||
| 100 | |||
| 101 | void Run(Core::System& system, Service* service, std::string_view name) { | ||
| 102 | system.RegisterHostThread(); | ||
| 103 | |||
| 104 | const std::string thread_name = fmt::format("yuzu:{}", name); | ||
| 105 | MicroProfileOnThreadCreate(thread_name.c_str()); | ||
| 106 | Common::SetCurrentThreadName(thread_name.c_str()); | ||
| 107 | |||
| 108 | bool keep_running = true; | ||
| 109 | while (keep_running) { | ||
| 110 | work_event.Wait(); | ||
| 111 | |||
| 112 | const auto visit_fn = [service, &keep_running]<typename T>(T&& w) { | ||
| 113 | if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) { | ||
| 114 | keep_running = false; | ||
| 115 | } else { | ||
| 116 | w.Execute(service); | ||
| 117 | } | ||
| 118 | }; | ||
| 119 | std::visit(visit_fn, work); | ||
| 120 | |||
| 121 | kernel_event->Signal(); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | std::thread thread; | ||
| 126 | WorkVariant work; | ||
| 127 | Common::Event work_event; | ||
| 128 | std::shared_ptr<Kernel::WritableEvent> kernel_event; | ||
| 129 | std::atomic_bool is_available{true}; | ||
| 130 | }; | ||
| 131 | |||
| 132 | template <class Service, class... Types> | ||
| 133 | class BlockingWorkerPool { | ||
| 134 | using Worker = BlockingWorker<Service, Types...>; | ||
| 135 | |||
| 136 | public: | ||
| 137 | explicit BlockingWorkerPool(Core::System& system_, Service* service_) | ||
| 138 | : system{system_}, service{service_} {} | ||
| 139 | |||
| 140 | /// Returns a captured worker thread, creating new ones if necessary | ||
| 141 | Worker* CaptureWorker() { | ||
| 142 | for (auto& worker : workers) { | ||
| 143 | if (worker->TryCapture()) { | ||
| 144 | return worker.get(); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size())); | ||
| 148 | [[maybe_unused]] const bool success = new_worker->TryCapture(); | ||
| 149 | ASSERT(success); | ||
| 150 | |||
| 151 | return workers.emplace_back(std::move(new_worker)).get(); | ||
| 152 | } | ||
| 153 | |||
| 154 | private: | ||
| 155 | Core::System& system; | ||
| 156 | Service* const service; | ||
| 157 | |||
| 158 | std::vector<std::unique_ptr<Worker>> workers; | ||
| 159 | }; | ||
| 160 | |||
| 161 | } // namespace Service::Sockets | ||
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index a74be9370..2b824059d 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -30,7 +30,7 @@ bool IsConnectionBased(Type type) { | |||
| 30 | case Type::DGRAM: | 30 | case Type::DGRAM: |
| 31 | return false; | 31 | return false; |
| 32 | default: | 32 | default: |
| 33 | UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); | 33 | UNIMPLEMENTED_MSG("Unimplemented type={}", type); |
| 34 | return false; | 34 | return false; |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| @@ -178,13 +178,12 @@ void BSD::Poll(Kernel::HLERequestContext& ctx) { | |||
| 178 | 178 | ||
| 179 | LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout); | 179 | LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout); |
| 180 | 180 | ||
| 181 | ExecuteWork(ctx, "BSD:Poll", timeout != 0, | 181 | ExecuteWork(ctx, PollWork{ |
| 182 | PollWork{ | 182 | .nfds = nfds, |
| 183 | .nfds = nfds, | 183 | .timeout = timeout, |
| 184 | .timeout = timeout, | 184 | .read_buffer = ctx.ReadBuffer(), |
| 185 | .read_buffer = ctx.ReadBuffer(), | 185 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), |
| 186 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), | 186 | }); |
| 187 | }); | ||
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | void BSD::Accept(Kernel::HLERequestContext& ctx) { | 189 | void BSD::Accept(Kernel::HLERequestContext& ctx) { |
| @@ -193,11 +192,10 @@ void BSD::Accept(Kernel::HLERequestContext& ctx) { | |||
| 193 | 192 | ||
| 194 | LOG_DEBUG(Service, "called. fd={}", fd); | 193 | LOG_DEBUG(Service, "called. fd={}", fd); |
| 195 | 194 | ||
| 196 | ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd), | 195 | ExecuteWork(ctx, AcceptWork{ |
| 197 | AcceptWork{ | 196 | .fd = fd, |
| 198 | .fd = fd, | 197 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), |
| 199 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), | 198 | }); |
| 200 | }); | ||
| 201 | } | 199 | } |
| 202 | 200 | ||
| 203 | void BSD::Bind(Kernel::HLERequestContext& ctx) { | 201 | void BSD::Bind(Kernel::HLERequestContext& ctx) { |
| @@ -215,11 +213,10 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) { | |||
| 215 | 213 | ||
| 216 | LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); | 214 | LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); |
| 217 | 215 | ||
| 218 | ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd), | 216 | ExecuteWork(ctx, ConnectWork{ |
| 219 | ConnectWork{ | 217 | .fd = fd, |
| 220 | .fd = fd, | 218 | .addr = ctx.ReadBuffer(), |
| 221 | .addr = ctx.ReadBuffer(), | 219 | }); |
| 222 | }); | ||
| 223 | } | 220 | } |
| 224 | 221 | ||
| 225 | void BSD::GetPeerName(Kernel::HLERequestContext& ctx) { | 222 | void BSD::GetPeerName(Kernel::HLERequestContext& ctx) { |
| @@ -327,12 +324,11 @@ void BSD::Recv(Kernel::HLERequestContext& ctx) { | |||
| 327 | 324 | ||
| 328 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize()); | 325 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize()); |
| 329 | 326 | ||
| 330 | ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd), | 327 | ExecuteWork(ctx, RecvWork{ |
| 331 | RecvWork{ | 328 | .fd = fd, |
| 332 | .fd = fd, | 329 | .flags = flags, |
| 333 | .flags = flags, | 330 | .message = std::vector<u8>(ctx.GetWriteBufferSize()), |
| 334 | .message = std::vector<u8>(ctx.GetWriteBufferSize()), | 331 | }); |
| 335 | }); | ||
| 336 | } | 332 | } |
| 337 | 333 | ||
| 338 | void BSD::RecvFrom(Kernel::HLERequestContext& ctx) { | 334 | void BSD::RecvFrom(Kernel::HLERequestContext& ctx) { |
| @@ -344,13 +340,12 @@ void BSD::RecvFrom(Kernel::HLERequestContext& ctx) { | |||
| 344 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags, | 340 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags, |
| 345 | ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1)); | 341 | ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1)); |
| 346 | 342 | ||
| 347 | ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd), | 343 | ExecuteWork(ctx, RecvFromWork{ |
| 348 | RecvFromWork{ | 344 | .fd = fd, |
| 349 | .fd = fd, | 345 | .flags = flags, |
| 350 | .flags = flags, | 346 | .message = std::vector<u8>(ctx.GetWriteBufferSize(0)), |
| 351 | .message = std::vector<u8>(ctx.GetWriteBufferSize(0)), | 347 | .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)), |
| 352 | .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)), | 348 | }); |
| 353 | }); | ||
| 354 | } | 349 | } |
| 355 | 350 | ||
| 356 | void BSD::Send(Kernel::HLERequestContext& ctx) { | 351 | void BSD::Send(Kernel::HLERequestContext& ctx) { |
| @@ -361,12 +356,11 @@ void BSD::Send(Kernel::HLERequestContext& ctx) { | |||
| 361 | 356 | ||
| 362 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize()); | 357 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize()); |
| 363 | 358 | ||
| 364 | ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd), | 359 | ExecuteWork(ctx, SendWork{ |
| 365 | SendWork{ | 360 | .fd = fd, |
| 366 | .fd = fd, | 361 | .flags = flags, |
| 367 | .flags = flags, | 362 | .message = ctx.ReadBuffer(), |
| 368 | .message = ctx.ReadBuffer(), | 363 | }); |
| 369 | }); | ||
| 370 | } | 364 | } |
| 371 | 365 | ||
| 372 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { | 366 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { |
| @@ -377,13 +371,12 @@ void BSD::SendTo(Kernel::HLERequestContext& ctx) { | |||
| 377 | LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags, | 371 | LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags, |
| 378 | ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1)); | 372 | ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1)); |
| 379 | 373 | ||
| 380 | ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd), | 374 | ExecuteWork(ctx, SendToWork{ |
| 381 | SendToWork{ | 375 | .fd = fd, |
| 382 | .fd = fd, | 376 | .flags = flags, |
| 383 | .flags = flags, | 377 | .message = ctx.ReadBuffer(0), |
| 384 | .message = ctx.ReadBuffer(0), | 378 | .addr = ctx.ReadBuffer(1), |
| 385 | .addr = ctx.ReadBuffer(1), | 379 | }); |
| 386 | }); | ||
| 387 | } | 380 | } |
| 388 | 381 | ||
| 389 | void BSD::Write(Kernel::HLERequestContext& ctx) { | 382 | void BSD::Write(Kernel::HLERequestContext& ctx) { |
| @@ -392,12 +385,11 @@ void BSD::Write(Kernel::HLERequestContext& ctx) { | |||
| 392 | 385 | ||
| 393 | LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize()); | 386 | LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize()); |
| 394 | 387 | ||
| 395 | ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd), | 388 | ExecuteWork(ctx, SendWork{ |
| 396 | SendWork{ | 389 | .fd = fd, |
| 397 | .fd = fd, | 390 | .flags = 0, |
| 398 | .flags = 0, | 391 | .message = ctx.ReadBuffer(), |
| 399 | .message = ctx.ReadBuffer(), | 392 | }); |
| 400 | }); | ||
| 401 | } | 393 | } |
| 402 | 394 | ||
| 403 | void BSD::Close(Kernel::HLERequestContext& ctx) { | 395 | void BSD::Close(Kernel::HLERequestContext& ctx) { |
| @@ -410,24 +402,9 @@ void BSD::Close(Kernel::HLERequestContext& ctx) { | |||
| 410 | } | 402 | } |
| 411 | 403 | ||
| 412 | template <typename Work> | 404 | template <typename Work> |
| 413 | void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, | 405 | void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) { |
| 414 | bool is_blocking, Work work) { | 406 | work.Execute(this); |
| 415 | if (!is_blocking) { | ||
| 416 | work.Execute(this); | ||
| 417 | work.Response(ctx); | ||
| 418 | return; | ||
| 419 | } | ||
| 420 | |||
| 421 | // Signal a dummy response to make IPC validation happy | ||
| 422 | // This will be overwritten by the SleepClientThread callback | ||
| 423 | work.Response(ctx); | 407 | work.Response(ctx); |
| 424 | |||
| 425 | auto worker = worker_pool.CaptureWorker(); | ||
| 426 | |||
| 427 | ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(), | ||
| 428 | worker->Callback<Work>(), worker->KernelEvent()); | ||
| 429 | |||
| 430 | worker->SendWork(std::move(work)); | ||
| 431 | } | 408 | } |
| 432 | 409 | ||
| 433 | std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) { | 410 | std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) { |
| @@ -489,18 +466,18 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u | |||
| 489 | } | 466 | } |
| 490 | 467 | ||
| 491 | for (PollFD& pollfd : fds) { | 468 | for (PollFD& pollfd : fds) { |
| 492 | ASSERT(pollfd.revents == 0); | 469 | ASSERT(False(pollfd.revents)); |
| 493 | 470 | ||
| 494 | if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) { | 471 | if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) { |
| 495 | LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd); | 472 | LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd); |
| 496 | pollfd.revents = 0; | 473 | pollfd.revents = PollEvents{}; |
| 497 | return {0, Errno::SUCCESS}; | 474 | return {0, Errno::SUCCESS}; |
| 498 | } | 475 | } |
| 499 | 476 | ||
| 500 | const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; | 477 | const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; |
| 501 | if (!descriptor) { | 478 | if (!descriptor) { |
| 502 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); | 479 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); |
| 503 | pollfd.revents = POLL_NVAL; | 480 | pollfd.revents = PollEvents::Nval; |
| 504 | return {0, Errno::SUCCESS}; | 481 | return {0, Errno::SUCCESS}; |
| 505 | } | 482 | } |
| 506 | } | 483 | } |
| @@ -510,7 +487,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u | |||
| 510 | Network::PollFD result; | 487 | Network::PollFD result; |
| 511 | result.socket = file_descriptors[pollfd.fd]->socket.get(); | 488 | result.socket = file_descriptors[pollfd.fd]->socket.get(); |
| 512 | result.events = TranslatePollEventsToHost(pollfd.events); | 489 | result.events = TranslatePollEventsToHost(pollfd.events); |
| 513 | result.revents = 0; | 490 | result.revents = Network::PollEvents{}; |
| 514 | return result; | 491 | return result; |
| 515 | }); | 492 | }); |
| 516 | 493 | ||
| @@ -636,7 +613,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) { | |||
| 636 | return {0, Errno::SUCCESS}; | 613 | return {0, Errno::SUCCESS}; |
| 637 | } | 614 | } |
| 638 | default: | 615 | default: |
| 639 | UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd)); | 616 | UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd); |
| 640 | return {-1, Errno::SUCCESS}; | 617 | return {-1, Errno::SUCCESS}; |
| 641 | } | 618 | } |
| 642 | } | 619 | } |
| @@ -679,7 +656,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con | |||
| 679 | case OptName::RCVTIMEO: | 656 | case OptName::RCVTIMEO: |
| 680 | return Translate(socket->SetRcvTimeo(value)); | 657 | return Translate(socket->SetRcvTimeo(value)); |
| 681 | default: | 658 | default: |
| 682 | UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname)); | 659 | UNIMPLEMENTED_MSG("Unimplemented optname={}", optname); |
| 683 | return Errno::SUCCESS; | 660 | return Errno::SUCCESS; |
| 684 | } | 661 | } |
| 685 | } | 662 | } |
| @@ -807,18 +784,6 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept { | |||
| 807 | return true; | 784 | return true; |
| 808 | } | 785 | } |
| 809 | 786 | ||
| 810 | bool BSD::IsBlockingSocket(s32 fd) const noexcept { | ||
| 811 | // Inform invalid sockets as non-blocking | ||
| 812 | // This way we avoid using a worker thread as it will fail without blocking host | ||
| 813 | if (fd > static_cast<s32>(MAX_FD) || fd < 0) { | ||
| 814 | return false; | ||
| 815 | } | ||
| 816 | if (!file_descriptors[fd]) { | ||
| 817 | return false; | ||
| 818 | } | ||
| 819 | return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0; | ||
| 820 | } | ||
| 821 | |||
| 822 | void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept { | 787 | void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept { |
| 823 | IPC::ResponseBuilder rb{ctx, 4}; | 788 | IPC::ResponseBuilder rb{ctx, 4}; |
| 824 | 789 | ||
| @@ -827,8 +792,7 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co | |||
| 827 | rb.PushEnum(bsd_errno); | 792 | rb.PushEnum(bsd_errno); |
| 828 | } | 793 | } |
| 829 | 794 | ||
| 830 | BSD::BSD(Core::System& system, const char* name) | 795 | BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { |
| 831 | : ServiceFramework(name), worker_pool{system, this} { | ||
| 832 | // clang-format off | 796 | // clang-format off |
| 833 | static const FunctionInfo functions[] = { | 797 | static const FunctionInfo functions[] = { |
| 834 | {0, &BSD::RegisterClient, "RegisterClient"}, | 798 | {0, &BSD::RegisterClient, "RegisterClient"}, |
| @@ -873,7 +837,7 @@ BSD::BSD(Core::System& system, const char* name) | |||
| 873 | 837 | ||
| 874 | BSD::~BSD() = default; | 838 | BSD::~BSD() = default; |
| 875 | 839 | ||
| 876 | BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { | 840 | BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { |
| 877 | // clang-format off | 841 | // clang-format off |
| 878 | static const FunctionInfo functions[] = { | 842 | static const FunctionInfo functions[] = { |
| 879 | {0, nullptr, "SetIfUp"}, | 843 | {0, nullptr, "SetIfUp"}, |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 357531951..6da0bfeb2 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/hle_ipc.h" | 12 | #include "core/hle/kernel/hle_ipc.h" |
| 13 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 14 | #include "core/hle/service/sockets/blocking_worker.h" | ||
| 15 | #include "core/hle/service/sockets/sockets.h" | 14 | #include "core/hle/service/sockets/sockets.h" |
| 16 | 15 | ||
| 17 | namespace Core { | 16 | namespace Core { |
| @@ -26,7 +25,7 @@ namespace Service::Sockets { | |||
| 26 | 25 | ||
| 27 | class BSD final : public ServiceFramework<BSD> { | 26 | class BSD final : public ServiceFramework<BSD> { |
| 28 | public: | 27 | public: |
| 29 | explicit BSD(Core::System& system, const char* name); | 28 | explicit BSD(Core::System& system_, const char* name); |
| 30 | ~BSD() override; | 29 | ~BSD() override; |
| 31 | 30 | ||
| 32 | private: | 31 | private: |
| @@ -138,8 +137,7 @@ private: | |||
| 138 | void Close(Kernel::HLERequestContext& ctx); | 137 | void Close(Kernel::HLERequestContext& ctx); |
| 139 | 138 | ||
| 140 | template <typename Work> | 139 | template <typename Work> |
| 141 | void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, | 140 | void ExecuteWork(Kernel::HLERequestContext& ctx, Work work); |
| 142 | bool is_blocking, Work work); | ||
| 143 | 141 | ||
| 144 | std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); | 142 | std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); |
| 145 | std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, | 143 | std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, |
| @@ -163,20 +161,15 @@ private: | |||
| 163 | 161 | ||
| 164 | s32 FindFreeFileDescriptorHandle() noexcept; | 162 | s32 FindFreeFileDescriptorHandle() noexcept; |
| 165 | bool IsFileDescriptorValid(s32 fd) const noexcept; | 163 | bool IsFileDescriptorValid(s32 fd) const noexcept; |
| 166 | bool IsBlockingSocket(s32 fd) const noexcept; | ||
| 167 | 164 | ||
| 168 | void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; | 165 | void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; |
| 169 | 166 | ||
| 170 | std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; | 167 | std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; |
| 171 | |||
| 172 | BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork, | ||
| 173 | SendToWork> | ||
| 174 | worker_pool; | ||
| 175 | }; | 168 | }; |
| 176 | 169 | ||
| 177 | class BSDCFG final : public ServiceFramework<BSDCFG> { | 170 | class BSDCFG final : public ServiceFramework<BSDCFG> { |
| 178 | public: | 171 | public: |
| 179 | explicit BSDCFG(); | 172 | explicit BSDCFG(Core::System& system_); |
| 180 | ~BSDCFG() override; | 173 | ~BSDCFG() override; |
| 181 | }; | 174 | }; |
| 182 | 175 | ||
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp index abbeb4c50..05681ca2d 100644 --- a/src/core/hle/service/sockets/ethc.cpp +++ b/src/core/hle/service/sockets/ethc.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Sockets { | 7 | namespace Service::Sockets { |
| 8 | 8 | ||
| 9 | ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { | 9 | ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, nullptr, "Initialize"}, | 12 | {0, nullptr, "Initialize"}, |
| @@ -23,7 +23,7 @@ ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { | |||
| 23 | 23 | ||
| 24 | ETHC_C::~ETHC_C() = default; | 24 | ETHC_C::~ETHC_C() = default; |
| 25 | 25 | ||
| 26 | ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { | 26 | ETHC_I::ETHC_I(Core::System& system_) : ServiceFramework{system_, "ethc:i"} { |
| 27 | // clang-format off | 27 | // clang-format off |
| 28 | static const FunctionInfo functions[] = { | 28 | static const FunctionInfo functions[] = { |
| 29 | {0, nullptr, "GetReadableHandle"}, | 29 | {0, nullptr, "GetReadableHandle"}, |
diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h index da2c7f741..71884182e 100644 --- a/src/core/hle/service/sockets/ethc.h +++ b/src/core/hle/service/sockets/ethc.h | |||
| @@ -6,17 +6,21 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Sockets { | 13 | namespace Service::Sockets { |
| 10 | 14 | ||
| 11 | class ETHC_C final : public ServiceFramework<ETHC_C> { | 15 | class ETHC_C final : public ServiceFramework<ETHC_C> { |
| 12 | public: | 16 | public: |
| 13 | explicit ETHC_C(); | 17 | explicit ETHC_C(Core::System& system_); |
| 14 | ~ETHC_C() override; | 18 | ~ETHC_C() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
| 17 | class ETHC_I final : public ServiceFramework<ETHC_I> { | 21 | class ETHC_I final : public ServiceFramework<ETHC_I> { |
| 18 | public: | 22 | public: |
| 19 | explicit ETHC_I(); | 23 | explicit ETHC_I(Core::System& system_); |
| 20 | ~ETHC_I() override; | 24 | ~ETHC_I() override; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index 40d781124..51c3739bb 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Sockets { | 7 | namespace Service::Sockets { |
| 8 | 8 | ||
| 9 | NSD::NSD(const char* name) : ServiceFramework(name) { | 9 | NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { |
| 10 | // clang-format off | 10 | // clang-format off |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {10, nullptr, "GetSettingName"}, | 12 | {10, nullptr, "GetSettingName"}, |
diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h index d842e3232..becf93125 100644 --- a/src/core/hle/service/sockets/nsd.h +++ b/src/core/hle/service/sockets/nsd.h | |||
| @@ -4,14 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | ||
| 8 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 9 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 10 | namespace Service::Sockets { | 13 | namespace Service::Sockets { |
| 11 | 14 | ||
| 12 | class NSD final : public ServiceFramework<NSD> { | 15 | class NSD final : public ServiceFramework<NSD> { |
| 13 | public: | 16 | public: |
| 14 | explicit NSD(const char* name); | 17 | explicit NSD(Core::System& system_, const char* name); |
| 15 | ~NSD() override; | 18 | ~NSD() override; |
| 16 | }; | 19 | }; |
| 17 | 20 | ||
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index e3017451f..3a6329f56 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp | |||
| @@ -7,25 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | namespace Service::Sockets { | 8 | namespace Service::Sockets { |
| 9 | 9 | ||
| 10 | void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { | 10 | SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} { |
| 11 | struct Parameters { | ||
| 12 | u8 use_nsd_resolve; | ||
| 13 | u32 unknown; | ||
| 14 | u64 process_id; | ||
| 15 | }; | ||
| 16 | |||
| 17 | IPC::RequestParser rp{ctx}; | ||
| 18 | const auto parameters = rp.PopRaw<Parameters>(); | ||
| 19 | |||
| 20 | LOG_WARNING(Service, | ||
| 21 | "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}", | ||
| 22 | parameters.use_nsd_resolve, parameters.unknown, parameters.process_id); | ||
| 23 | |||
| 24 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 25 | rb.Push(RESULT_SUCCESS); | ||
| 26 | } | ||
| 27 | |||
| 28 | SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { | ||
| 29 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 30 | {0, nullptr, "SetDnsAddressesPrivate"}, | 12 | {0, nullptr, "SetDnsAddressesPrivate"}, |
| 31 | {1, nullptr, "GetDnsAddressPrivate"}, | 13 | {1, nullptr, "GetDnsAddressPrivate"}, |
| @@ -49,4 +31,22 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { | |||
| 49 | 31 | ||
| 50 | SFDNSRES::~SFDNSRES() = default; | 32 | SFDNSRES::~SFDNSRES() = default; |
| 51 | 33 | ||
| 34 | void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { | ||
| 35 | struct Parameters { | ||
| 36 | u8 use_nsd_resolve; | ||
| 37 | u32 unknown; | ||
| 38 | u64 process_id; | ||
| 39 | }; | ||
| 40 | |||
| 41 | IPC::RequestParser rp{ctx}; | ||
| 42 | const auto parameters = rp.PopRaw<Parameters>(); | ||
| 43 | |||
| 44 | LOG_WARNING(Service, | ||
| 45 | "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}", | ||
| 46 | parameters.use_nsd_resolve, parameters.unknown, parameters.process_id); | ||
| 47 | |||
| 48 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 49 | rb.Push(RESULT_SUCCESS); | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace Service::Sockets | 52 | } // namespace Service::Sockets |
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index acd3647bb..faa6b7d0d 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h | |||
| @@ -7,11 +7,15 @@ | |||
| 7 | #include "core/hle/kernel/hle_ipc.h" | 7 | #include "core/hle/kernel/hle_ipc.h" |
| 8 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 9 | 9 | ||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Service::Sockets { | 14 | namespace Service::Sockets { |
| 11 | 15 | ||
| 12 | class SFDNSRES final : public ServiceFramework<SFDNSRES> { | 16 | class SFDNSRES final : public ServiceFramework<SFDNSRES> { |
| 13 | public: | 17 | public: |
| 14 | explicit SFDNSRES(); | 18 | explicit SFDNSRES(Core::System& system_); |
| 15 | ~SFDNSRES() override; | 19 | ~SFDNSRES() override; |
| 16 | 20 | ||
| 17 | private: | 21 | private: |
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp index 1d27f7906..96f73bce3 100644 --- a/src/core/hle/service/sockets/sockets.cpp +++ b/src/core/hle/service/sockets/sockets.cpp | |||
| @@ -13,15 +13,15 @@ namespace Service::Sockets { | |||
| 13 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 13 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 14 | std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager); | 14 | std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager); |
| 15 | std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager); | 15 | std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager); |
| 16 | std::make_shared<BSDCFG>()->InstallAsService(service_manager); | 16 | std::make_shared<BSDCFG>(system)->InstallAsService(service_manager); |
| 17 | 17 | ||
| 18 | std::make_shared<ETHC_C>()->InstallAsService(service_manager); | 18 | std::make_shared<ETHC_C>(system)->InstallAsService(service_manager); |
| 19 | std::make_shared<ETHC_I>()->InstallAsService(service_manager); | 19 | std::make_shared<ETHC_I>(system)->InstallAsService(service_manager); |
| 20 | 20 | ||
| 21 | std::make_shared<NSD>("nsd:a")->InstallAsService(service_manager); | 21 | std::make_shared<NSD>(system, "nsd:a")->InstallAsService(service_manager); |
| 22 | std::make_shared<NSD>("nsd:u")->InstallAsService(service_manager); | 22 | std::make_shared<NSD>(system, "nsd:u")->InstallAsService(service_manager); |
| 23 | 23 | ||
| 24 | std::make_shared<SFDNSRES>()->InstallAsService(service_manager); | 24 | std::make_shared<SFDNSRES>(system)->InstallAsService(service_manager); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | } // namespace Service::Sockets | 27 | } // namespace Service::Sockets |
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index 89a410076..5a65ed2a9 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h | |||
| @@ -69,10 +69,22 @@ struct SockAddrIn { | |||
| 69 | std::array<u8, 8> zeroes; | 69 | std::array<u8, 8> zeroes; |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | enum class PollEvents : u16 { | ||
| 73 | // Using Pascal case because IN is a macro on Windows. | ||
| 74 | In = 1 << 0, | ||
| 75 | Pri = 1 << 1, | ||
| 76 | Out = 1 << 2, | ||
| 77 | Err = 1 << 3, | ||
| 78 | Hup = 1 << 4, | ||
| 79 | Nval = 1 << 5, | ||
| 80 | }; | ||
| 81 | |||
| 82 | DECLARE_ENUM_FLAG_OPERATORS(PollEvents); | ||
| 83 | |||
| 72 | struct PollFD { | 84 | struct PollFD { |
| 73 | s32 fd; | 85 | s32 fd; |
| 74 | u16 events; | 86 | PollEvents events; |
| 75 | u16 revents; | 87 | PollEvents revents; |
| 76 | }; | 88 | }; |
| 77 | 89 | ||
| 78 | struct Linger { | 90 | struct Linger { |
| @@ -80,13 +92,6 @@ struct Linger { | |||
| 80 | u32 linger; | 92 | u32 linger; |
| 81 | }; | 93 | }; |
| 82 | 94 | ||
| 83 | constexpr u16 POLL_IN = 0x01; | ||
| 84 | constexpr u16 POLL_PRI = 0x02; | ||
| 85 | constexpr u16 POLL_OUT = 0x04; | ||
| 86 | constexpr u16 POLL_ERR = 0x08; | ||
| 87 | constexpr u16 POLL_HUP = 0x10; | ||
| 88 | constexpr u16 POLL_NVAL = 0x20; | ||
| 89 | |||
| 90 | constexpr u32 FLAG_MSG_DONTWAIT = 0x80; | 95 | constexpr u32 FLAG_MSG_DONTWAIT = 0x80; |
| 91 | 96 | ||
| 92 | constexpr u32 FLAG_O_NONBLOCK = 0x800; | 97 | constexpr u32 FLAG_O_NONBLOCK = 0x800; |
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index 139743e1d..ca61d72ca 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp | |||
| @@ -27,7 +27,7 @@ Errno Translate(Network::Errno value) { | |||
| 27 | case Network::Errno::NOTCONN: | 27 | case Network::Errno::NOTCONN: |
| 28 | return Errno::NOTCONN; | 28 | return Errno::NOTCONN; |
| 29 | default: | 29 | default: |
| 30 | UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value)); | 30 | UNIMPLEMENTED_MSG("Unimplemented errno={}", value); |
| 31 | return Errno::SUCCESS; | 31 | return Errno::SUCCESS; |
| 32 | } | 32 | } |
| 33 | } | 33 | } |
| @@ -41,7 +41,7 @@ Network::Domain Translate(Domain domain) { | |||
| 41 | case Domain::INET: | 41 | case Domain::INET: |
| 42 | return Network::Domain::INET; | 42 | return Network::Domain::INET; |
| 43 | default: | 43 | default: |
| 44 | UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); | 44 | UNIMPLEMENTED_MSG("Unimplemented domain={}", domain); |
| 45 | return {}; | 45 | return {}; |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| @@ -51,7 +51,7 @@ Domain Translate(Network::Domain domain) { | |||
| 51 | case Network::Domain::INET: | 51 | case Network::Domain::INET: |
| 52 | return Domain::INET; | 52 | return Domain::INET; |
| 53 | default: | 53 | default: |
| 54 | UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); | 54 | UNIMPLEMENTED_MSG("Unimplemented domain={}", domain); |
| 55 | return {}; | 55 | return {}; |
| 56 | } | 56 | } |
| 57 | } | 57 | } |
| @@ -63,7 +63,8 @@ Network::Type Translate(Type type) { | |||
| 63 | case Type::DGRAM: | 63 | case Type::DGRAM: |
| 64 | return Network::Type::DGRAM; | 64 | return Network::Type::DGRAM; |
| 65 | default: | 65 | default: |
| 66 | UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); | 66 | UNIMPLEMENTED_MSG("Unimplemented type={}", type); |
| 67 | return Network::Type{}; | ||
| 67 | } | 68 | } |
| 68 | } | 69 | } |
| 69 | 70 | ||
| @@ -84,47 +85,47 @@ Network::Protocol Translate(Type type, Protocol protocol) { | |||
| 84 | case Protocol::UDP: | 85 | case Protocol::UDP: |
| 85 | return Network::Protocol::UDP; | 86 | return Network::Protocol::UDP; |
| 86 | default: | 87 | default: |
| 87 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); | 88 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol); |
| 88 | return Network::Protocol::TCP; | 89 | return Network::Protocol::TCP; |
| 89 | } | 90 | } |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | u16 TranslatePollEventsToHost(u16 flags) { | 93 | Network::PollEvents TranslatePollEventsToHost(PollEvents flags) { |
| 93 | u16 result = 0; | 94 | Network::PollEvents result{}; |
| 94 | const auto translate = [&result, &flags](u16 from, u16 to) { | 95 | const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) { |
| 95 | if ((flags & from) != 0) { | 96 | if (True(flags & from)) { |
| 96 | flags &= ~from; | 97 | flags &= ~from; |
| 97 | result |= to; | 98 | result |= to; |
| 98 | } | 99 | } |
| 99 | }; | 100 | }; |
| 100 | translate(POLL_IN, Network::POLL_IN); | 101 | translate(PollEvents::In, Network::PollEvents::In); |
| 101 | translate(POLL_PRI, Network::POLL_PRI); | 102 | translate(PollEvents::Pri, Network::PollEvents::Pri); |
| 102 | translate(POLL_OUT, Network::POLL_OUT); | 103 | translate(PollEvents::Out, Network::PollEvents::Out); |
| 103 | translate(POLL_ERR, Network::POLL_ERR); | 104 | translate(PollEvents::Err, Network::PollEvents::Err); |
| 104 | translate(POLL_HUP, Network::POLL_HUP); | 105 | translate(PollEvents::Hup, Network::PollEvents::Hup); |
| 105 | translate(POLL_NVAL, Network::POLL_NVAL); | 106 | translate(PollEvents::Nval, Network::PollEvents::Nval); |
| 106 | 107 | ||
| 107 | UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); | 108 | UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags); |
| 108 | return result; | 109 | return result; |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | u16 TranslatePollEventsToGuest(u16 flags) { | 112 | PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) { |
| 112 | u16 result = 0; | 113 | PollEvents result{}; |
| 113 | const auto translate = [&result, &flags](u16 from, u16 to) { | 114 | const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) { |
| 114 | if ((flags & from) != 0) { | 115 | if (True(flags & from)) { |
| 115 | flags &= ~from; | 116 | flags &= ~from; |
| 116 | result |= to; | 117 | result |= to; |
| 117 | } | 118 | } |
| 118 | }; | 119 | }; |
| 119 | 120 | ||
| 120 | translate(Network::POLL_IN, POLL_IN); | 121 | translate(Network::PollEvents::In, PollEvents::In); |
| 121 | translate(Network::POLL_PRI, POLL_PRI); | 122 | translate(Network::PollEvents::Pri, PollEvents::Pri); |
| 122 | translate(Network::POLL_OUT, POLL_OUT); | 123 | translate(Network::PollEvents::Out, PollEvents::Out); |
| 123 | translate(Network::POLL_ERR, POLL_ERR); | 124 | translate(Network::PollEvents::Err, PollEvents::Err); |
| 124 | translate(Network::POLL_HUP, POLL_HUP); | 125 | translate(Network::PollEvents::Hup, PollEvents::Hup); |
| 125 | translate(Network::POLL_NVAL, POLL_NVAL); | 126 | translate(Network::PollEvents::Nval, PollEvents::Nval); |
| 126 | 127 | ||
| 127 | UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); | 128 | UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags); |
| 128 | return result; | 129 | return result; |
| 129 | } | 130 | } |
| 130 | 131 | ||
| @@ -157,7 +158,7 @@ Network::ShutdownHow Translate(ShutdownHow how) { | |||
| 157 | case ShutdownHow::RDWR: | 158 | case ShutdownHow::RDWR: |
| 158 | return Network::ShutdownHow::RDWR; | 159 | return Network::ShutdownHow::RDWR; |
| 159 | default: | 160 | default: |
| 160 | UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how)); | 161 | UNIMPLEMENTED_MSG("Unimplemented how={}", how); |
| 161 | return {}; | 162 | return {}; |
| 162 | } | 163 | } |
| 163 | } | 164 | } |
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h index 8ed041e31..057d1ff22 100644 --- a/src/core/hle/service/sockets/sockets_translate.h +++ b/src/core/hle/service/sockets/sockets_translate.h | |||
| @@ -31,10 +31,10 @@ Network::Type Translate(Type type); | |||
| 31 | Network::Protocol Translate(Type type, Protocol protocol); | 31 | Network::Protocol Translate(Type type, Protocol protocol); |
| 32 | 32 | ||
| 33 | /// Translate abstract poll event flags to guest poll event flags | 33 | /// Translate abstract poll event flags to guest poll event flags |
| 34 | u16 TranslatePollEventsToHost(u16 flags); | 34 | Network::PollEvents TranslatePollEventsToHost(PollEvents flags); |
| 35 | 35 | ||
| 36 | /// Translate guest poll event flags to abstract poll event flags | 36 | /// Translate guest poll event flags to abstract poll event flags |
| 37 | u16 TranslatePollEventsToGuest(u16 flags); | 37 | PollEvents TranslatePollEventsToGuest(Network::PollEvents flags); |
| 38 | 38 | ||
| 39 | /// Translate guest socket address structure to abstract socket address structure | 39 | /// Translate guest socket address structure to abstract socket address structure |
| 40 | Network::SockAddrIn Translate(SockAddrIn value); | 40 | Network::SockAddrIn Translate(SockAddrIn value); |
diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp index 674928798..1beca417c 100644 --- a/src/core/hle/service/spl/csrng.cpp +++ b/src/core/hle/service/spl/csrng.cpp | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::SPL { | 7 | namespace Service::SPL { |
| 8 | 8 | ||
| 9 | CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "csrng") { | 9 | CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_) |
| 10 | : Interface(system_, std::move(module_), "csrng") { | ||
| 10 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 11 | {0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, | 12 | {0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, |
| 12 | }; | 13 | }; |
diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h index 764d5ceb0..5c0bd2199 100644 --- a/src/core/hle/service/spl/csrng.h +++ b/src/core/hle/service/spl/csrng.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/spl/module.h" | 7 | #include "core/hle/service/spl/module.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::SPL { | 13 | namespace Service::SPL { |
| 10 | 14 | ||
| 11 | class CSRNG final : public Module::Interface { | 15 | class CSRNG final : public Module::Interface { |
| 12 | public: | 16 | public: |
| 13 | explicit CSRNG(std::shared_ptr<Module> module); | 17 | explicit CSRNG(Core::System& system_, std::shared_ptr<Module> module_); |
| 14 | ~CSRNG() override; | 18 | ~CSRNG() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 865ed3b91..dea6b0fe0 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp | |||
| @@ -17,8 +17,9 @@ | |||
| 17 | 17 | ||
| 18 | namespace Service::SPL { | 18 | namespace Service::SPL { |
| 19 | 19 | ||
| 20 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 20 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 21 | : ServiceFramework(name), module(std::move(module)), | 21 | const char* name) |
| 22 | : ServiceFramework{system_, name}, module{std::move(module_)}, | ||
| 22 | rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {} | 23 | rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {} |
| 23 | 24 | ||
| 24 | Module::Interface::~Interface() = default; | 25 | Module::Interface::~Interface() = default; |
| @@ -38,10 +39,10 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { | |||
| 38 | rb.Push(RESULT_SUCCESS); | 39 | rb.Push(RESULT_SUCCESS); |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 42 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 42 | auto module = std::make_shared<Module>(); | 43 | auto module = std::make_shared<Module>(); |
| 43 | std::make_shared<CSRNG>(module)->InstallAsService(service_manager); | 44 | std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager); |
| 44 | std::make_shared<SPL>(module)->InstallAsService(service_manager); | 45 | std::make_shared<SPL>(system, module)->InstallAsService(service_manager); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | } // namespace Service::SPL | 48 | } // namespace Service::SPL |
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index afa1f0295..71855c1bf 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h | |||
| @@ -7,13 +7,18 @@ | |||
| 7 | #include <random> | 7 | #include <random> |
| 8 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 9 | 9 | ||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Service::SPL { | 14 | namespace Service::SPL { |
| 11 | 15 | ||
| 12 | class Module final { | 16 | class Module final { |
| 13 | public: | 17 | public: |
| 14 | class Interface : public ServiceFramework<Interface> { | 18 | class Interface : public ServiceFramework<Interface> { |
| 15 | public: | 19 | public: |
| 16 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 20 | explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 21 | const char* name); | ||
| 17 | ~Interface() override; | 22 | ~Interface() override; |
| 18 | 23 | ||
| 19 | void GetRandomBytes(Kernel::HLERequestContext& ctx); | 24 | void GetRandomBytes(Kernel::HLERequestContext& ctx); |
| @@ -27,6 +32,6 @@ public: | |||
| 27 | }; | 32 | }; |
| 28 | 33 | ||
| 29 | /// Registers all SPL services with the specified service manager. | 34 | /// Registers all SPL services with the specified service manager. |
| 30 | void InstallInterfaces(SM::ServiceManager& service_manager); | 35 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 31 | 36 | ||
| 32 | } // namespace Service::SPL | 37 | } // namespace Service::SPL |
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index 773551464..3fabc2c79 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::SPL { | 7 | namespace Service::SPL { |
| 8 | 8 | ||
| 9 | SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { | 9 | SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_) |
| 10 | : Interface(system_, std::move(module_), "spl:") { | ||
| 10 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 11 | {0, nullptr, "GetConfig"}, | 12 | {0, nullptr, "GetConfig"}, |
| 12 | {1, nullptr, "ModularExponentiate"}, | 13 | {1, nullptr, "ModularExponentiate"}, |
diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h index 3637d1623..d27d16b86 100644 --- a/src/core/hle/service/spl/spl.h +++ b/src/core/hle/service/spl/spl.h | |||
| @@ -6,11 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/spl/module.h" | 7 | #include "core/hle/service/spl/module.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::SPL { | 13 | namespace Service::SPL { |
| 10 | 14 | ||
| 11 | class SPL final : public Module::Interface { | 15 | class SPL final : public Module::Interface { |
| 12 | public: | 16 | public: |
| 13 | explicit SPL(std::shared_ptr<Module> module); | 17 | explicit SPL(Core::System& system_, std::shared_ptr<Module> module_); |
| 14 | ~SPL() override; | 18 | ~SPL() override; |
| 15 | }; | 19 | }; |
| 16 | 20 | ||
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 1ba8c19a0..dc2baca4a 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::SSL { | |||
| 12 | 12 | ||
| 13 | class ISslConnection final : public ServiceFramework<ISslConnection> { | 13 | class ISslConnection final : public ServiceFramework<ISslConnection> { |
| 14 | public: | 14 | public: |
| 15 | ISslConnection() : ServiceFramework("ISslConnection") { | 15 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SetSocketDescriptor"}, | 18 | {0, nullptr, "SetSocketDescriptor"}, |
| @@ -52,7 +52,7 @@ public: | |||
| 52 | 52 | ||
| 53 | class ISslContext final : public ServiceFramework<ISslContext> { | 53 | class ISslContext final : public ServiceFramework<ISslContext> { |
| 54 | public: | 54 | public: |
| 55 | ISslContext() : ServiceFramework("ISslContext") { | 55 | explicit ISslContext(Core::System& system_) : ServiceFramework{system_, "ISslContext"} { |
| 56 | static const FunctionInfo functions[] = { | 56 | static const FunctionInfo functions[] = { |
| 57 | {0, &ISslContext::SetOption, "SetOption"}, | 57 | {0, &ISslContext::SetOption, "SetOption"}, |
| 58 | {1, nullptr, "GetOption"}, | 58 | {1, nullptr, "GetOption"}, |
| @@ -92,13 +92,13 @@ private: | |||
| 92 | 92 | ||
| 93 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 93 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 94 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.PushIpcInterface<ISslConnection>(); | 95 | rb.PushIpcInterface<ISslConnection>(system); |
| 96 | } | 96 | } |
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | class SSL final : public ServiceFramework<SSL> { | 99 | class SSL final : public ServiceFramework<SSL> { |
| 100 | public: | 100 | public: |
| 101 | explicit SSL() : ServiceFramework{"ssl"} { | 101 | explicit SSL(Core::System& system_) : ServiceFramework{system_, "ssl"} { |
| 102 | // clang-format off | 102 | // clang-format off |
| 103 | static const FunctionInfo functions[] = { | 103 | static const FunctionInfo functions[] = { |
| 104 | {0, &SSL::CreateContext, "CreateContext"}, | 104 | {0, &SSL::CreateContext, "CreateContext"}, |
| @@ -123,7 +123,7 @@ private: | |||
| 123 | 123 | ||
| 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 125 | rb.Push(RESULT_SUCCESS); | 125 | rb.Push(RESULT_SUCCESS); |
| 126 | rb.PushIpcInterface<ISslContext>(); | 126 | rb.PushIpcInterface<ISslContext>(system); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { | 129 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { |
| @@ -137,8 +137,8 @@ private: | |||
| 137 | } | 137 | } |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 140 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 141 | std::make_shared<SSL>()->InstallAsService(service_manager); | 141 | std::make_shared<SSL>(system)->InstallAsService(service_manager); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | } // namespace Service::SSL | 144 | } // namespace Service::SSL |
diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h index 5cb04c3b9..a3aa4b4b5 100644 --- a/src/core/hle/service/ssl/ssl.h +++ b/src/core/hle/service/ssl/ssl.h | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| @@ -11,6 +15,6 @@ class ServiceManager; | |||
| 11 | namespace Service::SSL { | 15 | namespace Service::SSL { |
| 12 | 16 | ||
| 13 | /// Registers all SSL services with the specified service manager. | 17 | /// Registers all SSL services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager); | 18 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 15 | 19 | ||
| 16 | } // namespace Service::SSL | 20 | } // namespace Service::SSL |
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index ba8fd6152..a01d9e0ff 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | namespace Service::Time { | 7 | namespace Service::Time { |
| 8 | 8 | ||
| 9 | Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name) | 9 | Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 10 | : Module::Interface(std::move(module), system, name) { | 10 | : Interface(std::move(module), system, name) { |
| 11 | // clang-format off | 11 | // clang-format off |
| 12 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 13 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | 13 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index ee4fa4b48..abc753d5d 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/kernel/client_port.h" | 11 | #include "core/hle/kernel/client_port.h" |
| 12 | #include "core/hle/kernel/client_session.h" | 12 | #include "core/hle/kernel/client_session.h" |
| 13 | #include "core/hle/kernel/scheduler.h" | 13 | #include "core/hle/kernel/k_scheduler.h" |
| 14 | #include "core/hle/kernel/kernel.h" | ||
| 14 | #include "core/hle/service/time/interface.h" | 15 | #include "core/hle/service/time/interface.h" |
| 15 | #include "core/hle/service/time/time.h" | 16 | #include "core/hle/service/time/time.h" |
| 16 | #include "core/hle/service/time/time_sharedmemory.h" | 17 | #include "core/hle/service/time/time_sharedmemory.h" |
| @@ -20,8 +21,8 @@ namespace Service::Time { | |||
| 20 | 21 | ||
| 21 | class ISystemClock final : public ServiceFramework<ISystemClock> { | 22 | class ISystemClock final : public ServiceFramework<ISystemClock> { |
| 22 | public: | 23 | public: |
| 23 | explicit ISystemClock(Clock::SystemClockCore& clock_core, Core::System& system) | 24 | explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_) |
| 24 | : ServiceFramework("ISystemClock"), clock_core{clock_core}, system{system} { | 25 | : ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} { |
| 25 | // clang-format off | 26 | // clang-format off |
| 26 | static const FunctionInfo functions[] = { | 27 | static const FunctionInfo functions[] = { |
| 27 | {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, | 28 | {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, |
| @@ -81,13 +82,12 @@ private: | |||
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | Clock::SystemClockCore& clock_core; | 84 | Clock::SystemClockCore& clock_core; |
| 84 | Core::System& system; | ||
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { | 87 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { |
| 88 | public: | 88 | public: |
| 89 | explicit ISteadyClock(Clock::SteadyClockCore& clock_core, Core::System& system) | 89 | explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_) |
| 90 | : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} { | 90 | : ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} { |
| 91 | static const FunctionInfo functions[] = { | 91 | static const FunctionInfo functions[] = { |
| 92 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, | 92 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, |
| 93 | {2, nullptr, "GetTestOffset"}, | 93 | {2, nullptr, "GetTestOffset"}, |
| @@ -118,14 +118,13 @@ private: | |||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | Clock::SteadyClockCore& clock_core; | 120 | Clock::SteadyClockCore& clock_core; |
| 121 | Core::System& system; | ||
| 122 | }; | 121 | }; |
| 123 | 122 | ||
| 124 | ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( | 123 | ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( |
| 125 | Kernel::Thread* thread, Clock::SystemClockContext user_context, | 124 | Kernel::Thread* thread, Clock::SystemClockContext user_context, |
| 126 | Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { | 125 | Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { |
| 127 | 126 | ||
| 128 | auto& time_manager{module->GetTimeManager()}; | 127 | auto& time_manager{system.GetTimeManager()}; |
| 129 | 128 | ||
| 130 | clock_snapshot.is_automatic_correction_enabled = | 129 | clock_snapshot.is_automatic_correction_enabled = |
| 131 | time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); | 130 | time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); |
| @@ -182,7 +181,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct | |||
| 182 | LOG_DEBUG(Service_Time, "called"); | 181 | LOG_DEBUG(Service_Time, "called"); |
| 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 182 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 184 | rb.Push(RESULT_SUCCESS); | 183 | rb.Push(RESULT_SUCCESS); |
| 185 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(), | 184 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(), |
| 186 | system); | 185 | system); |
| 187 | } | 186 | } |
| 188 | 187 | ||
| @@ -190,7 +189,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& | |||
| 190 | LOG_DEBUG(Service_Time, "called"); | 189 | LOG_DEBUG(Service_Time, "called"); |
| 191 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 190 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 192 | rb.Push(RESULT_SUCCESS); | 191 | rb.Push(RESULT_SUCCESS); |
| 193 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(), | 192 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(), |
| 194 | system); | 193 | system); |
| 195 | } | 194 | } |
| 196 | 195 | ||
| @@ -198,29 +197,29 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | |||
| 198 | LOG_DEBUG(Service_Time, "called"); | 197 | LOG_DEBUG(Service_Time, "called"); |
| 199 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 198 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 200 | rb.Push(RESULT_SUCCESS); | 199 | rb.Push(RESULT_SUCCESS); |
| 201 | rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(), | 200 | rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system); |
| 202 | system); | ||
| 203 | } | 201 | } |
| 204 | 202 | ||
| 205 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 203 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| 206 | LOG_DEBUG(Service_Time, "called"); | 204 | LOG_DEBUG(Service_Time, "called"); |
| 207 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 205 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 208 | rb.Push(RESULT_SUCCESS); | 206 | rb.Push(RESULT_SUCCESS); |
| 209 | rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager()); | 207 | rb.PushIpcInterface<ITimeZoneService>(system, |
| 208 | system.GetTimeManager().GetTimeZoneContentManager()); | ||
| 210 | } | 209 | } |
| 211 | 210 | ||
| 212 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | 211 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { |
| 213 | LOG_DEBUG(Service_Time, "called"); | 212 | LOG_DEBUG(Service_Time, "called"); |
| 214 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 213 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 215 | rb.Push(RESULT_SUCCESS); | 214 | rb.Push(RESULT_SUCCESS); |
| 216 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(), | 215 | rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(), |
| 217 | system); | 216 | system); |
| 218 | } | 217 | } |
| 219 | 218 | ||
| 220 | void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( | 219 | void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( |
| 221 | Kernel::HLERequestContext& ctx) { | 220 | Kernel::HLERequestContext& ctx) { |
| 222 | LOG_DEBUG(Service_Time, "called"); | 221 | LOG_DEBUG(Service_Time, "called"); |
| 223 | auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()}; | 222 | auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()}; |
| 224 | IPC::ResponseBuilder rb{ctx, 3}; | 223 | IPC::ResponseBuilder rb{ctx, 3}; |
| 225 | rb.Push(RESULT_SUCCESS); | 224 | rb.Push(RESULT_SUCCESS); |
| 226 | rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); | 225 | rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); |
| @@ -229,7 +228,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( | |||
| 229 | void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { | 228 | void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { |
| 230 | LOG_DEBUG(Service_Time, "called"); | 229 | LOG_DEBUG(Service_Time, "called"); |
| 231 | 230 | ||
| 232 | auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()}; | 231 | auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()}; |
| 233 | if (!steady_clock_core.IsInitialized()) { | 232 | if (!steady_clock_core.IsInitialized()) { |
| 234 | IPC::ResponseBuilder rb{ctx, 2}; | 233 | IPC::ResponseBuilder rb{ctx, 2}; |
| 235 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | 234 | rb.Push(ERROR_UNINITIALIZED_CLOCK); |
| @@ -262,8 +261,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 262 | 261 | ||
| 263 | Clock::SystemClockContext user_context{}; | 262 | Clock::SystemClockContext user_context{}; |
| 264 | if (const ResultCode result{ | 263 | if (const ResultCode result{ |
| 265 | module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext( | 264 | system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system, |
| 266 | system, user_context)}; | 265 | user_context)}; |
| 267 | result.IsError()) { | 266 | result.IsError()) { |
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | 267 | IPC::ResponseBuilder rb{ctx, 2}; |
| 269 | rb.Push(result); | 268 | rb.Push(result); |
| @@ -271,7 +270,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 271 | } | 270 | } |
| 272 | Clock::SystemClockContext network_context{}; | 271 | Clock::SystemClockContext network_context{}; |
| 273 | if (const ResultCode result{ | 272 | if (const ResultCode result{ |
| 274 | module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( | 273 | system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( |
| 275 | system, network_context)}; | 274 | system, network_context)}; |
| 276 | result.IsError()) { | 275 | result.IsError()) { |
| 277 | IPC::ResponseBuilder rb{ctx, 2}; | 276 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -372,16 +371,17 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c | |||
| 372 | LOG_DEBUG(Service_Time, "called"); | 371 | LOG_DEBUG(Service_Time, "called"); |
| 373 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 372 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 374 | rb.Push(RESULT_SUCCESS); | 373 | rb.Push(RESULT_SUCCESS); |
| 375 | rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder()); | 374 | rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem())); |
| 376 | } | 375 | } |
| 377 | 376 | ||
| 378 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) | 377 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 379 | : ServiceFramework(name), module{std::move(module)}, system{system} {} | 378 | const char* name) |
| 379 | : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||
| 380 | 380 | ||
| 381 | Module::Interface::~Interface() = default; | 381 | Module::Interface::~Interface() = default; |
| 382 | 382 | ||
| 383 | void InstallInterfaces(Core::System& system) { | 383 | void InstallInterfaces(Core::System& system) { |
| 384 | auto module{std::make_shared<Module>(system)}; | 384 | auto module{std::make_shared<Module>()}; |
| 385 | std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); | 385 | std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); |
| 386 | std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); | 386 | std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); |
| 387 | std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); | 387 | std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); |
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 41f3002e9..975a8ae5b 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -16,11 +16,12 @@ namespace Service::Time { | |||
| 16 | 16 | ||
| 17 | class Module final { | 17 | class Module final { |
| 18 | public: | 18 | public: |
| 19 | Module(Core::System& system) : time_manager{system} {} | 19 | Module() = default; |
| 20 | 20 | ||
| 21 | class Interface : public ServiceFramework<Interface> { | 21 | class Interface : public ServiceFramework<Interface> { |
| 22 | public: | 22 | public: |
| 23 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); | 23 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 24 | const char* name); | ||
| 24 | ~Interface() override; | 25 | ~Interface() override; |
| 25 | 26 | ||
| 26 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); | 27 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); |
| @@ -44,15 +45,7 @@ public: | |||
| 44 | 45 | ||
| 45 | protected: | 46 | protected: |
| 46 | std::shared_ptr<Module> module; | 47 | std::shared_ptr<Module> module; |
| 47 | Core::System& system; | ||
| 48 | }; | 48 | }; |
| 49 | |||
| 50 | TimeManager& GetTimeManager() { | ||
| 51 | return time_manager; | ||
| 52 | } | ||
| 53 | |||
| 54 | private: | ||
| 55 | TimeManager time_manager; | ||
| 56 | }; | 49 | }; |
| 57 | 50 | ||
| 58 | /// Registers all Time services with the specified service manager. | 51 | /// Registers all Time services with the specified service manager. |
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index b4dfe45e5..858623e2b 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp | |||
| @@ -22,125 +22,282 @@ static std::chrono::seconds GetSecondsSinceEpoch() { | |||
| 22 | Settings::values.custom_rtc_differential; | 22 | Settings::values.custom_rtc_differential; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | static s64 GetExternalTimeZoneOffset() { | ||
| 26 | // With "auto" timezone setting, we use the external system's timezone offset | ||
| 27 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 28 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 29 | } | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | |||
| 33 | static s64 GetExternalRtcValue() { | 25 | static s64 GetExternalRtcValue() { |
| 34 | return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset(); | 26 | return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset(); |
| 35 | } | ||
| 36 | |||
| 37 | TimeManager::TimeManager(Core::System& system) | ||
| 38 | : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core}, | ||
| 39 | standard_network_system_clock_core{standard_steady_clock_core}, | ||
| 40 | standard_user_system_clock_core{standard_local_system_clock_core, | ||
| 41 | standard_network_system_clock_core, system}, | ||
| 42 | ephemeral_network_system_clock_core{tick_based_steady_clock_core}, | ||
| 43 | local_system_clock_context_writer{ | ||
| 44 | std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)}, | ||
| 45 | network_system_clock_context_writer{ | ||
| 46 | std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)}, | ||
| 47 | ephemeral_network_system_clock_context_writer{ | ||
| 48 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, | ||
| 49 | time_zone_content_manager{*this, system} { | ||
| 50 | |||
| 51 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; | ||
| 52 | SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {}); | ||
| 53 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); | ||
| 54 | SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy); | ||
| 55 | SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); | ||
| 56 | SetupEphemeralNetworkSystemClock(); | ||
| 57 | } | 27 | } |
| 58 | 28 | ||
| 59 | TimeManager::~TimeManager() = default; | 29 | struct TimeManager::Impl final { |
| 30 | explicit Impl(Core::System& system) | ||
| 31 | : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core}, | ||
| 32 | standard_network_system_clock_core{standard_steady_clock_core}, | ||
| 33 | standard_user_system_clock_core{standard_local_system_clock_core, | ||
| 34 | standard_network_system_clock_core, system}, | ||
| 35 | ephemeral_network_system_clock_core{tick_based_steady_clock_core}, | ||
| 36 | local_system_clock_context_writer{ | ||
| 37 | std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)}, | ||
| 38 | network_system_clock_context_writer{ | ||
| 39 | std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)}, | ||
| 40 | ephemeral_network_system_clock_context_writer{ | ||
| 41 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, | ||
| 42 | time_zone_content_manager{system} { | ||
| 60 | 43 | ||
| 61 | void TimeManager::SetupTimeZoneManager(std::string location_name, | 44 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; |
| 62 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | 45 | SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {}); |
| 63 | std::size_t total_location_name_count, | 46 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); |
| 64 | u128 time_zone_rule_version, | 47 | SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy); |
| 65 | FileSys::VirtualFile& vfs_file) { | 48 | SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); |
| 66 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | 49 | SetupEphemeralNetworkSystemClock(); |
| 67 | location_name, vfs_file) != RESULT_SUCCESS) { | 50 | } |
| 68 | UNREACHABLE(); | 51 | |
| 69 | return; | 52 | ~Impl() = default; |
| 70 | } | 53 | |
| 71 | 54 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { | |
| 72 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); | 55 | return standard_steady_clock_core; |
| 73 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( | 56 | } |
| 74 | total_location_name_count); | 57 | |
| 75 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version); | 58 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { |
| 76 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); | 59 | return standard_steady_clock_core; |
| 77 | } | 60 | } |
| 78 | 61 | ||
| 79 | void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, | 62 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { |
| 80 | Clock::TimeSpanType setup_value, | 63 | return standard_local_system_clock_core; |
| 81 | Clock::TimeSpanType internal_offset, | 64 | } |
| 82 | bool is_rtc_reset_detected) { | 65 | |
| 83 | standard_steady_clock_core.SetClockSourceId(clock_source_id); | 66 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { |
| 84 | standard_steady_clock_core.SetSetupValue(setup_value); | 67 | return standard_local_system_clock_core; |
| 85 | standard_steady_clock_core.SetInternalOffset(internal_offset); | 68 | } |
| 86 | standard_steady_clock_core.MarkAsInitialized(); | 69 | |
| 87 | 70 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { | |
| 88 | const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; | 71 | return standard_network_system_clock_core; |
| 89 | shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); | 72 | } |
| 90 | } | 73 | |
| 91 | 74 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { | |
| 92 | void TimeManager::SetupStandardLocalSystemClock(Core::System& system, | 75 | return standard_network_system_clock_core; |
| 93 | Clock::SystemClockContext clock_context, | 76 | } |
| 94 | s64 posix_time) { | 77 | |
| 95 | standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer); | 78 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { |
| 96 | 79 | return standard_user_system_clock_core; | |
| 97 | const auto current_time_point{ | 80 | } |
| 98 | standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; | 81 | |
| 99 | if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { | 82 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { |
| 100 | standard_local_system_clock_core.SetSystemClockContext(clock_context); | 83 | return standard_user_system_clock_core; |
| 101 | } else { | 84 | } |
| 102 | if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) { | 85 | |
| 86 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { | ||
| 87 | return time_zone_content_manager; | ||
| 88 | } | ||
| 89 | |||
| 90 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { | ||
| 91 | return time_zone_content_manager; | ||
| 92 | } | ||
| 93 | |||
| 94 | SharedMemory& GetSharedMemory() { | ||
| 95 | return shared_memory; | ||
| 96 | } | ||
| 97 | |||
| 98 | const SharedMemory& GetSharedMemory() const { | ||
| 99 | return shared_memory; | ||
| 100 | } | ||
| 101 | |||
| 102 | void SetupTimeZoneManager(std::string location_name, | ||
| 103 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 104 | std::size_t total_location_name_count, u128 time_zone_rule_version, | ||
| 105 | FileSys::VirtualFile& vfs_file) { | ||
| 106 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | ||
| 107 | location_name, vfs_file) != RESULT_SUCCESS) { | ||
| 103 | UNREACHABLE(); | 108 | UNREACHABLE(); |
| 104 | return; | 109 | return; |
| 105 | } | 110 | } |
| 111 | |||
| 112 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); | ||
| 113 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( | ||
| 114 | total_location_name_count); | ||
| 115 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( | ||
| 116 | time_zone_rule_version); | ||
| 117 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); | ||
| 106 | } | 118 | } |
| 107 | 119 | ||
| 108 | standard_local_system_clock_core.MarkAsInitialized(); | 120 | static s64 GetExternalTimeZoneOffset() { |
| 109 | } | 121 | // With "auto" timezone setting, we use the external system's timezone offset |
| 122 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 123 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 124 | } | ||
| 125 | return 0; | ||
| 126 | } | ||
| 110 | 127 | ||
| 111 | void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | 128 | void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, |
| 112 | Clock::TimeSpanType sufficient_accuracy) { | 129 | Clock::TimeSpanType setup_value, |
| 113 | standard_network_system_clock_core.SetUpdateCallbackInstance( | 130 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { |
| 114 | network_system_clock_context_writer); | 131 | standard_steady_clock_core.SetClockSourceId(clock_source_id); |
| 132 | standard_steady_clock_core.SetSetupValue(setup_value); | ||
| 133 | standard_steady_clock_core.SetInternalOffset(internal_offset); | ||
| 134 | standard_steady_clock_core.MarkAsInitialized(); | ||
| 115 | 135 | ||
| 116 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) { | 136 | const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; |
| 117 | UNREACHABLE(); | 137 | shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); |
| 118 | return; | ||
| 119 | } | 138 | } |
| 120 | 139 | ||
| 121 | standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( | 140 | void SetupStandardLocalSystemClock(Core::System& system, |
| 122 | sufficient_accuracy); | 141 | Clock::SystemClockContext clock_context, s64 posix_time) { |
| 123 | standard_network_system_clock_core.MarkAsInitialized(); | 142 | standard_local_system_clock_core.SetUpdateCallbackInstance( |
| 124 | } | 143 | local_system_clock_context_writer); |
| 144 | |||
| 145 | const auto current_time_point{ | ||
| 146 | standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; | ||
| 147 | if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { | ||
| 148 | standard_local_system_clock_core.SetSystemClockContext(clock_context); | ||
| 149 | } else { | ||
| 150 | if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != | ||
| 151 | RESULT_SUCCESS) { | ||
| 152 | UNREACHABLE(); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | standard_local_system_clock_core.MarkAsInitialized(); | ||
| 158 | } | ||
| 159 | |||
| 160 | void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | ||
| 161 | Clock::TimeSpanType sufficient_accuracy) { | ||
| 162 | standard_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 163 | network_system_clock_context_writer); | ||
| 125 | 164 | ||
| 126 | void TimeManager::SetupStandardUserSystemClock( | 165 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != |
| 127 | Core::System& system, bool is_automatic_correction_enabled, | 166 | RESULT_SUCCESS) { |
| 128 | Clock::SteadyClockTimePoint steady_clock_time_point) { | 167 | UNREACHABLE(); |
| 129 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( | 168 | return; |
| 130 | system, is_automatic_correction_enabled) != RESULT_SUCCESS) { | 169 | } |
| 131 | UNREACHABLE(); | 170 | |
| 132 | return; | 171 | standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( |
| 172 | sufficient_accuracy); | ||
| 173 | standard_network_system_clock_core.MarkAsInitialized(); | ||
| 133 | } | 174 | } |
| 134 | 175 | ||
| 135 | standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); | 176 | void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled, |
| 136 | standard_user_system_clock_core.MarkAsInitialized(); | 177 | Clock::SteadyClockTimePoint steady_clock_time_point) { |
| 137 | shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); | 178 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( |
| 179 | system, is_automatic_correction_enabled) != RESULT_SUCCESS) { | ||
| 180 | UNREACHABLE(); | ||
| 181 | return; | ||
| 182 | } | ||
| 183 | |||
| 184 | standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); | ||
| 185 | standard_user_system_clock_core.MarkAsInitialized(); | ||
| 186 | shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); | ||
| 187 | } | ||
| 188 | |||
| 189 | void SetupEphemeralNetworkSystemClock() { | ||
| 190 | ephemeral_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 191 | ephemeral_network_system_clock_context_writer); | ||
| 192 | ephemeral_network_system_clock_core.MarkAsInitialized(); | ||
| 193 | } | ||
| 194 | |||
| 195 | void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) { | ||
| 196 | const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)}; | ||
| 197 | if (GetStandardLocalSystemClockCore() | ||
| 198 | .SetCurrentTime(system, timespan.ToSeconds()) | ||
| 199 | .IsError()) { | ||
| 200 | UNREACHABLE(); | ||
| 201 | return; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | SharedMemory shared_memory; | ||
| 206 | |||
| 207 | Clock::StandardSteadyClockCore standard_steady_clock_core; | ||
| 208 | Clock::TickBasedSteadyClockCore tick_based_steady_clock_core; | ||
| 209 | Clock::StandardLocalSystemClockCore standard_local_system_clock_core; | ||
| 210 | Clock::StandardNetworkSystemClockCore standard_network_system_clock_core; | ||
| 211 | Clock::StandardUserSystemClockCore standard_user_system_clock_core; | ||
| 212 | Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core; | ||
| 213 | |||
| 214 | std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer; | ||
| 215 | std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer; | ||
| 216 | std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter> | ||
| 217 | ephemeral_network_system_clock_context_writer; | ||
| 218 | |||
| 219 | TimeZone::TimeZoneContentManager time_zone_content_manager; | ||
| 220 | }; | ||
| 221 | |||
| 222 | TimeManager::TimeManager(Core::System& system) : system{system} {} | ||
| 223 | |||
| 224 | TimeManager::~TimeManager() = default; | ||
| 225 | |||
| 226 | void TimeManager::Initialize() { | ||
| 227 | impl = std::make_unique<Impl>(system); | ||
| 228 | |||
| 229 | // Time zones can only be initialized after impl is valid | ||
| 230 | impl->time_zone_content_manager.Initialize(*this); | ||
| 231 | } | ||
| 232 | |||
| 233 | Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() { | ||
| 234 | return impl->standard_steady_clock_core; | ||
| 235 | } | ||
| 236 | |||
| 237 | const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const { | ||
| 238 | return impl->standard_steady_clock_core; | ||
| 239 | } | ||
| 240 | |||
| 241 | Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() { | ||
| 242 | return impl->standard_local_system_clock_core; | ||
| 243 | } | ||
| 244 | |||
| 245 | const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const { | ||
| 246 | return impl->standard_local_system_clock_core; | ||
| 247 | } | ||
| 248 | |||
| 249 | Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() { | ||
| 250 | return impl->standard_network_system_clock_core; | ||
| 138 | } | 251 | } |
| 139 | 252 | ||
| 140 | void TimeManager::SetupEphemeralNetworkSystemClock() { | 253 | const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() |
| 141 | ephemeral_network_system_clock_core.SetUpdateCallbackInstance( | 254 | const { |
| 142 | ephemeral_network_system_clock_context_writer); | 255 | return impl->standard_network_system_clock_core; |
| 143 | ephemeral_network_system_clock_core.MarkAsInitialized(); | 256 | } |
| 257 | |||
| 258 | Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() { | ||
| 259 | return impl->standard_user_system_clock_core; | ||
| 260 | } | ||
| 261 | |||
| 262 | const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const { | ||
| 263 | return impl->standard_user_system_clock_core; | ||
| 264 | } | ||
| 265 | |||
| 266 | TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() { | ||
| 267 | return impl->time_zone_content_manager; | ||
| 268 | } | ||
| 269 | |||
| 270 | const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const { | ||
| 271 | return impl->time_zone_content_manager; | ||
| 272 | } | ||
| 273 | |||
| 274 | SharedMemory& TimeManager::GetSharedMemory() { | ||
| 275 | return impl->shared_memory; | ||
| 276 | } | ||
| 277 | |||
| 278 | const SharedMemory& TimeManager::GetSharedMemory() const { | ||
| 279 | return impl->shared_memory; | ||
| 280 | } | ||
| 281 | |||
| 282 | void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) { | ||
| 283 | impl->UpdateLocalSystemClockTime(system, posix_time); | ||
| 284 | } | ||
| 285 | |||
| 286 | void TimeManager::SetupTimeZoneManager(std::string location_name, | ||
| 287 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 288 | std::size_t total_location_name_count, | ||
| 289 | u128 time_zone_rule_version, | ||
| 290 | FileSys::VirtualFile& vfs_file) { | ||
| 291 | impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, | ||
| 292 | total_location_name_count, time_zone_rule_version, vfs_file); | ||
| 293 | } | ||
| 294 | |||
| 295 | /*static*/ s64 TimeManager::GetExternalTimeZoneOffset() { | ||
| 296 | // With "auto" timezone setting, we use the external system's timezone offset | ||
| 297 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 298 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 299 | } | ||
| 300 | return 0; | ||
| 144 | } | 301 | } |
| 145 | 302 | ||
| 146 | } // namespace Service::Time | 303 | } // namespace Service::Time |
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h index 8e65f0d22..993c7c288 100644 --- a/src/core/hle/service/time/time_manager.h +++ b/src/core/hle/service/time/time_manager.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/time_zone.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | 9 | #include "core/file_sys/vfs_types.h" |
| 9 | #include "core/hle/service/time/clock_types.h" | 10 | #include "core/hle/service/time/clock_types.h" |
| 10 | #include "core/hle/service/time/ephemeral_network_system_clock_core.h" | 11 | #include "core/hle/service/time/ephemeral_network_system_clock_core.h" |
| @@ -32,86 +33,46 @@ public: | |||
| 32 | explicit TimeManager(Core::System& system); | 33 | explicit TimeManager(Core::System& system); |
| 33 | ~TimeManager(); | 34 | ~TimeManager(); |
| 34 | 35 | ||
| 35 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { | 36 | void Initialize(); |
| 36 | return standard_steady_clock_core; | ||
| 37 | } | ||
| 38 | 37 | ||
| 39 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { | 38 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore(); |
| 40 | return standard_steady_clock_core; | ||
| 41 | } | ||
| 42 | 39 | ||
| 43 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { | 40 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const; |
| 44 | return standard_local_system_clock_core; | ||
| 45 | } | ||
| 46 | 41 | ||
| 47 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { | 42 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore(); |
| 48 | return standard_local_system_clock_core; | ||
| 49 | } | ||
| 50 | 43 | ||
| 51 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { | 44 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const; |
| 52 | return standard_network_system_clock_core; | ||
| 53 | } | ||
| 54 | 45 | ||
| 55 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { | 46 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore(); |
| 56 | return standard_network_system_clock_core; | ||
| 57 | } | ||
| 58 | 47 | ||
| 59 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { | 48 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const; |
| 60 | return standard_user_system_clock_core; | ||
| 61 | } | ||
| 62 | 49 | ||
| 63 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { | 50 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore(); |
| 64 | return standard_user_system_clock_core; | ||
| 65 | } | ||
| 66 | 51 | ||
| 67 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { | 52 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const; |
| 68 | return time_zone_content_manager; | ||
| 69 | } | ||
| 70 | 53 | ||
| 71 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { | 54 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager(); |
| 72 | return time_zone_content_manager; | ||
| 73 | } | ||
| 74 | 55 | ||
| 75 | SharedMemory& GetSharedMemory() { | 56 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const; |
| 76 | return shared_memory; | ||
| 77 | } | ||
| 78 | 57 | ||
| 79 | const SharedMemory& GetSharedMemory() const { | 58 | void UpdateLocalSystemClockTime(s64 posix_time); |
| 80 | return shared_memory; | 59 | |
| 81 | } | 60 | SharedMemory& GetSharedMemory(); |
| 61 | |||
| 62 | const SharedMemory& GetSharedMemory() const; | ||
| 82 | 63 | ||
| 83 | void SetupTimeZoneManager(std::string location_name, | 64 | void SetupTimeZoneManager(std::string location_name, |
| 84 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | 65 | Clock::SteadyClockTimePoint time_zone_updated_time_point, |
| 85 | std::size_t total_location_name_count, u128 time_zone_rule_version, | 66 | std::size_t total_location_name_count, u128 time_zone_rule_version, |
| 86 | FileSys::VirtualFile& vfs_file); | 67 | FileSys::VirtualFile& vfs_file); |
| 87 | 68 | ||
| 69 | static s64 GetExternalTimeZoneOffset(); | ||
| 70 | |||
| 88 | private: | 71 | private: |
| 89 | void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, | 72 | Core::System& system; |
| 90 | Clock::TimeSpanType setup_value, | 73 | |
| 91 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected); | 74 | struct Impl; |
| 92 | void SetupStandardLocalSystemClock(Core::System& system, | 75 | std::unique_ptr<Impl> impl; |
| 93 | Clock::SystemClockContext clock_context, s64 posix_time); | ||
| 94 | void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | ||
| 95 | Clock::TimeSpanType sufficient_accuracy); | ||
| 96 | void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled, | ||
| 97 | Clock::SteadyClockTimePoint steady_clock_time_point); | ||
| 98 | void SetupEphemeralNetworkSystemClock(); | ||
| 99 | |||
| 100 | SharedMemory shared_memory; | ||
| 101 | |||
| 102 | Clock::StandardSteadyClockCore standard_steady_clock_core; | ||
| 103 | Clock::TickBasedSteadyClockCore tick_based_steady_clock_core; | ||
| 104 | Clock::StandardLocalSystemClockCore standard_local_system_clock_core; | ||
| 105 | Clock::StandardNetworkSystemClockCore standard_network_system_clock_core; | ||
| 106 | Clock::StandardUserSystemClockCore standard_user_system_clock_core; | ||
| 107 | Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core; | ||
| 108 | |||
| 109 | std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer; | ||
| 110 | std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer; | ||
| 111 | std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter> | ||
| 112 | ephemeral_network_system_clock_context_writer; | ||
| 113 | |||
| 114 | TimeZone::TimeZoneContentManager time_zone_content_manager; | ||
| 115 | }; | 76 | }; |
| 116 | 77 | ||
| 117 | } // namespace Service::Time | 78 | } // namespace Service::Time |
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index 320672add..4177d0a41 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp | |||
| @@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) { | |||
| 68 | return location_name_cache; | 68 | return location_name_cache; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) | 71 | TimeZoneContentManager::TimeZoneContentManager(Core::System& system) |
| 72 | : system{system}, location_name_cache{BuildLocationNameCache(system)} { | 72 | : system{system}, location_name_cache{BuildLocationNameCache(system)} {} |
| 73 | 73 | ||
| 74 | void TimeZoneContentManager::Initialize(TimeManager& time_manager) { | ||
| 74 | std::string location_name; | 75 | std::string location_name; |
| 75 | const auto timezone_setting = Settings::GetTimeZoneString(); | 76 | const auto timezone_setting = Settings::GetTimeZoneString(); |
| 76 | if (timezone_setting == "auto" || timezone_setting == "default") { | 77 | if (timezone_setting == "auto" || timezone_setting == "default") { |
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h index 4f302c3b9..52dd1a020 100644 --- a/src/core/hle/service/time/time_zone_content_manager.h +++ b/src/core/hle/service/time/time_zone_content_manager.h | |||
| @@ -21,7 +21,9 @@ namespace Service::Time::TimeZone { | |||
| 21 | 21 | ||
| 22 | class TimeZoneContentManager final { | 22 | class TimeZoneContentManager final { |
| 23 | public: | 23 | public: |
| 24 | TimeZoneContentManager(TimeManager& time_manager, Core::System& system); | 24 | explicit TimeZoneContentManager(Core::System& system); |
| 25 | |||
| 26 | void Initialize(TimeManager& time_manager); | ||
| 25 | 27 | ||
| 26 | TimeZoneManager& GetTimeZoneManager() { | 28 | TimeZoneManager& GetTimeZoneManager() { |
| 27 | return time_zone_manager; | 29 | return time_zone_manager; |
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 69152d0ac..bdf0439f2 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp | |||
| @@ -820,7 +820,10 @@ static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, Calend | |||
| 820 | const ResultCode result{ | 820 | const ResultCode result{ |
| 821 | ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)}; | 821 | ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)}; |
| 822 | calendar.time.year = static_cast<s16>(calendar_time.year); | 822 | calendar.time.year = static_cast<s16>(calendar_time.year); |
| 823 | calendar.time.month = calendar_time.month + 1; // Internal impl. uses 0-indexed month | 823 | |
| 824 | // Internal impl. uses 0-indexed month | ||
| 825 | calendar.time.month = static_cast<s8>(calendar_time.month + 1); | ||
| 826 | |||
| 824 | calendar.time.day = calendar_time.day; | 827 | calendar.time.day = calendar_time.day; |
| 825 | calendar.time.hour = calendar_time.hour; | 828 | calendar.time.hour = calendar_time.hour; |
| 826 | calendar.time.minute = calendar_time.minute; | 829 | calendar.time.minute = calendar_time.minute; |
| @@ -872,13 +875,15 @@ ResultCode TimeZoneManager::ToPosixTime(const TimeZoneRule& rules, | |||
| 872 | const CalendarTime& calendar_time, s64& posix_time) const { | 875 | const CalendarTime& calendar_time, s64& posix_time) const { |
| 873 | posix_time = 0; | 876 | posix_time = 0; |
| 874 | 877 | ||
| 875 | CalendarTimeInternal internal_time{}; | 878 | CalendarTimeInternal internal_time{ |
| 876 | internal_time.year = calendar_time.year; | 879 | .year = calendar_time.year, |
| 877 | internal_time.month = calendar_time.month - 1; // Internal impl. uses 0-indexed month | 880 | // Internal impl. uses 0-indexed month |
| 878 | internal_time.day = calendar_time.day; | 881 | .month = static_cast<s8>(calendar_time.month - 1), |
| 879 | internal_time.hour = calendar_time.hour; | 882 | .day = calendar_time.day, |
| 880 | internal_time.minute = calendar_time.minute; | 883 | .hour = calendar_time.hour, |
| 881 | internal_time.second = calendar_time.second; | 884 | .minute = calendar_time.minute, |
| 885 | .second = calendar_time.second, | ||
| 886 | }; | ||
| 882 | 887 | ||
| 883 | s32 hour{internal_time.hour}; | 888 | s32 hour{internal_time.hour}; |
| 884 | s32 minute{internal_time.minute}; | 889 | s32 minute{internal_time.minute}; |
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp index ff3a10b3e..25cecbc83 100644 --- a/src/core/hle/service/time/time_zone_service.cpp +++ b/src/core/hle/service/time/time_zone_service.cpp | |||
| @@ -10,8 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Time { | 11 | namespace Service::Time { |
| 12 | 12 | ||
| 13 | ITimeZoneService ::ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_content_manager) | 13 | ITimeZoneService ::ITimeZoneService(Core::System& system_, |
| 14 | : ServiceFramework("ITimeZoneService"), time_zone_content_manager{time_zone_content_manager} { | 14 | TimeZone::TimeZoneContentManager& time_zone_manager_) |
| 15 | : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} { | ||
| 15 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 16 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, | 17 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, |
| 17 | {1, nullptr, "SetDeviceLocationName"}, | 18 | {1, nullptr, "SetDeviceLocationName"}, |
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h index cb495748b..2c9b97603 100644 --- a/src/core/hle/service/time/time_zone_service.h +++ b/src/core/hle/service/time/time_zone_service.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::Time { | 13 | namespace Service::Time { |
| 10 | 14 | ||
| 11 | namespace TimeZone { | 15 | namespace TimeZone { |
| @@ -14,7 +18,8 @@ class TimeZoneContentManager; | |||
| 14 | 18 | ||
| 15 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { | 19 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { |
| 16 | public: | 20 | public: |
| 17 | explicit ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_manager); | 21 | explicit ITimeZoneService(Core::System& system_, |
| 22 | TimeZone::TimeZoneContentManager& time_zone_manager_); | ||
| 18 | 23 | ||
| 19 | private: | 24 | private: |
| 20 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx); | 25 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index d033f8603..579de83e4 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp | |||
| @@ -15,7 +15,7 @@ namespace Service::USB { | |||
| 15 | 15 | ||
| 16 | class IDsInterface final : public ServiceFramework<IDsInterface> { | 16 | class IDsInterface final : public ServiceFramework<IDsInterface> { |
| 17 | public: | 17 | public: |
| 18 | explicit IDsInterface() : ServiceFramework{"IDsInterface"} { | 18 | explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { |
| 19 | // clang-format off | 19 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| 21 | {0, nullptr, "GetDsEndpoint"}, | 21 | {0, nullptr, "GetDsEndpoint"}, |
| @@ -40,7 +40,7 @@ public: | |||
| 40 | 40 | ||
| 41 | class USB_DS final : public ServiceFramework<USB_DS> { | 41 | class USB_DS final : public ServiceFramework<USB_DS> { |
| 42 | public: | 42 | public: |
| 43 | explicit USB_DS() : ServiceFramework{"usb:ds"} { | 43 | explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { |
| 44 | // clang-format off | 44 | // clang-format off |
| 45 | static const FunctionInfo functions[] = { | 45 | static const FunctionInfo functions[] = { |
| 46 | {0, nullptr, "BindDevice"}, | 46 | {0, nullptr, "BindDevice"}, |
| @@ -65,7 +65,8 @@ public: | |||
| 65 | 65 | ||
| 66 | class IClientEpSession final : public ServiceFramework<IClientEpSession> { | 66 | class IClientEpSession final : public ServiceFramework<IClientEpSession> { |
| 67 | public: | 67 | public: |
| 68 | explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} { | 68 | explicit IClientEpSession(Core::System& system_) |
| 69 | : ServiceFramework{system_, "IClientEpSession"} { | ||
| 69 | // clang-format off | 70 | // clang-format off |
| 70 | static const FunctionInfo functions[] = { | 71 | static const FunctionInfo functions[] = { |
| 71 | {0, nullptr, "Open"}, | 72 | {0, nullptr, "Open"}, |
| @@ -86,7 +87,8 @@ public: | |||
| 86 | 87 | ||
| 87 | class IClientIfSession final : public ServiceFramework<IClientIfSession> { | 88 | class IClientIfSession final : public ServiceFramework<IClientIfSession> { |
| 88 | public: | 89 | public: |
| 89 | explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { | 90 | explicit IClientIfSession(Core::System& system_) |
| 91 | : ServiceFramework{system_, "IClientIfSession"} { | ||
| 90 | // clang-format off | 92 | // clang-format off |
| 91 | static const FunctionInfo functions[] = { | 93 | static const FunctionInfo functions[] = { |
| 92 | {0, nullptr, "Unknown0"}, | 94 | {0, nullptr, "Unknown0"}, |
| @@ -108,7 +110,7 @@ public: | |||
| 108 | 110 | ||
| 109 | class USB_HS final : public ServiceFramework<USB_HS> { | 111 | class USB_HS final : public ServiceFramework<USB_HS> { |
| 110 | public: | 112 | public: |
| 111 | explicit USB_HS() : ServiceFramework{"usb:hs"} { | 113 | explicit USB_HS(Core::System& system_) : ServiceFramework{system_, "usb:hs"} { |
| 112 | // clang-format off | 114 | // clang-format off |
| 113 | static const FunctionInfo functions[] = { | 115 | static const FunctionInfo functions[] = { |
| 114 | {0, nullptr, "BindClientProcess"}, | 116 | {0, nullptr, "BindClientProcess"}, |
| @@ -129,7 +131,7 @@ public: | |||
| 129 | 131 | ||
| 130 | class IPdSession final : public ServiceFramework<IPdSession> { | 132 | class IPdSession final : public ServiceFramework<IPdSession> { |
| 131 | public: | 133 | public: |
| 132 | explicit IPdSession() : ServiceFramework{"IPdSession"} { | 134 | explicit IPdSession(Core::System& system_) : ServiceFramework{system_, "IPdSession"} { |
| 133 | // clang-format off | 135 | // clang-format off |
| 134 | static const FunctionInfo functions[] = { | 136 | static const FunctionInfo functions[] = { |
| 135 | {0, nullptr, "BindNoticeEvent"}, | 137 | {0, nullptr, "BindNoticeEvent"}, |
| @@ -148,7 +150,7 @@ public: | |||
| 148 | 150 | ||
| 149 | class USB_PD final : public ServiceFramework<USB_PD> { | 151 | class USB_PD final : public ServiceFramework<USB_PD> { |
| 150 | public: | 152 | public: |
| 151 | explicit USB_PD() : ServiceFramework{"usb:pd"} { | 153 | explicit USB_PD(Core::System& system_) : ServiceFramework{system_, "usb:pd"} { |
| 152 | // clang-format off | 154 | // clang-format off |
| 153 | static const FunctionInfo functions[] = { | 155 | static const FunctionInfo functions[] = { |
| 154 | {0, &USB_PD::GetPdSession, "GetPdSession"}, | 156 | {0, &USB_PD::GetPdSession, "GetPdSession"}, |
| @@ -164,13 +166,14 @@ private: | |||
| 164 | 166 | ||
| 165 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 167 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 166 | rb.Push(RESULT_SUCCESS); | 168 | rb.Push(RESULT_SUCCESS); |
| 167 | rb.PushIpcInterface<IPdSession>(); | 169 | rb.PushIpcInterface<IPdSession>(system); |
| 168 | } | 170 | } |
| 169 | }; | 171 | }; |
| 170 | 172 | ||
| 171 | class IPdCradleSession final : public ServiceFramework<IPdCradleSession> { | 173 | class IPdCradleSession final : public ServiceFramework<IPdCradleSession> { |
| 172 | public: | 174 | public: |
| 173 | explicit IPdCradleSession() : ServiceFramework{"IPdCradleSession"} { | 175 | explicit IPdCradleSession(Core::System& system_) |
| 176 | : ServiceFramework{system_, "IPdCradleSession"} { | ||
| 174 | // clang-format off | 177 | // clang-format off |
| 175 | static const FunctionInfo functions[] = { | 178 | static const FunctionInfo functions[] = { |
| 176 | {0, nullptr, "VdmUserWrite"}, | 179 | {0, nullptr, "VdmUserWrite"}, |
| @@ -191,7 +194,7 @@ public: | |||
| 191 | 194 | ||
| 192 | class USB_PD_C final : public ServiceFramework<USB_PD_C> { | 195 | class USB_PD_C final : public ServiceFramework<USB_PD_C> { |
| 193 | public: | 196 | public: |
| 194 | explicit USB_PD_C() : ServiceFramework{"usb:pd:c"} { | 197 | explicit USB_PD_C(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} { |
| 195 | // clang-format off | 198 | // clang-format off |
| 196 | static const FunctionInfo functions[] = { | 199 | static const FunctionInfo functions[] = { |
| 197 | {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"}, | 200 | {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"}, |
| @@ -205,7 +208,7 @@ private: | |||
| 205 | void GetPdCradleSession(Kernel::HLERequestContext& ctx) { | 208 | void GetPdCradleSession(Kernel::HLERequestContext& ctx) { |
| 206 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 209 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 207 | rb.Push(RESULT_SUCCESS); | 210 | rb.Push(RESULT_SUCCESS); |
| 208 | rb.PushIpcInterface<IPdCradleSession>(); | 211 | rb.PushIpcInterface<IPdCradleSession>(system); |
| 209 | 212 | ||
| 210 | LOG_DEBUG(Service_USB, "called"); | 213 | LOG_DEBUG(Service_USB, "called"); |
| 211 | } | 214 | } |
| @@ -213,7 +216,7 @@ private: | |||
| 213 | 216 | ||
| 214 | class USB_PM final : public ServiceFramework<USB_PM> { | 217 | class USB_PM final : public ServiceFramework<USB_PM> { |
| 215 | public: | 218 | public: |
| 216 | explicit USB_PM() : ServiceFramework{"usb:pm"} { | 219 | explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} { |
| 217 | // clang-format off | 220 | // clang-format off |
| 218 | static const FunctionInfo functions[] = { | 221 | static const FunctionInfo functions[] = { |
| 219 | {0, nullptr, "Unknown0"}, | 222 | {0, nullptr, "Unknown0"}, |
| @@ -229,12 +232,12 @@ public: | |||
| 229 | } | 232 | } |
| 230 | }; | 233 | }; |
| 231 | 234 | ||
| 232 | void InstallInterfaces(SM::ServiceManager& sm) { | 235 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 233 | std::make_shared<USB_DS>()->InstallAsService(sm); | 236 | std::make_shared<USB_DS>(system)->InstallAsService(sm); |
| 234 | std::make_shared<USB_HS>()->InstallAsService(sm); | 237 | std::make_shared<USB_HS>(system)->InstallAsService(sm); |
| 235 | std::make_shared<USB_PD>()->InstallAsService(sm); | 238 | std::make_shared<USB_PD>(system)->InstallAsService(sm); |
| 236 | std::make_shared<USB_PD_C>()->InstallAsService(sm); | 239 | std::make_shared<USB_PD_C>(system)->InstallAsService(sm); |
| 237 | std::make_shared<USB_PM>()->InstallAsService(sm); | 240 | std::make_shared<USB_PM>(system)->InstallAsService(sm); |
| 238 | } | 241 | } |
| 239 | 242 | ||
| 240 | } // namespace Service::USB | 243 | } // namespace Service::USB |
diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h index 970a11fe8..fc366df34 100644 --- a/src/core/hle/service/usb/usb.h +++ b/src/core/hle/service/usb/usb.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::USB { | 15 | namespace Service::USB { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::USB | 19 | } // namespace Service::USB |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 480d34725..968cd16b6 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -159,7 +159,7 @@ public: | |||
| 159 | header.data_size = static_cast<u32_le>(write_index - sizeof(Header)); | 159 | header.data_size = static_cast<u32_le>(write_index - sizeof(Header)); |
| 160 | header.data_offset = sizeof(Header); | 160 | header.data_offset = sizeof(Header); |
| 161 | header.objects_size = 4; | 161 | header.objects_size = 4; |
| 162 | header.objects_offset = sizeof(Header) + header.data_size; | 162 | header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size); |
| 163 | std::memcpy(buffer.data(), &header, sizeof(Header)); | 163 | std::memcpy(buffer.data(), &header, sizeof(Header)); |
| 164 | 164 | ||
| 165 | return buffer; | 165 | return buffer; |
| @@ -215,10 +215,9 @@ public: | |||
| 215 | explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | 215 | explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { |
| 216 | Deserialize(); | 216 | Deserialize(); |
| 217 | } | 217 | } |
| 218 | ~IGBPConnectRequestParcel() override = default; | ||
| 219 | 218 | ||
| 220 | void DeserializeData() override { | 219 | void DeserializeData() override { |
| 221 | std::u16string token = ReadInterfaceToken(); | 220 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 222 | data = Read<Data>(); | 221 | data = Read<Data>(); |
| 223 | } | 222 | } |
| 224 | 223 | ||
| @@ -279,23 +278,28 @@ public: | |||
| 279 | : Parcel(std::move(buffer)) { | 278 | : Parcel(std::move(buffer)) { |
| 280 | Deserialize(); | 279 | Deserialize(); |
| 281 | } | 280 | } |
| 282 | ~IGBPSetPreallocatedBufferRequestParcel() override = default; | ||
| 283 | 281 | ||
| 284 | void DeserializeData() override { | 282 | void DeserializeData() override { |
| 285 | std::u16string token = ReadInterfaceToken(); | 283 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 286 | data = Read<Data>(); | 284 | data = Read<Data>(); |
| 287 | buffer = Read<NVFlinger::IGBPBuffer>(); | 285 | if (data.contains_object != 0) { |
| 286 | buffer_container = Read<BufferContainer>(); | ||
| 287 | } | ||
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | struct Data { | 290 | struct Data { |
| 291 | u32_le slot; | 291 | u32_le slot; |
| 292 | INSERT_PADDING_WORDS(1); | 292 | u32_le contains_object; |
| 293 | }; | ||
| 294 | |||
| 295 | struct BufferContainer { | ||
| 293 | u32_le graphic_buffer_length; | 296 | u32_le graphic_buffer_length; |
| 294 | INSERT_PADDING_WORDS(1); | 297 | INSERT_PADDING_WORDS(1); |
| 298 | NVFlinger::IGBPBuffer buffer{}; | ||
| 295 | }; | 299 | }; |
| 296 | 300 | ||
| 297 | Data data; | 301 | Data data{}; |
| 298 | NVFlinger::IGBPBuffer buffer; | 302 | BufferContainer buffer_container{}; |
| 299 | }; | 303 | }; |
| 300 | 304 | ||
| 301 | class IGBPSetPreallocatedBufferResponseParcel : public Parcel { | 305 | class IGBPSetPreallocatedBufferResponseParcel : public Parcel { |
| @@ -306,15 +310,40 @@ protected: | |||
| 306 | } | 310 | } |
| 307 | }; | 311 | }; |
| 308 | 312 | ||
| 313 | class IGBPCancelBufferRequestParcel : public Parcel { | ||
| 314 | public: | ||
| 315 | explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | ||
| 316 | Deserialize(); | ||
| 317 | } | ||
| 318 | |||
| 319 | void DeserializeData() override { | ||
| 320 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); | ||
| 321 | data = Read<Data>(); | ||
| 322 | } | ||
| 323 | |||
| 324 | struct Data { | ||
| 325 | u32_le slot; | ||
| 326 | Service::Nvidia::MultiFence multi_fence; | ||
| 327 | }; | ||
| 328 | |||
| 329 | Data data; | ||
| 330 | }; | ||
| 331 | |||
| 332 | class IGBPCancelBufferResponseParcel : public Parcel { | ||
| 333 | protected: | ||
| 334 | void SerializeData() override { | ||
| 335 | Write<u32>(0); // Success | ||
| 336 | } | ||
| 337 | }; | ||
| 338 | |||
| 309 | class IGBPDequeueBufferRequestParcel : public Parcel { | 339 | class IGBPDequeueBufferRequestParcel : public Parcel { |
| 310 | public: | 340 | public: |
| 311 | explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | 341 | explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { |
| 312 | Deserialize(); | 342 | Deserialize(); |
| 313 | } | 343 | } |
| 314 | ~IGBPDequeueBufferRequestParcel() override = default; | ||
| 315 | 344 | ||
| 316 | void DeserializeData() override { | 345 | void DeserializeData() override { |
| 317 | std::u16string token = ReadInterfaceToken(); | 346 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 318 | data = Read<Data>(); | 347 | data = Read<Data>(); |
| 319 | } | 348 | } |
| 320 | 349 | ||
| @@ -333,7 +362,6 @@ class IGBPDequeueBufferResponseParcel : public Parcel { | |||
| 333 | public: | 362 | public: |
| 334 | explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) | 363 | explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) |
| 335 | : slot(slot), multi_fence(multi_fence) {} | 364 | : slot(slot), multi_fence(multi_fence) {} |
| 336 | ~IGBPDequeueBufferResponseParcel() override = default; | ||
| 337 | 365 | ||
| 338 | protected: | 366 | protected: |
| 339 | void SerializeData() override { | 367 | void SerializeData() override { |
| @@ -352,10 +380,9 @@ public: | |||
| 352 | explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | 380 | explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { |
| 353 | Deserialize(); | 381 | Deserialize(); |
| 354 | } | 382 | } |
| 355 | ~IGBPRequestBufferRequestParcel() override = default; | ||
| 356 | 383 | ||
| 357 | void DeserializeData() override { | 384 | void DeserializeData() override { |
| 358 | std::u16string token = ReadInterfaceToken(); | 385 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 359 | slot = Read<u32_le>(); | 386 | slot = Read<u32_le>(); |
| 360 | } | 387 | } |
| 361 | 388 | ||
| @@ -384,10 +411,9 @@ public: | |||
| 384 | explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | 411 | explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { |
| 385 | Deserialize(); | 412 | Deserialize(); |
| 386 | } | 413 | } |
| 387 | ~IGBPQueueBufferRequestParcel() override = default; | ||
| 388 | 414 | ||
| 389 | void DeserializeData() override { | 415 | void DeserializeData() override { |
| 390 | std::u16string token = ReadInterfaceToken(); | 416 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 391 | data = Read<Data>(); | 417 | data = Read<Data>(); |
| 392 | } | 418 | } |
| 393 | 419 | ||
| @@ -447,10 +473,9 @@ public: | |||
| 447 | explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { | 473 | explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { |
| 448 | Deserialize(); | 474 | Deserialize(); |
| 449 | } | 475 | } |
| 450 | ~IGBPQueryRequestParcel() override = default; | ||
| 451 | 476 | ||
| 452 | void DeserializeData() override { | 477 | void DeserializeData() override { |
| 453 | std::u16string token = ReadInterfaceToken(); | 478 | [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); |
| 454 | type = Read<u32_le>(); | 479 | type = Read<u32_le>(); |
| 455 | } | 480 | } |
| 456 | 481 | ||
| @@ -473,8 +498,8 @@ private: | |||
| 473 | 498 | ||
| 474 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | 499 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { |
| 475 | public: | 500 | public: |
| 476 | explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 501 | explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) |
| 477 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { | 502 | : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) { |
| 478 | static const FunctionInfo functions[] = { | 503 | static const FunctionInfo functions[] = { |
| 479 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | 504 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, |
| 480 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, | 505 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, |
| @@ -509,10 +534,9 @@ private: | |||
| 509 | const u32 flags = rp.Pop<u32>(); | 534 | const u32 flags = rp.Pop<u32>(); |
| 510 | 535 | ||
| 511 | LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, | 536 | LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, |
| 512 | static_cast<u32>(transaction), flags); | 537 | transaction, flags); |
| 513 | 538 | ||
| 514 | const auto guard = nv_flinger->Lock(); | 539 | auto& buffer_queue = *nv_flinger.FindBufferQueue(id); |
| 515 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); | ||
| 516 | 540 | ||
| 517 | switch (transaction) { | 541 | switch (transaction) { |
| 518 | case TransactionId::Connect: { | 542 | case TransactionId::Connect: { |
| @@ -522,13 +546,16 @@ private: | |||
| 522 | Settings::values.resolution_factor.GetValue()), | 546 | Settings::values.resolution_factor.GetValue()), |
| 523 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * | 547 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * |
| 524 | Settings::values.resolution_factor.GetValue())}; | 548 | Settings::values.resolution_factor.GetValue())}; |
| 549 | |||
| 550 | buffer_queue.Connect(); | ||
| 551 | |||
| 525 | ctx.WriteBuffer(response.Serialize()); | 552 | ctx.WriteBuffer(response.Serialize()); |
| 526 | break; | 553 | break; |
| 527 | } | 554 | } |
| 528 | case TransactionId::SetPreallocatedBuffer: { | 555 | case TransactionId::SetPreallocatedBuffer: { |
| 529 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; | 556 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; |
| 530 | 557 | ||
| 531 | buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer); | 558 | buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer); |
| 532 | 559 | ||
| 533 | IGBPSetPreallocatedBufferResponseParcel response{}; | 560 | IGBPSetPreallocatedBufferResponseParcel response{}; |
| 534 | ctx.WriteBuffer(response.Serialize()); | 561 | ctx.WriteBuffer(response.Serialize()); |
| @@ -538,40 +565,25 @@ private: | |||
| 538 | IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; | 565 | IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; |
| 539 | const u32 width{request.data.width}; | 566 | const u32 width{request.data.width}; |
| 540 | const u32 height{request.data.height}; | 567 | const u32 height{request.data.height}; |
| 541 | auto result = buffer_queue.DequeueBuffer(width, height); | 568 | |
| 542 | 569 | do { | |
| 543 | if (result) { | 570 | if (auto result = buffer_queue.DequeueBuffer(width, height); result) { |
| 544 | // Buffer is available | 571 | // Buffer is available |
| 545 | IGBPDequeueBufferResponseParcel response{result->first, *result->second}; | 572 | IGBPDequeueBufferResponseParcel response{result->first, *result->second}; |
| 546 | ctx.WriteBuffer(response.Serialize()); | 573 | ctx.WriteBuffer(response.Serialize()); |
| 547 | } else { | 574 | break; |
| 548 | // Wait the current thread until a buffer becomes available | 575 | } |
| 549 | ctx.SleepClientThread( | 576 | } while (buffer_queue.IsConnected()); |
| 550 | "IHOSBinderDriver::DequeueBuffer", UINT64_MAX, | 577 | |
| 551 | [=, this](std::shared_ptr<Kernel::Thread> thread, | ||
| 552 | Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { | ||
| 553 | // Repeat TransactParcel DequeueBuffer when a buffer is available | ||
| 554 | const auto guard = nv_flinger->Lock(); | ||
| 555 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); | ||
| 556 | auto result = buffer_queue.DequeueBuffer(width, height); | ||
| 557 | ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); | ||
| 558 | |||
| 559 | IGBPDequeueBufferResponseParcel response{result->first, *result->second}; | ||
| 560 | ctx.WriteBuffer(response.Serialize()); | ||
| 561 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 562 | rb.Push(RESULT_SUCCESS); | ||
| 563 | }, | ||
| 564 | buffer_queue.GetWritableBufferWaitEvent()); | ||
| 565 | } | ||
| 566 | break; | 578 | break; |
| 567 | } | 579 | } |
| 568 | case TransactionId::RequestBuffer: { | 580 | case TransactionId::RequestBuffer: { |
| 569 | IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; | 581 | IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; |
| 570 | 582 | ||
| 571 | auto& buffer = buffer_queue.RequestBuffer(request.slot); | 583 | auto& buffer = buffer_queue.RequestBuffer(request.slot); |
| 572 | |||
| 573 | IGBPRequestBufferResponseParcel response{buffer}; | 584 | IGBPRequestBufferResponseParcel response{buffer}; |
| 574 | ctx.WriteBuffer(response.Serialize()); | 585 | ctx.WriteBuffer(response.Serialize()); |
| 586 | |||
| 575 | break; | 587 | break; |
| 576 | } | 588 | } |
| 577 | case TransactionId::QueueBuffer: { | 589 | case TransactionId::QueueBuffer: { |
| @@ -596,7 +608,12 @@ private: | |||
| 596 | break; | 608 | break; |
| 597 | } | 609 | } |
| 598 | case TransactionId::CancelBuffer: { | 610 | case TransactionId::CancelBuffer: { |
| 599 | LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); | 611 | IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()}; |
| 612 | |||
| 613 | buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence); | ||
| 614 | |||
| 615 | IGBPCancelBufferResponseParcel response{}; | ||
| 616 | ctx.WriteBuffer(response.Serialize()); | ||
| 600 | break; | 617 | break; |
| 601 | } | 618 | } |
| 602 | case TransactionId::Disconnect: { | 619 | case TransactionId::Disconnect: { |
| @@ -652,7 +669,7 @@ private: | |||
| 652 | 669 | ||
| 653 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | 670 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); |
| 654 | 671 | ||
| 655 | const auto& buffer_queue = nv_flinger->FindBufferQueue(id); | 672 | const auto& buffer_queue = *nv_flinger.FindBufferQueue(id); |
| 656 | 673 | ||
| 657 | // TODO(Subv): Find out what this actually is. | 674 | // TODO(Subv): Find out what this actually is. |
| 658 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 675 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| @@ -660,12 +677,13 @@ private: | |||
| 660 | rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); | 677 | rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); |
| 661 | } | 678 | } |
| 662 | 679 | ||
| 663 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 680 | NVFlinger::NVFlinger& nv_flinger; |
| 664 | }; // namespace VI | 681 | }; |
| 665 | 682 | ||
| 666 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { | 683 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { |
| 667 | public: | 684 | public: |
| 668 | explicit ISystemDisplayService() : ServiceFramework("ISystemDisplayService") { | 685 | explicit ISystemDisplayService(Core::System& system_) |
| 686 | : ServiceFramework{system_, "ISystemDisplayService"} { | ||
| 669 | static const FunctionInfo functions[] = { | 687 | static const FunctionInfo functions[] = { |
| 670 | {1200, nullptr, "GetZOrderCountMin"}, | 688 | {1200, nullptr, "GetZOrderCountMin"}, |
| 671 | {1202, nullptr, "GetZOrderCountMax"}, | 689 | {1202, nullptr, "GetZOrderCountMax"}, |
| @@ -747,7 +765,7 @@ private: | |||
| 747 | IPC::ResponseBuilder rb{ctx, 6}; | 765 | IPC::ResponseBuilder rb{ctx, 6}; |
| 748 | rb.Push(RESULT_SUCCESS); | 766 | rb.Push(RESULT_SUCCESS); |
| 749 | 767 | ||
| 750 | if (Settings::values.use_docked_mode) { | 768 | if (Settings::values.use_docked_mode.GetValue()) { |
| 751 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * | 769 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 752 | static_cast<u32>(Settings::values.resolution_factor.GetValue())); | 770 | static_cast<u32>(Settings::values.resolution_factor.GetValue())); |
| 753 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | 771 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * |
| @@ -766,8 +784,8 @@ private: | |||
| 766 | 784 | ||
| 767 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 785 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 768 | public: | 786 | public: |
| 769 | explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 787 | explicit IManagerDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) |
| 770 | : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { | 788 | : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} { |
| 771 | // clang-format off | 789 | // clang-format off |
| 772 | static const FunctionInfo functions[] = { | 790 | static const FunctionInfo functions[] = { |
| 773 | {200, nullptr, "AllocateProcessHeapBlock"}, | 791 | {200, nullptr, "AllocateProcessHeapBlock"}, |
| @@ -869,7 +887,7 @@ private: | |||
| 869 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", | 887 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", |
| 870 | unknown, display, aruid); | 888 | unknown, display, aruid); |
| 871 | 889 | ||
| 872 | const auto layer_id = nv_flinger->CreateLayer(display); | 890 | const auto layer_id = nv_flinger.CreateLayer(display); |
| 873 | if (!layer_id) { | 891 | if (!layer_id) { |
| 874 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); | 892 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); |
| 875 | IPC::ResponseBuilder rb{ctx, 2}; | 893 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -906,12 +924,12 @@ private: | |||
| 906 | rb.Push(RESULT_SUCCESS); | 924 | rb.Push(RESULT_SUCCESS); |
| 907 | } | 925 | } |
| 908 | 926 | ||
| 909 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 927 | NVFlinger::NVFlinger& nv_flinger; |
| 910 | }; | 928 | }; |
| 911 | 929 | ||
| 912 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 930 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 913 | public: | 931 | public: |
| 914 | explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 932 | explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); |
| 915 | 933 | ||
| 916 | private: | 934 | private: |
| 917 | enum class ConvertedScaleMode : u64 { | 935 | enum class ConvertedScaleMode : u64 { |
| @@ -935,7 +953,7 @@ private: | |||
| 935 | 953 | ||
| 936 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 954 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 937 | rb.Push(RESULT_SUCCESS); | 955 | rb.Push(RESULT_SUCCESS); |
| 938 | rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); | 956 | rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); |
| 939 | } | 957 | } |
| 940 | 958 | ||
| 941 | void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { | 959 | void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { |
| @@ -943,7 +961,7 @@ private: | |||
| 943 | 961 | ||
| 944 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 962 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 945 | rb.Push(RESULT_SUCCESS); | 963 | rb.Push(RESULT_SUCCESS); |
| 946 | rb.PushIpcInterface<ISystemDisplayService>(); | 964 | rb.PushIpcInterface<ISystemDisplayService>(system); |
| 947 | } | 965 | } |
| 948 | 966 | ||
| 949 | void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { | 967 | void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { |
| @@ -951,7 +969,7 @@ private: | |||
| 951 | 969 | ||
| 952 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 970 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 953 | rb.Push(RESULT_SUCCESS); | 971 | rb.Push(RESULT_SUCCESS); |
| 954 | rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); | 972 | rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger); |
| 955 | } | 973 | } |
| 956 | 974 | ||
| 957 | void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { | 975 | void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { |
| @@ -959,7 +977,7 @@ private: | |||
| 959 | 977 | ||
| 960 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 978 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 961 | rb.Push(RESULT_SUCCESS); | 979 | rb.Push(RESULT_SUCCESS); |
| 962 | rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); | 980 | rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); |
| 963 | } | 981 | } |
| 964 | 982 | ||
| 965 | void OpenDisplay(Kernel::HLERequestContext& ctx) { | 983 | void OpenDisplay(Kernel::HLERequestContext& ctx) { |
| @@ -986,7 +1004,7 @@ private: | |||
| 986 | 1004 | ||
| 987 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); | 1005 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); |
| 988 | 1006 | ||
| 989 | const auto display_id = nv_flinger->OpenDisplay(name); | 1007 | const auto display_id = nv_flinger.OpenDisplay(name); |
| 990 | if (!display_id) { | 1008 | if (!display_id) { |
| 991 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); | 1009 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); |
| 992 | IPC::ResponseBuilder rb{ctx, 2}; | 1010 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1041,8 +1059,8 @@ private: | |||
| 1041 | const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); | 1059 | const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); |
| 1042 | const u64 unknown = rp.Pop<u64>(); | 1060 | const u64 unknown = rp.Pop<u64>(); |
| 1043 | 1061 | ||
| 1044 | LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", | 1062 | LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", scaling_mode, |
| 1045 | static_cast<u32>(scaling_mode), unknown); | 1063 | unknown); |
| 1046 | 1064 | ||
| 1047 | IPC::ResponseBuilder rb{ctx, 2}; | 1065 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1048 | 1066 | ||
| @@ -1086,7 +1104,7 @@ private: | |||
| 1086 | 1104 | ||
| 1087 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); | 1105 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); |
| 1088 | 1106 | ||
| 1089 | const auto display_id = nv_flinger->OpenDisplay(display_name); | 1107 | const auto display_id = nv_flinger.OpenDisplay(display_name); |
| 1090 | if (!display_id) { | 1108 | if (!display_id) { |
| 1091 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); | 1109 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); |
| 1092 | IPC::ResponseBuilder rb{ctx, 2}; | 1110 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1094,7 +1112,7 @@ private: | |||
| 1094 | return; | 1112 | return; |
| 1095 | } | 1113 | } |
| 1096 | 1114 | ||
| 1097 | const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id); | 1115 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); |
| 1098 | if (!buffer_queue_id) { | 1116 | if (!buffer_queue_id) { |
| 1099 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); | 1117 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); |
| 1100 | IPC::ResponseBuilder rb{ctx, 2}; | 1118 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1114,7 +1132,7 @@ private: | |||
| 1114 | 1132 | ||
| 1115 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); | 1133 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); |
| 1116 | 1134 | ||
| 1117 | nv_flinger->CloseLayer(layer_id); | 1135 | nv_flinger.CloseLayer(layer_id); |
| 1118 | 1136 | ||
| 1119 | IPC::ResponseBuilder rb{ctx, 2}; | 1137 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1120 | rb.Push(RESULT_SUCCESS); | 1138 | rb.Push(RESULT_SUCCESS); |
| @@ -1130,7 +1148,7 @@ private: | |||
| 1130 | 1148 | ||
| 1131 | // TODO(Subv): What's the difference between a Stray and a Managed layer? | 1149 | // TODO(Subv): What's the difference between a Stray and a Managed layer? |
| 1132 | 1150 | ||
| 1133 | const auto layer_id = nv_flinger->CreateLayer(display_id); | 1151 | const auto layer_id = nv_flinger.CreateLayer(display_id); |
| 1134 | if (!layer_id) { | 1152 | if (!layer_id) { |
| 1135 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); | 1153 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); |
| 1136 | IPC::ResponseBuilder rb{ctx, 2}; | 1154 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1138,7 +1156,7 @@ private: | |||
| 1138 | return; | 1156 | return; |
| 1139 | } | 1157 | } |
| 1140 | 1158 | ||
| 1141 | const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id); | 1159 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); |
| 1142 | if (!buffer_queue_id) { | 1160 | if (!buffer_queue_id) { |
| 1143 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | 1161 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); |
| 1144 | IPC::ResponseBuilder rb{ctx, 2}; | 1162 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1169,7 +1187,7 @@ private: | |||
| 1169 | 1187 | ||
| 1170 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); | 1188 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); |
| 1171 | 1189 | ||
| 1172 | const auto vsync_event = nv_flinger->FindVsyncEvent(display_id); | 1190 | const auto vsync_event = nv_flinger.FindVsyncEvent(display_id); |
| 1173 | if (!vsync_event) { | 1191 | if (!vsync_event) { |
| 1174 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | 1192 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); |
| 1175 | IPC::ResponseBuilder rb{ctx, 2}; | 1193 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1185,7 +1203,7 @@ private: | |||
| 1185 | void ConvertScalingMode(Kernel::HLERequestContext& ctx) { | 1203 | void ConvertScalingMode(Kernel::HLERequestContext& ctx) { |
| 1186 | IPC::RequestParser rp{ctx}; | 1204 | IPC::RequestParser rp{ctx}; |
| 1187 | const auto mode = rp.PopEnum<NintendoScaleMode>(); | 1205 | const auto mode = rp.PopEnum<NintendoScaleMode>(); |
| 1188 | LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode)); | 1206 | LOG_DEBUG(Service_VI, "called mode={}", mode); |
| 1189 | 1207 | ||
| 1190 | const auto converted_mode = ConvertScalingModeImpl(mode); | 1208 | const auto converted_mode = ConvertScalingModeImpl(mode); |
| 1191 | 1209 | ||
| @@ -1205,8 +1223,8 @@ private: | |||
| 1205 | const auto height = rp.Pop<u64>(); | 1223 | const auto height = rp.Pop<u64>(); |
| 1206 | LOG_DEBUG(Service_VI, "called width={}, height={}", width, height); | 1224 | LOG_DEBUG(Service_VI, "called width={}, height={}", width, height); |
| 1207 | 1225 | ||
| 1208 | constexpr std::size_t base_size = 0x20000; | 1226 | constexpr u64 base_size = 0x20000; |
| 1209 | constexpr std::size_t alignment = 0x1000; | 1227 | constexpr u64 alignment = 0x1000; |
| 1210 | const auto texture_size = width * height * 4; | 1228 | const auto texture_size = width * height * 4; |
| 1211 | const auto out_size = (texture_size + base_size - 1) / base_size * base_size; | 1229 | const auto out_size = (texture_size + base_size - 1) / base_size * base_size; |
| 1212 | 1230 | ||
| @@ -1234,12 +1252,12 @@ private: | |||
| 1234 | } | 1252 | } |
| 1235 | } | 1253 | } |
| 1236 | 1254 | ||
| 1237 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 1255 | NVFlinger::NVFlinger& nv_flinger; |
| 1238 | }; | 1256 | }; |
| 1239 | 1257 | ||
| 1240 | IApplicationDisplayService::IApplicationDisplayService( | 1258 | IApplicationDisplayService::IApplicationDisplayService(Core::System& system_, |
| 1241 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 1259 | NVFlinger::NVFlinger& nv_flinger_) |
| 1242 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { | 1260 | : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} { |
| 1243 | static const FunctionInfo functions[] = { | 1261 | static const FunctionInfo functions[] = { |
| 1244 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, | 1262 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, |
| 1245 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, | 1263 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, |
| @@ -1280,14 +1298,13 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { | |||
| 1280 | return false; | 1298 | return false; |
| 1281 | } | 1299 | } |
| 1282 | 1300 | ||
| 1283 | void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | 1301 | void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, |
| 1284 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, | 1302 | NVFlinger::NVFlinger& nv_flinger, Permission permission) { |
| 1285 | Permission permission) { | ||
| 1286 | IPC::RequestParser rp{ctx}; | 1303 | IPC::RequestParser rp{ctx}; |
| 1287 | const auto policy = rp.PopEnum<Policy>(); | 1304 | const auto policy = rp.PopEnum<Policy>(); |
| 1288 | 1305 | ||
| 1289 | if (!IsValidServiceAccess(permission, policy)) { | 1306 | if (!IsValidServiceAccess(permission, policy)) { |
| 1290 | LOG_ERROR(Service_VI, "Permission denied for policy {}", static_cast<u32>(policy)); | 1307 | LOG_ERROR(Service_VI, "Permission denied for policy {}", policy); |
| 1291 | IPC::ResponseBuilder rb{ctx, 2}; | 1308 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1292 | rb.Push(ERR_PERMISSION_DENIED); | 1309 | rb.Push(ERR_PERMISSION_DENIED); |
| 1293 | return; | 1310 | return; |
| @@ -1295,14 +1312,14 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | |||
| 1295 | 1312 | ||
| 1296 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1313 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1297 | rb.Push(RESULT_SUCCESS); | 1314 | rb.Push(RESULT_SUCCESS); |
| 1298 | rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); | 1315 | rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger); |
| 1299 | } | 1316 | } |
| 1300 | 1317 | ||
| 1301 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1318 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, |
| 1302 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { | 1319 | NVFlinger::NVFlinger& nv_flinger) { |
| 1303 | std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); | 1320 | std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager); |
| 1304 | std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); | 1321 | std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager); |
| 1305 | std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); | 1322 | std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager); |
| 1306 | } | 1323 | } |
| 1307 | 1324 | ||
| 1308 | } // namespace Service::VI | 1325 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 6b66f8b81..eec531d54 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Kernel { | 14 | namespace Kernel { |
| 11 | class HLERequestContext; | 15 | class HLERequestContext; |
| 12 | } | 16 | } |
| @@ -43,12 +47,12 @@ enum class Policy { | |||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | namespace detail { | 49 | namespace detail { |
| 46 | void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | 50 | void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, |
| 47 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); | 51 | NVFlinger::NVFlinger& nv_flinger, Permission permission); |
| 48 | } // namespace detail | 52 | } // namespace detail |
| 49 | 53 | ||
| 50 | /// Registers all VI services with the specified service manager. | 54 | /// Registers all VI services with the specified service manager. |
| 51 | void InstallInterfaces(SM::ServiceManager& service_manager, | 55 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, |
| 52 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 56 | NVFlinger::NVFlinger& nv_flinger); |
| 53 | 57 | ||
| 54 | } // namespace Service::VI | 58 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 06070087f..87db1c416 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) |
| 12 | : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { | 12 | : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} { |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, | 14 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, |
| 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -22,7 +22,7 @@ VI_M::~VI_M() = default; | |||
| 22 | void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { | 22 | void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { |
| 23 | LOG_DEBUG(Service_VI, "called"); | 23 | LOG_DEBUG(Service_VI, "called"); |
| 24 | 24 | ||
| 25 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::Manager); | 25 | detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | } // namespace Service::VI | 28 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 290e06689..d79c41beb 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -18,13 +22,13 @@ namespace Service::VI { | |||
| 18 | 22 | ||
| 19 | class VI_M final : public ServiceFramework<VI_M> { | 23 | class VI_M final : public ServiceFramework<VI_M> { |
| 20 | public: | 24 | public: |
| 21 | explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 25 | explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); |
| 22 | ~VI_M() override; | 26 | ~VI_M() override; |
| 23 | 27 | ||
| 24 | private: | 28 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 29 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 30 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 31 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 32 | }; |
| 29 | 33 | ||
| 30 | } // namespace Service::VI | 34 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 57c596cc4..5cd22f7df 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) |
| 12 | : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { | 12 | : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} { |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, | 14 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, |
| 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -22,7 +22,7 @@ VI_S::~VI_S() = default; | |||
| 22 | void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { | 22 | void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { |
| 23 | LOG_DEBUG(Service_VI, "called"); | 23 | LOG_DEBUG(Service_VI, "called"); |
| 24 | 24 | ||
| 25 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::System); | 25 | detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | } // namespace Service::VI | 28 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 47804dc0b..5f1f8f290 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -18,13 +22,13 @@ namespace Service::VI { | |||
| 18 | 22 | ||
| 19 | class VI_S final : public ServiceFramework<VI_S> { | 23 | class VI_S final : public ServiceFramework<VI_S> { |
| 20 | public: | 24 | public: |
| 21 | explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 25 | explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); |
| 22 | ~VI_S() override; | 26 | ~VI_S() override; |
| 23 | 27 | ||
| 24 | private: | 28 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 29 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 30 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 31 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 32 | }; |
| 29 | 33 | ||
| 30 | } // namespace Service::VI | 34 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 6b7329345..0079d51f0 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) |
| 12 | : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { | 12 | : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} { |
| 13 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 14 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, | 14 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, |
| 15 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 15 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -22,7 +22,7 @@ VI_U::~VI_U() = default; | |||
| 22 | void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { | 22 | void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { |
| 23 | LOG_DEBUG(Service_VI, "called"); | 23 | LOG_DEBUG(Service_VI, "called"); |
| 24 | 24 | ||
| 25 | detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::User); | 25 | detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | } // namespace Service::VI | 28 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index 19bdb73b0..8e3885c73 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | class HLERequestContext; | 14 | class HLERequestContext; |
| 11 | } | 15 | } |
| @@ -18,13 +22,13 @@ namespace Service::VI { | |||
| 18 | 22 | ||
| 19 | class VI_U final : public ServiceFramework<VI_U> { | 23 | class VI_U final : public ServiceFramework<VI_U> { |
| 20 | public: | 24 | public: |
| 21 | explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 25 | explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); |
| 22 | ~VI_U() override; | 26 | ~VI_U() override; |
| 23 | 27 | ||
| 24 | private: | 28 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 29 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 30 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 31 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 32 | }; |
| 29 | 33 | ||
| 30 | } // namespace Service::VI | 34 | } // namespace Service::VI |
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp index 0260d7dcf..ddbf04069 100644 --- a/src/core/hle/service/wlan/wlan.cpp +++ b/src/core/hle/service/wlan/wlan.cpp | |||
| @@ -12,7 +12,7 @@ namespace Service::WLAN { | |||
| 12 | 12 | ||
| 13 | class WLANInfra final : public ServiceFramework<WLANInfra> { | 13 | class WLANInfra final : public ServiceFramework<WLANInfra> { |
| 14 | public: | 14 | public: |
| 15 | explicit WLANInfra() : ServiceFramework{"wlan:inf"} { | 15 | explicit WLANInfra(Core::System& system_) : ServiceFramework{system_, "wlan:inf"} { |
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "OpenMode"}, | 18 | {0, nullptr, "OpenMode"}, |
| @@ -55,7 +55,7 @@ public: | |||
| 55 | 55 | ||
| 56 | class WLANLocal final : public ServiceFramework<WLANLocal> { | 56 | class WLANLocal final : public ServiceFramework<WLANLocal> { |
| 57 | public: | 57 | public: |
| 58 | explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { | 58 | explicit WLANLocal(Core::System& system_) : ServiceFramework{system_, "wlan:lcl"} { |
| 59 | // clang-format off | 59 | // clang-format off |
| 60 | static const FunctionInfo functions[] = { | 60 | static const FunctionInfo functions[] = { |
| 61 | {0, nullptr, "Unknown0"}, | 61 | {0, nullptr, "Unknown0"}, |
| @@ -120,7 +120,7 @@ public: | |||
| 120 | 120 | ||
| 121 | class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { | 121 | class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { |
| 122 | public: | 122 | public: |
| 123 | explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} { | 123 | explicit WLANLocalGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:lg"} { |
| 124 | // clang-format off | 124 | // clang-format off |
| 125 | static const FunctionInfo functions[] = { | 125 | static const FunctionInfo functions[] = { |
| 126 | {0, nullptr, "Unknown"}, | 126 | {0, nullptr, "Unknown"}, |
| @@ -133,7 +133,7 @@ public: | |||
| 133 | 133 | ||
| 134 | class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { | 134 | class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { |
| 135 | public: | 135 | public: |
| 136 | explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} { | 136 | explicit WLANSocketGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:sg"} { |
| 137 | // clang-format off | 137 | // clang-format off |
| 138 | static const FunctionInfo functions[] = { | 138 | static const FunctionInfo functions[] = { |
| 139 | {0, nullptr, "Unknown"}, | 139 | {0, nullptr, "Unknown"}, |
| @@ -146,7 +146,7 @@ public: | |||
| 146 | 146 | ||
| 147 | class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { | 147 | class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { |
| 148 | public: | 148 | public: |
| 149 | explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { | 149 | explicit WLANSocketManager(Core::System& system_) : ServiceFramework{system_, "wlan:soc"} { |
| 150 | // clang-format off | 150 | // clang-format off |
| 151 | static const FunctionInfo functions[] = { | 151 | static const FunctionInfo functions[] = { |
| 152 | {0, nullptr, "Unknown0"}, | 152 | {0, nullptr, "Unknown0"}, |
| @@ -169,12 +169,12 @@ public: | |||
| 169 | } | 169 | } |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | void InstallInterfaces(SM::ServiceManager& sm) { | 172 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { |
| 173 | std::make_shared<WLANInfra>()->InstallAsService(sm); | 173 | std::make_shared<WLANInfra>(system)->InstallAsService(sm); |
| 174 | std::make_shared<WLANLocal>()->InstallAsService(sm); | 174 | std::make_shared<WLANLocal>(system)->InstallAsService(sm); |
| 175 | std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm); | 175 | std::make_shared<WLANLocalGetFrame>(system)->InstallAsService(sm); |
| 176 | std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm); | 176 | std::make_shared<WLANSocketGetFrame>(system)->InstallAsService(sm); |
| 177 | std::make_shared<WLANSocketManager>()->InstallAsService(sm); | 177 | std::make_shared<WLANSocketManager>(system)->InstallAsService(sm); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | } // namespace Service::WLAN | 180 | } // namespace Service::WLAN |
diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h index 054ea928a..3899eedbb 100644 --- a/src/core/hle/service/wlan/wlan.h +++ b/src/core/hle/service/wlan/wlan.h | |||
| @@ -4,12 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Core { | ||
| 8 | class System; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::SM { | 11 | namespace Service::SM { |
| 8 | class ServiceManager; | 12 | class ServiceManager; |
| 9 | } | 13 | } |
| 10 | 14 | ||
| 11 | namespace Service::WLAN { | 15 | namespace Service::WLAN { |
| 12 | 16 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& sm); | 17 | void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); |
| 14 | 18 | ||
| 15 | } // namespace Service::WLAN | 19 | } // namespace Service::WLAN |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 394a1bf26..79ebf11de 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include "core/file_sys/control_metadata.h" | 12 | #include "core/file_sys/control_metadata.h" |
| 13 | #include "core/file_sys/patch_manager.h" | 13 | #include "core/file_sys/patch_manager.h" |
| 14 | #include "core/file_sys/romfs_factory.h" | 14 | #include "core/file_sys/romfs_factory.h" |
| 15 | #include "core/gdbstub/gdbstub.h" | ||
| 16 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 17 | #include "core/hle/kernel/memory/page_table.h" | 16 | #include "core/hle/kernel/memory/page_table.h" |
| 18 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| @@ -114,7 +113,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 114 | } | 113 | } |
| 115 | 114 | ||
| 116 | if (override_update) { | 115 | if (override_update) { |
| 117 | const FileSys::PatchManager patch_manager(metadata.GetTitleID()); | 116 | const FileSys::PatchManager patch_manager( |
| 117 | metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider()); | ||
| 118 | dir = patch_manager.PatchExeFS(dir); | 118 | dir = patch_manager.PatchExeFS(dir); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| @@ -160,7 +160,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 160 | modules.clear(); | 160 | modules.clear(); |
| 161 | const VAddr base_address{process.PageTable().GetCodeRegionStart()}; | 161 | const VAddr base_address{process.PageTable().GetCodeRegionStart()}; |
| 162 | VAddr next_load_addr{base_address}; | 162 | VAddr next_load_addr{base_address}; |
| 163 | const FileSys::PatchManager pm{metadata.GetTitleID()}; | 163 | const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), |
| 164 | system.GetContentProvider()}; | ||
| 164 | for (const auto& module : static_modules) { | 165 | for (const auto& module : static_modules) { |
| 165 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; | 166 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; |
| 166 | if (!module_file) { | 167 | if (!module_file) { |
| @@ -178,8 +179,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 178 | next_load_addr = *tentative_next_load_addr; | 179 | next_load_addr = *tentative_next_load_addr; |
| 179 | modules.insert_or_assign(load_addr, module); | 180 | modules.insert_or_assign(load_addr, module); |
| 180 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | 181 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |
| 181 | // Register module with GDBStub | ||
| 182 | GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | ||
| 183 | } | 182 | } |
| 184 | 183 | ||
| 185 | // Find the RomFS by searching for a ".romfs" file in this directory | 184 | // Find the RomFS by searching for a ".romfs" file in this directory |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 35d340317..3c968580f 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| 34 | * Returns the type of the file | 34 | * Returns the type of the file |
| 35 | * @param file std::shared_ptr<VfsFile> open file | 35 | * @param file open file |
| 36 | * @return FileType found, or FileType::Error if this loader doesn't know it | 36 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 37 | */ | 37 | */ |
| 38 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 38 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index 3527933ad..2067932c7 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h | |||
| @@ -21,7 +21,7 @@ public: | |||
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | * Returns the type of the file | 23 | * Returns the type of the file |
| 24 | * @param file std::shared_ptr<VfsFile> open file | 24 | * @param file open file |
| 25 | * @return FileType found, or FileType::Error if this loader doesn't know it | 25 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 26 | */ | 26 | */ |
| 27 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 27 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 5981bcd21..e162c4ff0 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "core/file_sys/kernel_executable.h" | 6 | #include "core/file_sys/kernel_executable.h" |
| 7 | #include "core/file_sys/program_metadata.h" | 7 | #include "core/file_sys/program_metadata.h" |
| 8 | #include "core/gdbstub/gdbstub.h" | ||
| 9 | #include "core/hle/kernel/code_set.h" | 8 | #include "core/hle/kernel/code_set.h" |
| 10 | #include "core/hle/kernel/memory/page_table.h" | 9 | #include "core/hle/kernel/memory/page_table.h" |
| 11 | #include "core/hle/kernel/process.h" | 10 | #include "core/hle/kernel/process.h" |
| @@ -16,7 +15,7 @@ namespace Loader { | |||
| 16 | 15 | ||
| 17 | namespace { | 16 | namespace { |
| 18 | constexpr u32 PageAlignSize(u32 size) { | 17 | constexpr u32 PageAlignSize(u32 size) { |
| 19 | return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; | 18 | return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); |
| 20 | } | 19 | } |
| 21 | } // Anonymous namespace | 20 | } // Anonymous namespace |
| 22 | 21 | ||
| @@ -91,8 +90,6 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process, | |||
| 91 | program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); | 90 | program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); |
| 92 | codeset.DataSegment().size += kip->GetBSSSize(); | 91 | codeset.DataSegment().size += kip->GetBSSSize(); |
| 93 | 92 | ||
| 94 | GDBStub::RegisterModule(kip->GetName(), base_address, base_address + program_image.size()); | ||
| 95 | |||
| 96 | codeset.memory = std::move(program_image); | 93 | codeset.memory = std::move(program_image); |
| 97 | process.LoadModule(std::move(codeset), base_address); | 94 | process.LoadModule(std::move(codeset), base_address); |
| 98 | 95 | ||
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h index dee05a7b5..14a85e295 100644 --- a/src/core/loader/kip.h +++ b/src/core/loader/kip.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | * Returns the type of the file | 25 | * Returns the type of the file |
| 26 | * @param file std::shared_ptr<VfsFile> open file | 26 | * @param file open file |
| 27 | * @return FileType found, or FileType::Error if this loader doesn't know it | 27 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 28 | */ | 28 | */ |
| 29 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 29 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 9bc3a8840..e4f5fd40c 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 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/string_util.h" | 12 | #include "common/string_util.h" |
| 13 | #include "core/core.h" | ||
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/loader/deconstructed_rom_directory.h" | 15 | #include "core/loader/deconstructed_rom_directory.h" |
| 15 | #include "core/loader/elf.h" | 16 | #include "core/loader/elf.h" |
| @@ -184,6 +185,10 @@ constexpr std::array<const char*, 66> RESULT_MESSAGES{ | |||
| 184 | "The INI file contains more than the maximum allowable number of KIP files.", | 185 | "The INI file contains more than the maximum allowable number of KIP files.", |
| 185 | }; | 186 | }; |
| 186 | 187 | ||
| 188 | std::string GetResultStatusString(ResultStatus status) { | ||
| 189 | return RESULT_MESSAGES.at(static_cast<std::size_t>(status)); | ||
| 190 | } | ||
| 191 | |||
| 187 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { | 192 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { |
| 188 | os << RESULT_MESSAGES.at(static_cast<std::size_t>(status)); | 193 | os << RESULT_MESSAGES.at(static_cast<std::size_t>(status)); |
| 189 | return os; | 194 | return os; |
| @@ -194,15 +199,15 @@ AppLoader::~AppLoader() = default; | |||
| 194 | 199 | ||
| 195 | /** | 200 | /** |
| 196 | * Get a loader for a file with a specific type | 201 | * Get a loader for a file with a specific type |
| 197 | * @param file The file to load | 202 | * @param system The system context to use. |
| 198 | * @param type The type of the file | 203 | * @param file The file to retrieve the loader for |
| 199 | * @param file the file to retrieve the loader for | 204 | * @param type The file type |
| 200 | * @param type the file type | 205 | * @param program_index Specifies the index within the container of the program to launch. |
| 201 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 206 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 202 | */ | 207 | */ |
| 203 | static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileType type) { | 208 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 209 | FileType type, std::size_t program_index) { | ||
| 204 | switch (type) { | 210 | switch (type) { |
| 205 | |||
| 206 | // Standard ELF file format. | 211 | // Standard ELF file format. |
| 207 | case FileType::ELF: | 212 | case FileType::ELF: |
| 208 | return std::make_unique<AppLoader_ELF>(std::move(file)); | 213 | return std::make_unique<AppLoader_ELF>(std::move(file)); |
| @@ -221,7 +226,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 221 | 226 | ||
| 222 | // NX XCI (nX Card Image) file format. | 227 | // NX XCI (nX Card Image) file format. |
| 223 | case FileType::XCI: | 228 | case FileType::XCI: |
| 224 | return std::make_unique<AppLoader_XCI>(std::move(file)); | 229 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 230 | system.GetContentProvider(), program_index); | ||
| 225 | 231 | ||
| 226 | // NX NAX (NintendoAesXts) file format. | 232 | // NX NAX (NintendoAesXts) file format. |
| 227 | case FileType::NAX: | 233 | case FileType::NAX: |
| @@ -229,7 +235,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 229 | 235 | ||
| 230 | // NX NSP (Nintendo Submission Package) file format | 236 | // NX NSP (Nintendo Submission Package) file format |
| 231 | case FileType::NSP: | 237 | case FileType::NSP: |
| 232 | return std::make_unique<AppLoader_NSP>(std::move(file)); | 238 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 239 | system.GetContentProvider(), program_index); | ||
| 233 | 240 | ||
| 234 | // NX KIP (Kernel Internal Process) file format | 241 | // NX KIP (Kernel Internal Process) file format |
| 235 | case FileType::KIP: | 242 | case FileType::KIP: |
| @@ -244,20 +251,22 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 244 | } | 251 | } |
| 245 | } | 252 | } |
| 246 | 253 | ||
| 247 | std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { | 254 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 255 | std::size_t program_index) { | ||
| 248 | FileType type = IdentifyFile(file); | 256 | FileType type = IdentifyFile(file); |
| 249 | FileType filename_type = GuessFromFilename(file->GetName()); | 257 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 250 | 258 | ||
| 251 | // Special case: 00 is either a NCA or NAX. | 259 | // Special case: 00 is either a NCA or NAX. |
| 252 | if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { | 260 | if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { |
| 253 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); | 261 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); |
| 254 | if (FileType::Unknown == type) | 262 | if (FileType::Unknown == type) { |
| 255 | type = filename_type; | 263 | type = filename_type; |
| 264 | } | ||
| 256 | } | 265 | } |
| 257 | 266 | ||
| 258 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 267 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 259 | 268 | ||
| 260 | return GetFileLoader(std::move(file), type); | 269 | return GetFileLoader(system, std::move(file), type, program_index); |
| 261 | } | 270 | } |
| 262 | 271 | ||
| 263 | } // namespace Loader | 272 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index ac60b097a..b2e5b13de 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -135,6 +135,7 @@ enum class ResultStatus : u16 { | |||
| 135 | ErrorINITooManyKIPs, | 135 | ErrorINITooManyKIPs, |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | std::string GetResultStatusString(ResultStatus status); | ||
| 138 | std::ostream& operator<<(std::ostream& os, ResultStatus status); | 139 | std::ostream& operator<<(std::ostream& os, ResultStatus status); |
| 139 | 140 | ||
| 140 | /// Interface for loading an application | 141 | /// Interface for loading an application |
| @@ -290,9 +291,14 @@ protected: | |||
| 290 | 291 | ||
| 291 | /** | 292 | /** |
| 292 | * Identifies a bootable file and return a suitable loader | 293 | * Identifies a bootable file and return a suitable loader |
| 293 | * @param file The bootable file | 294 | * |
| 294 | * @return the best loader for this file | 295 | * @param system The system context. |
| 296 | * @param file The bootable file. | ||
| 297 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 298 | * | ||
| 299 | * @return the best loader for this file. | ||
| 295 | */ | 300 | */ |
| 296 | std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file); | 301 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 302 | std::size_t program_index = 0); | ||
| 297 | 303 | ||
| 298 | } // namespace Loader | 304 | } // namespace Loader |
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index c2b7722b5..a5b5e2ae1 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h | |||
| @@ -28,7 +28,7 @@ public: | |||
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | * Returns the type of the file | 30 | * Returns the type of the file |
| 31 | * @param file std::shared_ptr<VfsFile> open file | 31 | * @param file open file |
| 32 | * @return FileType found, or FileType::Error if this loader doesn't know it | 32 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 33 | */ | 33 | */ |
| 34 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 34 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 711070294..918792800 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h | |||
| @@ -28,7 +28,7 @@ public: | |||
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| 30 | * Returns the type of the file | 30 | * Returns the type of the file |
| 31 | * @param file std::shared_ptr<VfsFile> open file | 31 | * @param file open file |
| 32 | * @return FileType found, or FileType::Error if this loader doesn't know it | 32 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 33 | */ | 33 | */ |
| 34 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 34 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 9fb5eddad..ccf8cc153 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -14,10 +14,10 @@ | |||
| 14 | #include "core/file_sys/control_metadata.h" | 14 | #include "core/file_sys/control_metadata.h" |
| 15 | #include "core/file_sys/romfs_factory.h" | 15 | #include "core/file_sys/romfs_factory.h" |
| 16 | #include "core/file_sys/vfs_offset.h" | 16 | #include "core/file_sys/vfs_offset.h" |
| 17 | #include "core/gdbstub/gdbstub.h" | ||
| 18 | #include "core/hle/kernel/code_set.h" | 17 | #include "core/hle/kernel/code_set.h" |
| 19 | #include "core/hle/kernel/memory/page_table.h" | 18 | #include "core/hle/kernel/memory/page_table.h" |
| 20 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/thread.h" | ||
| 21 | #include "core/hle/service/filesystem/filesystem.h" | 21 | #include "core/hle/service/filesystem/filesystem.h" |
| 22 | #include "core/loader/nro.h" | 22 | #include "core/loader/nro.h" |
| 23 | #include "core/loader/nso.h" | 23 | #include "core/loader/nso.h" |
| @@ -127,7 +127,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | static constexpr u32 PageAlignSize(u32 size) { | 129 | static constexpr u32 PageAlignSize(u32 size) { |
| 130 | return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; | 130 | return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, | 133 | static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, |
| @@ -197,10 +197,6 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, | |||
| 197 | codeset.memory = std::move(program_image); | 197 | codeset.memory = std::move(program_image); |
| 198 | process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); | 198 | process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); |
| 199 | 199 | ||
| 200 | // Register module with GDBStub | ||
| 201 | GDBStub::RegisterModule(name, process.PageTable().GetCodeRegionStart(), | ||
| 202 | process.PageTable().GetCodeRegionEnd()); | ||
| 203 | |||
| 204 | return true; | 200 | return true; |
| 205 | } | 201 | } |
| 206 | 202 | ||
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index a2aab2ecc..a82b66221 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| 34 | * Returns the type of the file | 34 | * Returns the type of the file |
| 35 | * @param file std::shared_ptr<VfsFile> open file | 35 | * @param file open file |
| 36 | * @return FileType found, or FileType::Error if this loader doesn't know it | 36 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 37 | */ | 37 | */ |
| 38 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 38 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 1e70f6e11..95b6f339a 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -14,10 +14,10 @@ | |||
| 14 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/file_sys/patch_manager.h" | 16 | #include "core/file_sys/patch_manager.h" |
| 17 | #include "core/gdbstub/gdbstub.h" | ||
| 18 | #include "core/hle/kernel/code_set.h" | 17 | #include "core/hle/kernel/code_set.h" |
| 19 | #include "core/hle/kernel/memory/page_table.h" | 18 | #include "core/hle/kernel/memory/page_table.h" |
| 20 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/thread.h" | ||
| 21 | #include "core/loader/nso.h" | 21 | #include "core/loader/nso.h" |
| 22 | #include "core/memory.h" | 22 | #include "core/memory.h" |
| 23 | #include "core/settings.h" | 23 | #include "core/settings.h" |
| @@ -47,7 +47,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, | |||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | constexpr u32 PageAlignSize(u32 size) { | 49 | constexpr u32 PageAlignSize(u32 size) { |
| 50 | return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; | 50 | return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); |
| 51 | } | 51 | } |
| 52 | } // Anonymous namespace | 52 | } // Anonymous namespace |
| 53 | 53 | ||
| @@ -149,7 +149,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S | |||
| 149 | // Apply cheats if they exist and the program has a valid title ID | 149 | // Apply cheats if they exist and the program has a valid title ID |
| 150 | if (pm) { | 150 | if (pm) { |
| 151 | system.SetCurrentProcessBuildID(nso_header.build_id); | 151 | system.SetCurrentProcessBuildID(nso_header.build_id); |
| 152 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); | 152 | const auto cheats = pm->CreateCheatList(nso_header.build_id); |
| 153 | if (!cheats.empty()) { | 153 | if (!cheats.empty()) { |
| 154 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); | 154 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); |
| 155 | } | 155 | } |
| @@ -159,9 +159,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S | |||
| 159 | codeset.memory = std::move(program_image); | 159 | codeset.memory = std::move(program_image); |
| 160 | process.LoadModule(std::move(codeset), load_base); | 160 | process.LoadModule(std::move(codeset), load_base); |
| 161 | 161 | ||
| 162 | // Register module with GDBStub | ||
| 163 | GDBStub::RegisterModule(file.GetName(), load_base, load_base); | ||
| 164 | |||
| 165 | return load_base + image_size; | 162 | return load_base + image_size; |
| 166 | } | 163 | } |
| 167 | 164 | ||
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 4bd47787d..3af461b5f 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -59,7 +59,7 @@ struct NSOHeader { | |||
| 59 | static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); | 59 | static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); |
| 60 | static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); | 60 | static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); |
| 61 | 61 | ||
| 62 | constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; | 62 | constexpr u32 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; |
| 63 | 63 | ||
| 64 | struct NSOArgumentHeader { | 64 | struct NSOArgumentHeader { |
| 65 | u32_le allocated_size; | 65 | u32_le allocated_size; |
| @@ -75,7 +75,7 @@ public: | |||
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * Returns the type of the file | 77 | * Returns the type of the file |
| 78 | * @param file std::shared_ptr<VfsFile> open file | 78 | * @param file open file |
| 79 | * @return FileType found, or FileType::Error if this loader doesn't know it | 79 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 80 | */ | 80 | */ |
| 81 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 81 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 15e528fa8..928f64c8c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -21,26 +21,34 @@ | |||
| 21 | 21 | ||
| 22 | namespace Loader { | 22 | namespace Loader { |
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, |
| 25 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider, | ||
| 27 | std::size_t program_index) | ||
| 28 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)), | ||
| 26 | title_id(nsp->GetProgramTitleID()) { | 29 | title_id(nsp->GetProgramTitleID()) { |
| 27 | 30 | ||
| 28 | if (nsp->GetStatus() != ResultStatus::Success) | 31 | if (nsp->GetStatus() != ResultStatus::Success) { |
| 29 | return; | 32 | return; |
| 33 | } | ||
| 30 | 34 | ||
| 31 | if (nsp->IsExtractedType()) { | 35 | if (nsp->IsExtractedType()) { |
| 32 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); | 36 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); |
| 33 | } else { | 37 | } else { |
| 34 | const auto control_nca = | 38 | const auto control_nca = |
| 35 | nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); | 39 | nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); |
| 36 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | 40 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) { |
| 37 | return; | 41 | return; |
| 42 | } | ||
| 38 | 43 | ||
| 39 | std::tie(nacp_file, icon_file) = | 44 | std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { |
| 40 | FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); | 45 | const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider}; |
| 46 | return pm.ParseControlNCA(*control_nca); | ||
| 47 | }(); | ||
| 41 | 48 | ||
| 42 | if (title_id == 0) | 49 | if (title_id == 0) { |
| 43 | return; | 50 | return; |
| 51 | } | ||
| 44 | 52 | ||
| 45 | secondary_loader = std::make_unique<AppLoader_NCA>( | 53 | secondary_loader = std::make_unique<AppLoader_NCA>( |
| 46 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | 54 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index b27deb686..d48d87f2c 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -9,15 +9,16 @@ | |||
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace FileSys { | 12 | namespace FileSys { |
| 13 | class ContentProvider; | ||
| 17 | class NACP; | 14 | class NACP; |
| 18 | class NSP; | 15 | class NSP; |
| 19 | } // namespace FileSys | 16 | } // namespace FileSys |
| 20 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 21 | namespace Loader { | 22 | namespace Loader { |
| 22 | 23 | ||
| 23 | class AppLoader_NCA; | 24 | class AppLoader_NCA; |
| @@ -25,12 +26,15 @@ class AppLoader_NCA; | |||
| 25 | /// Loads an XCI file | 26 | /// Loads an XCI file |
| 26 | class AppLoader_NSP final : public AppLoader { | 27 | class AppLoader_NSP final : public AppLoader { |
| 27 | public: | 28 | public: |
| 28 | explicit AppLoader_NSP(FileSys::VirtualFile file); | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | ||
| 31 | const FileSys::ContentProvider& content_provider, | ||
| 32 | std::size_t program_index); | ||
| 29 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 30 | 34 | ||
| 31 | /** | 35 | /** |
| 32 | * Returns the type of the file | 36 | * Returns the type of the file |
| 33 | * @param file std::shared_ptr<VfsFile> open file | 37 | * @param file open file |
| 34 | * @return FileType found, or FileType::Error if this loader doesn't know it | 38 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 35 | */ | 39 | */ |
| 36 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 40 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 25e83af0f..aaa250cea 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -20,18 +20,25 @@ | |||
| 20 | 20 | ||
| 21 | namespace Loader { | 21 | namespace Loader { |
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, |
| 24 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider, | ||
| 26 | std::size_t program_index) | ||
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)), | ||
| 25 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 26 | if (xci->GetStatus() != ResultStatus::Success) | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 27 | return; | 30 | return; |
| 31 | } | ||
| 28 | 32 | ||
| 29 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); | 33 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); |
| 30 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | 34 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) { |
| 31 | return; | 35 | return; |
| 36 | } | ||
| 32 | 37 | ||
| 33 | std::tie(nacp_file, icon_file) = | 38 | std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { |
| 34 | FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca); | 39 | const FileSys::PatchManager pm{xci->GetProgramTitleID(), fsc, content_provider}; |
| 40 | return pm.ParseControlNCA(*control_nca); | ||
| 41 | }(); | ||
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | AppLoader_XCI::~AppLoader_XCI() = default; | 44 | AppLoader_XCI::~AppLoader_XCI() = default; |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 04aea286f..9f0ceb5ef 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -9,15 +9,16 @@ | |||
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace FileSys { | 12 | namespace FileSys { |
| 13 | class ContentProvider; | ||
| 17 | class NACP; | 14 | class NACP; |
| 18 | class XCI; | 15 | class XCI; |
| 19 | } // namespace FileSys | 16 | } // namespace FileSys |
| 20 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 21 | namespace Loader { | 22 | namespace Loader { |
| 22 | 23 | ||
| 23 | class AppLoader_NCA; | 24 | class AppLoader_NCA; |
| @@ -25,12 +26,15 @@ class AppLoader_NCA; | |||
| 25 | /// Loads an XCI file | 26 | /// Loads an XCI file |
| 26 | class AppLoader_XCI final : public AppLoader { | 27 | class AppLoader_XCI final : public AppLoader { |
| 27 | public: | 28 | public: |
| 28 | explicit AppLoader_XCI(FileSys::VirtualFile file); | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | ||
| 31 | const FileSys::ContentProvider& content_provider, | ||
| 32 | std::size_t program_index); | ||
| 29 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 30 | 34 | ||
| 31 | /** | 35 | /** |
| 32 | * Returns the type of the file | 36 | * Returns the type of the file |
| 33 | * @param file std::shared_ptr<VfsFile> open file | 37 | * @param file open file |
| 34 | * @return FileType found, or FileType::Error if this loader doesn't know it | 38 | * @return FileType found, or FileType::Error if this loader doesn't know it |
| 35 | */ | 39 | */ |
| 36 | static FileType IdentifyType(const FileSys::VirtualFile& file); | 40 | static FileType IdentifyType(const FileSys::VirtualFile& file); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index c3f4829d7..11609682a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -44,44 +44,16 @@ struct Memory::Impl { | |||
| 44 | MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); | 44 | MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 48 | Common::MemoryHookPointer mmio_handler) { | ||
| 49 | UNIMPLEMENTED(); | ||
| 50 | } | ||
| 51 | |||
| 52 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { | 47 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { |
| 53 | ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); | 48 | ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); |
| 54 | ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); | 49 | ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); |
| 55 | MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); | 50 | MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); |
| 56 | } | 51 | } |
| 57 | 52 | ||
| 58 | void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 59 | Common::MemoryHookPointer hook) { | ||
| 60 | UNIMPLEMENTED(); | ||
| 61 | } | ||
| 62 | |||
| 63 | void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 64 | Common::MemoryHookPointer hook) { | ||
| 65 | UNIMPLEMENTED(); | ||
| 66 | } | ||
| 67 | |||
| 68 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { | 53 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { |
| 69 | const auto& page_table = process.PageTable().PageTableImpl(); | 54 | const auto& page_table = process.PageTable().PageTableImpl(); |
| 70 | 55 | const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType(); | |
| 71 | const u8* const page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; | 56 | return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; |
| 72 | if (page_pointer != nullptr) { | ||
| 73 | return true; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) { | ||
| 77 | return true; | ||
| 78 | } | ||
| 79 | |||
| 80 | if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) { | ||
| 81 | return false; | ||
| 82 | } | ||
| 83 | |||
| 84 | return false; | ||
| 85 | } | 57 | } |
| 86 | 58 | ||
| 87 | bool IsValidVirtualAddress(VAddr vaddr) const { | 59 | bool IsValidVirtualAddress(VAddr vaddr) const { |
| @@ -99,17 +71,15 @@ struct Memory::Impl { | |||
| 99 | } | 71 | } |
| 100 | 72 | ||
| 101 | u8* GetPointer(const VAddr vaddr) const { | 73 | u8* GetPointer(const VAddr vaddr) const { |
| 102 | u8* const page_pointer{current_page_table->pointers[vaddr >> PAGE_BITS]}; | 74 | const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); |
| 103 | if (page_pointer) { | 75 | if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { |
| 104 | return page_pointer + vaddr; | 76 | return pointer + vaddr; |
| 105 | } | 77 | } |
| 106 | 78 | const auto type = Common::PageTable::PageInfo::ExtractType(raw_pointer); | |
| 107 | if (current_page_table->attributes[vaddr >> PAGE_BITS] == | 79 | if (type == Common::PageType::RasterizerCachedMemory) { |
| 108 | Common::PageType::RasterizerCachedMemory) { | ||
| 109 | return GetPointerFromRasterizerCachedMemory(vaddr); | 80 | return GetPointerFromRasterizerCachedMemory(vaddr); |
| 110 | } | 81 | } |
| 111 | 82 | return nullptr; | |
| 112 | return {}; | ||
| 113 | } | 83 | } |
| 114 | 84 | ||
| 115 | u8 Read8(const VAddr addr) { | 85 | u8 Read8(const VAddr addr) { |
| @@ -120,9 +90,9 @@ struct Memory::Impl { | |||
| 120 | if ((addr & 1) == 0) { | 90 | if ((addr & 1) == 0) { |
| 121 | return Read<u16_le>(addr); | 91 | return Read<u16_le>(addr); |
| 122 | } else { | 92 | } else { |
| 123 | const u8 a{Read<u8>(addr)}; | 93 | const u32 a{Read<u8>(addr)}; |
| 124 | const u8 b{Read<u8>(addr + sizeof(u8))}; | 94 | const u32 b{Read<u8>(addr + sizeof(u8))}; |
| 125 | return (static_cast<u16>(b) << 8) | a; | 95 | return static_cast<u16>((b << 8) | a); |
| 126 | } | 96 | } |
| 127 | } | 97 | } |
| 128 | 98 | ||
| @@ -130,9 +100,9 @@ struct Memory::Impl { | |||
| 130 | if ((addr & 3) == 0) { | 100 | if ((addr & 3) == 0) { |
| 131 | return Read<u32_le>(addr); | 101 | return Read<u32_le>(addr); |
| 132 | } else { | 102 | } else { |
| 133 | const u16 a{Read16(addr)}; | 103 | const u32 a{Read16(addr)}; |
| 134 | const u16 b{Read16(addr + sizeof(u16))}; | 104 | const u32 b{Read16(addr + sizeof(u16))}; |
| 135 | return (static_cast<u32>(b) << 16) | a; | 105 | return (b << 16) | a; |
| 136 | } | 106 | } |
| 137 | } | 107 | } |
| 138 | 108 | ||
| @@ -221,7 +191,8 @@ struct Memory::Impl { | |||
| 221 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 191 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 222 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 192 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 223 | 193 | ||
| 224 | switch (page_table.attributes[page_index]) { | 194 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 195 | switch (type) { | ||
| 225 | case Common::PageType::Unmapped: { | 196 | case Common::PageType::Unmapped: { |
| 226 | LOG_ERROR(HW_Memory, | 197 | LOG_ERROR(HW_Memory, |
| 227 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 198 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -230,10 +201,8 @@ struct Memory::Impl { | |||
| 230 | break; | 201 | break; |
| 231 | } | 202 | } |
| 232 | case Common::PageType::Memory: { | 203 | case Common::PageType::Memory: { |
| 233 | DEBUG_ASSERT(page_table.pointers[page_index]); | 204 | DEBUG_ASSERT(pointer); |
| 234 | 205 | const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS); | |
| 235 | const u8* const src_ptr = | ||
| 236 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 237 | std::memcpy(dest_buffer, src_ptr, copy_amount); | 206 | std::memcpy(dest_buffer, src_ptr, copy_amount); |
| 238 | break; | 207 | break; |
| 239 | } | 208 | } |
| @@ -267,7 +236,8 @@ struct Memory::Impl { | |||
| 267 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 236 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 268 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 237 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 269 | 238 | ||
| 270 | switch (page_table.attributes[page_index]) { | 239 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 240 | switch (type) { | ||
| 271 | case Common::PageType::Unmapped: { | 241 | case Common::PageType::Unmapped: { |
| 272 | LOG_ERROR(HW_Memory, | 242 | LOG_ERROR(HW_Memory, |
| 273 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 243 | "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -276,10 +246,8 @@ struct Memory::Impl { | |||
| 276 | break; | 246 | break; |
| 277 | } | 247 | } |
| 278 | case Common::PageType::Memory: { | 248 | case Common::PageType::Memory: { |
| 279 | DEBUG_ASSERT(page_table.pointers[page_index]); | 249 | DEBUG_ASSERT(pointer); |
| 280 | 250 | const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS); | |
| 281 | const u8* const src_ptr = | ||
| 282 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 283 | std::memcpy(dest_buffer, src_ptr, copy_amount); | 251 | std::memcpy(dest_buffer, src_ptr, copy_amount); |
| 284 | break; | 252 | break; |
| 285 | } | 253 | } |
| @@ -319,7 +287,8 @@ struct Memory::Impl { | |||
| 319 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 287 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 320 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 288 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 321 | 289 | ||
| 322 | switch (page_table.attributes[page_index]) { | 290 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 291 | switch (type) { | ||
| 323 | case Common::PageType::Unmapped: { | 292 | case Common::PageType::Unmapped: { |
| 324 | LOG_ERROR(HW_Memory, | 293 | LOG_ERROR(HW_Memory, |
| 325 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 294 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -327,10 +296,8 @@ struct Memory::Impl { | |||
| 327 | break; | 296 | break; |
| 328 | } | 297 | } |
| 329 | case Common::PageType::Memory: { | 298 | case Common::PageType::Memory: { |
| 330 | DEBUG_ASSERT(page_table.pointers[page_index]); | 299 | DEBUG_ASSERT(pointer); |
| 331 | 300 | u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS); | |
| 332 | u8* const dest_ptr = | ||
| 333 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 334 | std::memcpy(dest_ptr, src_buffer, copy_amount); | 301 | std::memcpy(dest_ptr, src_buffer, copy_amount); |
| 335 | break; | 302 | break; |
| 336 | } | 303 | } |
| @@ -363,7 +330,8 @@ struct Memory::Impl { | |||
| 363 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 330 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 364 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 331 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 365 | 332 | ||
| 366 | switch (page_table.attributes[page_index]) { | 333 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 334 | switch (type) { | ||
| 367 | case Common::PageType::Unmapped: { | 335 | case Common::PageType::Unmapped: { |
| 368 | LOG_ERROR(HW_Memory, | 336 | LOG_ERROR(HW_Memory, |
| 369 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 337 | "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -371,10 +339,8 @@ struct Memory::Impl { | |||
| 371 | break; | 339 | break; |
| 372 | } | 340 | } |
| 373 | case Common::PageType::Memory: { | 341 | case Common::PageType::Memory: { |
| 374 | DEBUG_ASSERT(page_table.pointers[page_index]); | 342 | DEBUG_ASSERT(pointer); |
| 375 | 343 | u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS); | |
| 376 | u8* const dest_ptr = | ||
| 377 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 378 | std::memcpy(dest_ptr, src_buffer, copy_amount); | 344 | std::memcpy(dest_ptr, src_buffer, copy_amount); |
| 379 | break; | 345 | break; |
| 380 | } | 346 | } |
| @@ -413,7 +379,8 @@ struct Memory::Impl { | |||
| 413 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 379 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 414 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 380 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 415 | 381 | ||
| 416 | switch (page_table.attributes[page_index]) { | 382 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 383 | switch (type) { | ||
| 417 | case Common::PageType::Unmapped: { | 384 | case Common::PageType::Unmapped: { |
| 418 | LOG_ERROR(HW_Memory, | 385 | LOG_ERROR(HW_Memory, |
| 419 | "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 386 | "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -421,10 +388,8 @@ struct Memory::Impl { | |||
| 421 | break; | 388 | break; |
| 422 | } | 389 | } |
| 423 | case Common::PageType::Memory: { | 390 | case Common::PageType::Memory: { |
| 424 | DEBUG_ASSERT(page_table.pointers[page_index]); | 391 | DEBUG_ASSERT(pointer); |
| 425 | 392 | u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS); | |
| 426 | u8* dest_ptr = | ||
| 427 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 428 | std::memset(dest_ptr, 0, copy_amount); | 393 | std::memset(dest_ptr, 0, copy_amount); |
| 429 | break; | 394 | break; |
| 430 | } | 395 | } |
| @@ -460,7 +425,8 @@ struct Memory::Impl { | |||
| 460 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); | 425 | std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); |
| 461 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | 426 | const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |
| 462 | 427 | ||
| 463 | switch (page_table.attributes[page_index]) { | 428 | const auto [pointer, type] = page_table.pointers[page_index].PointerType(); |
| 429 | switch (type) { | ||
| 464 | case Common::PageType::Unmapped: { | 430 | case Common::PageType::Unmapped: { |
| 465 | LOG_ERROR(HW_Memory, | 431 | LOG_ERROR(HW_Memory, |
| 466 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | 432 | "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", |
| @@ -469,9 +435,8 @@ struct Memory::Impl { | |||
| 469 | break; | 435 | break; |
| 470 | } | 436 | } |
| 471 | case Common::PageType::Memory: { | 437 | case Common::PageType::Memory: { |
| 472 | DEBUG_ASSERT(page_table.pointers[page_index]); | 438 | DEBUG_ASSERT(pointer); |
| 473 | const u8* src_ptr = | 439 | const u8* src_ptr = pointer + page_offset + (page_index << PAGE_BITS); |
| 474 | page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); | ||
| 475 | WriteBlock(process, dest_addr, src_ptr, copy_amount); | 440 | WriteBlock(process, dest_addr, src_ptr, copy_amount); |
| 476 | break; | 441 | break; |
| 477 | } | 442 | } |
| @@ -501,16 +466,15 @@ struct Memory::Impl { | |||
| 501 | if (vaddr == 0) { | 466 | if (vaddr == 0) { |
| 502 | return; | 467 | return; |
| 503 | } | 468 | } |
| 504 | |||
| 505 | // Iterate over a contiguous CPU address space, which corresponds to the specified GPU | 469 | // Iterate over a contiguous CPU address space, which corresponds to the specified GPU |
| 506 | // address space, marking the region as un/cached. The region is marked un/cached at a | 470 | // address space, marking the region as un/cached. The region is marked un/cached at a |
| 507 | // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size | 471 | // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size |
| 508 | // is different). This assumes the specified GPU address region is contiguous as well. | 472 | // is different). This assumes the specified GPU address region is contiguous as well. |
| 509 | 473 | ||
| 510 | u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; | 474 | const u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; |
| 511 | for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { | 475 | for (u64 i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { |
| 512 | Common::PageType& page_type{current_page_table->attributes[vaddr >> PAGE_BITS]}; | 476 | const Common::PageType page_type{ |
| 513 | 477 | current_page_table->pointers[vaddr >> PAGE_BITS].Type()}; | |
| 514 | if (cached) { | 478 | if (cached) { |
| 515 | // Switch page type to cached if now cached | 479 | // Switch page type to cached if now cached |
| 516 | switch (page_type) { | 480 | switch (page_type) { |
| @@ -519,8 +483,8 @@ struct Memory::Impl { | |||
| 519 | // space, for example, a system module need not have a VRAM mapping. | 483 | // space, for example, a system module need not have a VRAM mapping. |
| 520 | break; | 484 | break; |
| 521 | case Common::PageType::Memory: | 485 | case Common::PageType::Memory: |
| 522 | page_type = Common::PageType::RasterizerCachedMemory; | 486 | current_page_table->pointers[vaddr >> PAGE_BITS].Store( |
| 523 | current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; | 487 | nullptr, Common::PageType::RasterizerCachedMemory); |
| 524 | break; | 488 | break; |
| 525 | case Common::PageType::RasterizerCachedMemory: | 489 | case Common::PageType::RasterizerCachedMemory: |
| 526 | // There can be more than one GPU region mapped per CPU region, so it's common | 490 | // There can be more than one GPU region mapped per CPU region, so it's common |
| @@ -541,16 +505,16 @@ struct Memory::Impl { | |||
| 541 | // that this area is already unmarked as cached. | 505 | // that this area is already unmarked as cached. |
| 542 | break; | 506 | break; |
| 543 | case Common::PageType::RasterizerCachedMemory: { | 507 | case Common::PageType::RasterizerCachedMemory: { |
| 544 | u8* pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~PAGE_MASK)}; | 508 | u8* const pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~PAGE_MASK)}; |
| 545 | if (pointer == nullptr) { | 509 | if (pointer == nullptr) { |
| 546 | // It's possible that this function has been called while updating the | 510 | // It's possible that this function has been called while updating the |
| 547 | // pagetable after unmapping a VMA. In that case the underlying VMA will no | 511 | // pagetable after unmapping a VMA. In that case the underlying VMA will no |
| 548 | // longer exist, and we should just leave the pagetable entry blank. | 512 | // longer exist, and we should just leave the pagetable entry blank. |
| 549 | page_type = Common::PageType::Unmapped; | 513 | current_page_table->pointers[vaddr >> PAGE_BITS].Store( |
| 514 | nullptr, Common::PageType::Unmapped); | ||
| 550 | } else { | 515 | } else { |
| 551 | current_page_table->pointers[vaddr >> PAGE_BITS] = | 516 | current_page_table->pointers[vaddr >> PAGE_BITS].Store( |
| 552 | pointer - (vaddr & ~PAGE_MASK); | 517 | pointer - (vaddr & ~PAGE_MASK), Common::PageType::Memory); |
| 553 | page_type = Common::PageType::Memory; | ||
| 554 | } | 518 | } |
| 555 | break; | 519 | break; |
| 556 | } | 520 | } |
| @@ -580,7 +544,7 @@ struct Memory::Impl { | |||
| 580 | auto& gpu = system.GPU(); | 544 | auto& gpu = system.GPU(); |
| 581 | for (u64 i = 0; i < size; i++) { | 545 | for (u64 i = 0; i < size; i++) { |
| 582 | const auto page = base + i; | 546 | const auto page = base + i; |
| 583 | if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) { | 547 | if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { |
| 584 | gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); | 548 | gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); |
| 585 | } | 549 | } |
| 586 | } | 550 | } |
| @@ -595,20 +559,18 @@ struct Memory::Impl { | |||
| 595 | "Mapping memory page without a pointer @ {:016x}", base * PAGE_SIZE); | 559 | "Mapping memory page without a pointer @ {:016x}", base * PAGE_SIZE); |
| 596 | 560 | ||
| 597 | while (base != end) { | 561 | while (base != end) { |
| 598 | page_table.attributes[base] = type; | 562 | page_table.pointers[base].Store(nullptr, type); |
| 599 | page_table.pointers[base] = nullptr; | ||
| 600 | page_table.backing_addr[base] = 0; | 563 | page_table.backing_addr[base] = 0; |
| 601 | 564 | ||
| 602 | base += 1; | 565 | base += 1; |
| 603 | } | 566 | } |
| 604 | } else { | 567 | } else { |
| 605 | while (base != end) { | 568 | while (base != end) { |
| 606 | page_table.pointers[base] = | 569 | page_table.pointers[base].Store( |
| 607 | system.DeviceMemory().GetPointer(target) - (base << PAGE_BITS); | 570 | system.DeviceMemory().GetPointer(target) - (base << PAGE_BITS), type); |
| 608 | page_table.attributes[base] = type; | ||
| 609 | page_table.backing_addr[base] = target - (base << PAGE_BITS); | 571 | page_table.backing_addr[base] = target - (base << PAGE_BITS); |
| 610 | 572 | ||
| 611 | ASSERT_MSG(page_table.pointers[base], | 573 | ASSERT_MSG(page_table.pointers[base].Pointer(), |
| 612 | "memory mapping base yield a nullptr within the table"); | 574 | "memory mapping base yield a nullptr within the table"); |
| 613 | 575 | ||
| 614 | base += 1; | 576 | base += 1; |
| @@ -630,16 +592,14 @@ struct Memory::Impl { | |||
| 630 | */ | 592 | */ |
| 631 | template <typename T> | 593 | template <typename T> |
| 632 | T Read(const VAddr vaddr) { | 594 | T Read(const VAddr vaddr) { |
| 633 | const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 595 | // Avoid adding any extra logic to this fast-path block |
| 634 | if (page_pointer != nullptr) { | 596 | const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); |
| 635 | // NOTE: Avoid adding any extra logic to this fast-path block | 597 | if (const u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { |
| 636 | T value; | 598 | T value; |
| 637 | std::memcpy(&value, &page_pointer[vaddr], sizeof(T)); | 599 | std::memcpy(&value, &pointer[vaddr], sizeof(T)); |
| 638 | return value; | 600 | return value; |
| 639 | } | 601 | } |
| 640 | 602 | switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { | |
| 641 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 642 | switch (type) { | ||
| 643 | case Common::PageType::Unmapped: | 603 | case Common::PageType::Unmapped: |
| 644 | LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); | 604 | LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); |
| 645 | return 0; | 605 | return 0; |
| @@ -667,20 +627,16 @@ struct Memory::Impl { | |||
| 667 | * @tparam T The data type to write to memory. This type *must* be | 627 | * @tparam T The data type to write to memory. This type *must* be |
| 668 | * trivially copyable, otherwise the behavior of this function | 628 | * trivially copyable, otherwise the behavior of this function |
| 669 | * is undefined. | 629 | * is undefined. |
| 670 | * | ||
| 671 | * @returns The instance of T write to the specified virtual address. | ||
| 672 | */ | 630 | */ |
| 673 | template <typename T> | 631 | template <typename T> |
| 674 | void Write(const VAddr vaddr, const T data) { | 632 | void Write(const VAddr vaddr, const T data) { |
| 675 | u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 633 | // Avoid adding any extra logic to this fast-path block |
| 676 | if (page_pointer != nullptr) { | 634 | const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); |
| 677 | // NOTE: Avoid adding any extra logic to this fast-path block | 635 | if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { |
| 678 | std::memcpy(&page_pointer[vaddr], &data, sizeof(T)); | 636 | std::memcpy(&pointer[vaddr], &data, sizeof(T)); |
| 679 | return; | 637 | return; |
| 680 | } | 638 | } |
| 681 | 639 | switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { | |
| 682 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 683 | switch (type) { | ||
| 684 | case Common::PageType::Unmapped: | 640 | case Common::PageType::Unmapped: |
| 685 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, | 641 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, |
| 686 | static_cast<u32>(data), vaddr); | 642 | static_cast<u32>(data), vaddr); |
| @@ -701,15 +657,13 @@ struct Memory::Impl { | |||
| 701 | 657 | ||
| 702 | template <typename T> | 658 | template <typename T> |
| 703 | bool WriteExclusive(const VAddr vaddr, const T data, const T expected) { | 659 | bool WriteExclusive(const VAddr vaddr, const T data, const T expected) { |
| 704 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 660 | const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); |
| 705 | if (page_pointer != nullptr) { | 661 | if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { |
| 706 | // NOTE: Avoid adding any extra logic to this fast-path block | 662 | // NOTE: Avoid adding any extra logic to this fast-path block |
| 707 | auto* pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr]); | 663 | const auto volatile_pointer = reinterpret_cast<volatile T*>(&pointer[vaddr]); |
| 708 | return Common::AtomicCompareAndSwap(pointer, data, expected); | 664 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |
| 709 | } | 665 | } |
| 710 | 666 | switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { | |
| 711 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 712 | switch (type) { | ||
| 713 | case Common::PageType::Unmapped: | 667 | case Common::PageType::Unmapped: |
| 714 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, | 668 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, |
| 715 | static_cast<u32>(data), vaddr); | 669 | static_cast<u32>(data), vaddr); |
| @@ -730,15 +684,13 @@ struct Memory::Impl { | |||
| 730 | } | 684 | } |
| 731 | 685 | ||
| 732 | bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) { | 686 | bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) { |
| 733 | u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | 687 | const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); |
| 734 | if (page_pointer != nullptr) { | 688 | if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { |
| 735 | // NOTE: Avoid adding any extra logic to this fast-path block | 689 | // NOTE: Avoid adding any extra logic to this fast-path block |
| 736 | auto* pointer = reinterpret_cast<volatile u64*>(&page_pointer[vaddr]); | 690 | const auto volatile_pointer = reinterpret_cast<volatile u64*>(&pointer[vaddr]); |
| 737 | return Common::AtomicCompareAndSwap(pointer, data, expected); | 691 | return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |
| 738 | } | 692 | } |
| 739 | 693 | switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { | |
| 740 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 741 | switch (type) { | ||
| 742 | case Common::PageType::Unmapped: | 694 | case Common::PageType::Unmapped: |
| 743 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8, | 695 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8, |
| 744 | static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr); | 696 | static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr); |
| @@ -773,25 +725,10 @@ void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size | |||
| 773 | impl->MapMemoryRegion(page_table, base, size, target); | 725 | impl->MapMemoryRegion(page_table, base, size, target); |
| 774 | } | 726 | } |
| 775 | 727 | ||
| 776 | void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 777 | Common::MemoryHookPointer mmio_handler) { | ||
| 778 | impl->MapIoRegion(page_table, base, size, std::move(mmio_handler)); | ||
| 779 | } | ||
| 780 | |||
| 781 | void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { | 728 | void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { |
| 782 | impl->UnmapRegion(page_table, base, size); | 729 | impl->UnmapRegion(page_table, base, size); |
| 783 | } | 730 | } |
| 784 | 731 | ||
| 785 | void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 786 | Common::MemoryHookPointer hook) { | ||
| 787 | impl->AddDebugHook(page_table, base, size, std::move(hook)); | ||
| 788 | } | ||
| 789 | |||
| 790 | void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 791 | Common::MemoryHookPointer hook) { | ||
| 792 | impl->RemoveDebugHook(page_table, base, size, std::move(hook)); | ||
| 793 | } | ||
| 794 | |||
| 795 | bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { | 732 | bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { |
| 796 | return impl->IsValidVirtualAddress(process, vaddr); | 733 | return impl->IsValidVirtualAddress(process, vaddr); |
| 797 | } | 734 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 4a1cc63f4..705ebb23d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/memory_hook.h" | ||
| 12 | 11 | ||
| 13 | namespace Common { | 12 | namespace Common { |
| 14 | struct PageTable; | 13 | struct PageTable; |
| @@ -78,17 +77,6 @@ public: | |||
| 78 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target); | 77 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target); |
| 79 | 78 | ||
| 80 | /** | 79 | /** |
| 81 | * Maps a region of the emulated process address space as a IO region. | ||
| 82 | * | ||
| 83 | * @param page_table The page table of the emulated process. | ||
| 84 | * @param base The address to start mapping at. Must be page-aligned. | ||
| 85 | * @param size The amount of bytes to map. Must be page-aligned. | ||
| 86 | * @param mmio_handler The handler that backs the mapping. | ||
| 87 | */ | ||
| 88 | void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 89 | Common::MemoryHookPointer mmio_handler); | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Unmaps a region of the emulated process address space. | 80 | * Unmaps a region of the emulated process address space. |
| 93 | * | 81 | * |
| 94 | * @param page_table The page table of the emulated process. | 82 | * @param page_table The page table of the emulated process. |
| @@ -98,28 +86,6 @@ public: | |||
| 98 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); | 86 | void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); |
| 99 | 87 | ||
| 100 | /** | 88 | /** |
| 101 | * Adds a memory hook to intercept reads and writes to given region of memory. | ||
| 102 | * | ||
| 103 | * @param page_table The page table of the emulated process | ||
| 104 | * @param base The starting address to apply the hook to. | ||
| 105 | * @param size The size of the memory region to apply the hook to, in bytes. | ||
| 106 | * @param hook The hook to apply to the region of memory. | ||
| 107 | */ | ||
| 108 | void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 109 | Common::MemoryHookPointer hook); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Removes a memory hook from a given range of memory. | ||
| 113 | * | ||
| 114 | * @param page_table The page table of the emulated process. | ||
| 115 | * @param base The starting address to remove the hook from. | ||
| 116 | * @param size The size of the memory region to remove the hook from, in bytes. | ||
| 117 | * @param hook The hook to remove from the specified region of memory. | ||
| 118 | */ | ||
| 119 | void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 120 | Common::MemoryHookPointer hook); | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Checks whether or not the supplied address is a valid virtual | 89 | * Checks whether or not the supplied address is a valid virtual |
| 124 | * address for the given process. | 90 | * address for the given process. |
| 125 | * | 91 | * |
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 29284a42d..2dd0eb0f8 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -153,8 +153,9 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const { | |||
| 153 | return {}; | 153 | return {}; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | const auto value = static_cast<u32>(std::stoul(hex, nullptr, 0x10)); | ||
| 156 | out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] = | 157 | out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] = |
| 157 | std::stoul(hex, nullptr, 0x10); | 158 | value; |
| 158 | 159 | ||
| 159 | i += 8; | 160 | i += 8; |
| 160 | } else { | 161 | } else { |
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 56d173b5e..681e93468 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #ifdef _WIN32 | 11 | #ifdef _WIN32 |
| 12 | #define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname | 12 | #define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname |
| 13 | #include <winsock2.h> | 13 | #include <winsock2.h> |
| 14 | #elif __unix__ | 14 | #elif YUZU_UNIX |
| 15 | #include <errno.h> | 15 | #include <errno.h> |
| 16 | #include <fcntl.h> | 16 | #include <fcntl.h> |
| 17 | #include <netdb.h> | 17 | #include <netdb.h> |
| @@ -54,7 +54,7 @@ constexpr IPv4Address TranslateIPv4(in_addr addr) { | |||
| 54 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | 54 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { |
| 55 | sockaddr_in result; | 55 | sockaddr_in result; |
| 56 | 56 | ||
| 57 | #ifdef __unix__ | 57 | #if YUZU_UNIX |
| 58 | result.sin_len = sizeof(result); | 58 | result.sin_len = sizeof(result); |
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| @@ -63,7 +63,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | |||
| 63 | result.sin_family = AF_INET; | 63 | result.sin_family = AF_INET; |
| 64 | break; | 64 | break; |
| 65 | default: | 65 | default: |
| 66 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); | 66 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family); |
| 67 | result.sin_family = AF_INET; | 67 | result.sin_family = AF_INET; |
| 68 | break; | 68 | break; |
| 69 | } | 69 | } |
| @@ -99,7 +99,7 @@ bool EnableNonBlock(SOCKET fd, bool enable) { | |||
| 99 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; | 99 | return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | #elif __unix__ // ^ _WIN32 v __unix__ | 102 | #elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX |
| 103 | 103 | ||
| 104 | using SOCKET = int; | 104 | using SOCKET = int; |
| 105 | using WSAPOLLFD = pollfd; | 105 | using WSAPOLLFD = pollfd; |
| @@ -133,7 +133,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | |||
| 133 | result.sin_family = AF_INET; | 133 | result.sin_family = AF_INET; |
| 134 | break; | 134 | break; |
| 135 | default: | 135 | default: |
| 136 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); | 136 | UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family); |
| 137 | result.sin_family = AF_INET; | 137 | result.sin_family = AF_INET; |
| 138 | break; | 138 | break; |
| 139 | } | 139 | } |
| @@ -148,7 +148,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | |||
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) { | 150 | int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) { |
| 151 | return poll(fds, nfds, timeout); | 151 | return poll(fds, static_cast<nfds_t>(nfds), timeout); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | int closesocket(SOCKET fd) { | 154 | int closesocket(SOCKET fd) { |
| @@ -186,7 +186,7 @@ int TranslateDomain(Domain domain) { | |||
| 186 | case Domain::INET: | 186 | case Domain::INET: |
| 187 | return AF_INET; | 187 | return AF_INET; |
| 188 | default: | 188 | default: |
| 189 | UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); | 189 | UNIMPLEMENTED_MSG("Unimplemented domain={}", domain); |
| 190 | return 0; | 190 | return 0; |
| 191 | } | 191 | } |
| 192 | } | 192 | } |
| @@ -198,7 +198,7 @@ int TranslateType(Type type) { | |||
| 198 | case Type::DGRAM: | 198 | case Type::DGRAM: |
| 199 | return SOCK_DGRAM; | 199 | return SOCK_DGRAM; |
| 200 | default: | 200 | default: |
| 201 | UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); | 201 | UNIMPLEMENTED_MSG("Unimplemented type={}", type); |
| 202 | return 0; | 202 | return 0; |
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| @@ -210,7 +210,7 @@ int TranslateProtocol(Protocol protocol) { | |||
| 210 | case Protocol::UDP: | 210 | case Protocol::UDP: |
| 211 | return IPPROTO_UDP; | 211 | return IPPROTO_UDP; |
| 212 | default: | 212 | default: |
| 213 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); | 213 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol); |
| 214 | return 0; | 214 | return 0; |
| 215 | } | 215 | } |
| 216 | } | 216 | } |
| @@ -238,45 +238,45 @@ SockAddrIn TranslateToSockAddrIn(sockaddr input_) { | |||
| 238 | return result; | 238 | return result; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | u16 TranslatePollEvents(u16 events) { | 241 | short TranslatePollEvents(PollEvents events) { |
| 242 | u16 result = 0; | 242 | short result = 0; |
| 243 | 243 | ||
| 244 | if (events & POLL_IN) { | 244 | if (True(events & PollEvents::In)) { |
| 245 | events &= ~POLL_IN; | 245 | events &= ~PollEvents::In; |
| 246 | result |= POLLIN; | 246 | result |= POLLIN; |
| 247 | } | 247 | } |
| 248 | if (events & POLL_PRI) { | 248 | if (True(events & PollEvents::Pri)) { |
| 249 | events &= ~POLL_PRI; | 249 | events &= ~PollEvents::Pri; |
| 250 | #ifdef _WIN32 | 250 | #ifdef _WIN32 |
| 251 | LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); | 251 | LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); |
| 252 | #else | 252 | #else |
| 253 | result |= POLL_PRI; | 253 | result |= POLLPRI; |
| 254 | #endif | 254 | #endif |
| 255 | } | 255 | } |
| 256 | if (events & POLL_OUT) { | 256 | if (True(events & PollEvents::Out)) { |
| 257 | events &= ~POLL_OUT; | 257 | events &= ~PollEvents::Out; |
| 258 | result |= POLLOUT; | 258 | result |= POLLOUT; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events); | 261 | UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events); |
| 262 | 262 | ||
| 263 | return result; | 263 | return result; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | u16 TranslatePollRevents(u16 revents) { | 266 | PollEvents TranslatePollRevents(short revents) { |
| 267 | u16 result = 0; | 267 | PollEvents result{}; |
| 268 | const auto translate = [&result, &revents](int host, unsigned guest) { | 268 | const auto translate = [&result, &revents](short host, PollEvents guest) { |
| 269 | if (revents & host) { | 269 | if ((revents & host) != 0) { |
| 270 | revents &= ~host; | 270 | revents &= static_cast<short>(~host); |
| 271 | result |= guest; | 271 | result |= guest; |
| 272 | } | 272 | } |
| 273 | }; | 273 | }; |
| 274 | 274 | ||
| 275 | translate(POLLIN, POLL_IN); | 275 | translate(POLLIN, PollEvents::In); |
| 276 | translate(POLLPRI, POLL_PRI); | 276 | translate(POLLPRI, PollEvents::Pri); |
| 277 | translate(POLLOUT, POLL_OUT); | 277 | translate(POLLOUT, PollEvents::Out); |
| 278 | translate(POLLERR, POLL_ERR); | 278 | translate(POLLERR, PollEvents::Err); |
| 279 | translate(POLLHUP, POLL_HUP); | 279 | translate(POLLHUP, PollEvents::Hup); |
| 280 | 280 | ||
| 281 | UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); | 281 | UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); |
| 282 | 282 | ||
| @@ -408,7 +408,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() { | |||
| 408 | 408 | ||
| 409 | Errno Socket::Connect(SockAddrIn addr_in) { | 409 | Errno Socket::Connect(SockAddrIn addr_in) { |
| 410 | const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in); | 410 | const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in); |
| 411 | if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) { | 411 | if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != SOCKET_ERROR) { |
| 412 | return Errno::SUCCESS; | 412 | return Errno::SUCCESS; |
| 413 | } | 413 | } |
| 414 | 414 | ||
| @@ -482,7 +482,7 @@ Errno Socket::Shutdown(ShutdownHow how) { | |||
| 482 | host_how = SD_BOTH; | 482 | host_how = SD_BOTH; |
| 483 | break; | 483 | break; |
| 484 | default: | 484 | default: |
| 485 | UNIMPLEMENTED_MSG("Unimplemented flag how={}", static_cast<int>(how)); | 485 | UNIMPLEMENTED_MSG("Unimplemented flag how={}", how); |
| 486 | return Errno::SUCCESS; | 486 | return Errno::SUCCESS; |
| 487 | } | 487 | } |
| 488 | if (shutdown(fd, host_how) != SOCKET_ERROR) { | 488 | if (shutdown(fd, host_how) != SOCKET_ERROR) { |
| @@ -503,10 +503,10 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { | |||
| 503 | ASSERT(flags == 0); | 503 | ASSERT(flags == 0); |
| 504 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | 504 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); |
| 505 | 505 | ||
| 506 | const int result = | 506 | const auto result = |
| 507 | recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0); | 507 | recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0); |
| 508 | if (result != SOCKET_ERROR) { | 508 | if (result != SOCKET_ERROR) { |
| 509 | return {result, Errno::SUCCESS}; | 509 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | switch (const int ec = LastError()) { | 512 | switch (const int ec = LastError()) { |
| @@ -531,14 +531,14 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock | |||
| 531 | socklen_t* const p_addrlen = addr ? &addrlen : nullptr; | 531 | socklen_t* const p_addrlen = addr ? &addrlen : nullptr; |
| 532 | sockaddr* const p_addr_in = addr ? &addr_in : nullptr; | 532 | sockaddr* const p_addr_in = addr ? &addr_in : nullptr; |
| 533 | 533 | ||
| 534 | const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()), | 534 | const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()), |
| 535 | static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); | 535 | static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); |
| 536 | if (result != SOCKET_ERROR) { | 536 | if (result != SOCKET_ERROR) { |
| 537 | if (addr) { | 537 | if (addr) { |
| 538 | ASSERT(addrlen == sizeof(addr_in)); | 538 | ASSERT(addrlen == sizeof(addr_in)); |
| 539 | *addr = TranslateToSockAddrIn(addr_in); | 539 | *addr = TranslateToSockAddrIn(addr_in); |
| 540 | } | 540 | } |
| 541 | return {result, Errno::SUCCESS}; | 541 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | switch (const int ec = LastError()) { | 544 | switch (const int ec = LastError()) { |
| @@ -558,10 +558,10 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { | |||
| 558 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); | 558 | ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); |
| 559 | ASSERT(flags == 0); | 559 | ASSERT(flags == 0); |
| 560 | 560 | ||
| 561 | const int result = send(fd, reinterpret_cast<const char*>(message.data()), | 561 | const auto result = send(fd, reinterpret_cast<const char*>(message.data()), |
| 562 | static_cast<int>(message.size()), 0); | 562 | static_cast<int>(message.size()), 0); |
| 563 | if (result != SOCKET_ERROR) { | 563 | if (result != SOCKET_ERROR) { |
| 564 | return {result, Errno::SUCCESS}; | 564 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 565 | } | 565 | } |
| 566 | 566 | ||
| 567 | const int ec = LastError(); | 567 | const int ec = LastError(); |
| @@ -591,10 +591,10 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, | |||
| 591 | to = &host_addr_in; | 591 | to = &host_addr_in; |
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | const int result = sendto(fd, reinterpret_cast<const char*>(message.data()), | 594 | const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()), |
| 595 | static_cast<int>(message.size()), 0, to, tolen); | 595 | static_cast<int>(message.size()), 0, to, tolen); |
| 596 | if (result != SOCKET_ERROR) { | 596 | if (result != SOCKET_ERROR) { |
| 597 | return {result, Errno::SUCCESS}; | 597 | return {static_cast<s32>(result), Errno::SUCCESS}; |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | const int ec = LastError(); | 600 | const int ec = LastError(); |
diff --git a/src/core/network/network.h b/src/core/network/network.h index 0622e4593..76b2821f2 100644 --- a/src/core/network/network.h +++ b/src/core/network/network.h | |||
| @@ -61,19 +61,25 @@ struct SockAddrIn { | |||
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | /// Cross-platform poll fd structure | 63 | /// Cross-platform poll fd structure |
| 64 | |||
| 65 | enum class PollEvents : u16 { | ||
| 66 | // Using Pascal case because IN is a macro on Windows. | ||
| 67 | In = 1 << 0, | ||
| 68 | Pri = 1 << 1, | ||
| 69 | Out = 1 << 2, | ||
| 70 | Err = 1 << 3, | ||
| 71 | Hup = 1 << 4, | ||
| 72 | Nval = 1 << 5, | ||
| 73 | }; | ||
| 74 | |||
| 75 | DECLARE_ENUM_FLAG_OPERATORS(PollEvents); | ||
| 76 | |||
| 64 | struct PollFD { | 77 | struct PollFD { |
| 65 | Socket* socket; | 78 | Socket* socket; |
| 66 | u16 events; | 79 | PollEvents events; |
| 67 | u16 revents; | 80 | PollEvents revents; |
| 68 | }; | 81 | }; |
| 69 | 82 | ||
| 70 | constexpr u16 POLL_IN = 1 << 0; | ||
| 71 | constexpr u16 POLL_PRI = 1 << 1; | ||
| 72 | constexpr u16 POLL_OUT = 1 << 2; | ||
| 73 | constexpr u16 POLL_ERR = 1 << 3; | ||
| 74 | constexpr u16 POLL_HUP = 1 << 4; | ||
| 75 | constexpr u16 POLL_NVAL = 1 << 5; | ||
| 76 | |||
| 77 | class NetworkInstance { | 83 | class NetworkInstance { |
| 78 | public: | 84 | public: |
| 79 | explicit NetworkInstance(); | 85 | explicit NetworkInstance(); |
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h index 7bdff0fe4..a44393325 100644 --- a/src/core/network/sockets.h +++ b/src/core/network/sockets.h | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #if defined(_WIN32) | 10 | #if defined(_WIN32) |
| 11 | #include <winsock.h> | 11 | #include <winsock.h> |
| 12 | #elif !defined(__unix__) | 12 | #elif !YUZU_UNIX |
| 13 | #error "Platform not implemented" | 13 | #error "Platform not implemented" |
| 14 | #endif | 14 | #endif |
| 15 | 15 | ||
| @@ -84,7 +84,7 @@ public: | |||
| 84 | 84 | ||
| 85 | #if defined(_WIN32) | 85 | #if defined(_WIN32) |
| 86 | SOCKET fd = INVALID_SOCKET; | 86 | SOCKET fd = INVALID_SOCKET; |
| 87 | #elif defined(__unix__) | 87 | #elif YUZU_UNIX |
| 88 | int fd = -1; | 88 | int fd = -1; |
| 89 | #endif | 89 | #endif |
| 90 | }; | 90 | }; |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 28d3f9099..39306509a 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -4,9 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <string_view> | 5 | #include <string_view> |
| 6 | 6 | ||
| 7 | #include "common/assert.h" | ||
| 7 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | ||
| 8 | #include "core/core.h" | 10 | #include "core/core.h" |
| 9 | #include "core/gdbstub/gdbstub.h" | ||
| 10 | #include "core/hle/service/hid/hid.h" | 11 | #include "core/hle/service/hid/hid.h" |
| 11 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 12 | #include "video_core/renderer_base.h" | 13 | #include "video_core/renderer_base.h" |
| @@ -14,7 +15,7 @@ | |||
| 14 | namespace Settings { | 15 | namespace Settings { |
| 15 | 16 | ||
| 16 | Values values = {}; | 17 | Values values = {}; |
| 17 | bool configuring_global = true; | 18 | static bool configuring_global = true; |
| 18 | 19 | ||
| 19 | std::string GetTimeZoneString() { | 20 | std::string GetTimeZoneString() { |
| 20 | static constexpr std::array timezones{ | 21 | static constexpr std::array timezones{ |
| @@ -31,13 +32,9 @@ std::string GetTimeZoneString() { | |||
| 31 | return timezones[time_zone_index]; | 32 | return timezones[time_zone_index]; |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | void Apply() { | 35 | void Apply(Core::System& system) { |
| 35 | GDBStub::SetServerPort(values.gdbstub_port); | 36 | if (system.IsPoweredOn()) { |
| 36 | GDBStub::ToggleServer(values.use_gdbstub); | 37 | system.Renderer().RefreshBaseSettings(); |
| 37 | |||
| 38 | auto& system_instance = Core::System::GetInstance(); | ||
| 39 | if (system_instance.IsPoweredOn()) { | ||
| 40 | system_instance.Renderer().RefreshBaseSettings(); | ||
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | Service::HID::ReloadInputDevices(); | 40 | Service::HID::ReloadInputDevices(); |
| @@ -49,13 +46,14 @@ void LogSettings() { | |||
| 49 | }; | 46 | }; |
| 50 | 47 | ||
| 51 | LOG_INFO(Config, "yuzu Configuration:"); | 48 | LOG_INFO(Config, "yuzu Configuration:"); |
| 52 | log_setting("Controls_UseDockedMode", values.use_docked_mode); | 49 | log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue()); |
| 53 | log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); | 50 | log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); |
| 54 | log_setting("System_CurrentUser", values.current_user); | 51 | log_setting("System_CurrentUser", values.current_user); |
| 55 | log_setting("System_LanguageIndex", values.language_index.GetValue()); | 52 | log_setting("System_LanguageIndex", values.language_index.GetValue()); |
| 56 | log_setting("System_RegionIndex", values.region_index.GetValue()); | 53 | log_setting("System_RegionIndex", values.region_index.GetValue()); |
| 57 | log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); | 54 | log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); |
| 58 | log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); | 55 | log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); |
| 56 | log_setting("CPU_Accuracy", values.cpu_accuracy); | ||
| 59 | log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); | 57 | log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); |
| 60 | log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); | 58 | log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); |
| 61 | log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); | 59 | log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); |
| @@ -63,6 +61,7 @@ void LogSettings() { | |||
| 63 | log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); | 61 | log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); |
| 64 | log_setting("Renderer_UseAsynchronousGpuEmulation", | 62 | log_setting("Renderer_UseAsynchronousGpuEmulation", |
| 65 | values.use_asynchronous_gpu_emulation.GetValue()); | 63 | values.use_asynchronous_gpu_emulation.GetValue()); |
| 64 | log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue()); | ||
| 66 | log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); | 65 | log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); |
| 67 | log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); | 66 | log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); |
| 68 | log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); | 67 | log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); |
| @@ -73,18 +72,17 @@ void LogSettings() { | |||
| 73 | log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); | 72 | log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); |
| 74 | log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); | 73 | log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); |
| 75 | log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); | 74 | log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); |
| 76 | log_setting("Debugging_UseGdbstub", values.use_gdbstub); | ||
| 77 | log_setting("Debugging_GdbstubPort", values.gdbstub_port); | ||
| 78 | log_setting("Debugging_ProgramArgs", values.program_args); | 75 | log_setting("Debugging_ProgramArgs", values.program_args); |
| 79 | log_setting("Services_BCATBackend", values.bcat_backend); | 76 | log_setting("Services_BCATBackend", values.bcat_backend); |
| 80 | log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); | 77 | log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); |
| 81 | } | 78 | } |
| 82 | 79 | ||
| 83 | float Volume() { | 80 | bool IsConfiguringGlobal() { |
| 84 | if (values.audio_muted) { | 81 | return configuring_global; |
| 85 | return 0.0f; | 82 | } |
| 86 | } | 83 | |
| 87 | return values.volume.GetValue(); | 84 | void SetConfiguringGlobal(bool is_global) { |
| 85 | configuring_global = is_global; | ||
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | bool IsGPULevelExtreme() { | 88 | bool IsGPULevelExtreme() { |
| @@ -96,9 +94,16 @@ bool IsGPULevelHigh() { | |||
| 96 | values.gpu_accuracy.GetValue() == GPUAccuracy::High; | 94 | values.gpu_accuracy.GetValue() == GPUAccuracy::High; |
| 97 | } | 95 | } |
| 98 | 96 | ||
| 99 | void RestoreGlobalState() { | 97 | float Volume() { |
| 98 | if (values.audio_muted) { | ||
| 99 | return 0.0f; | ||
| 100 | } | ||
| 101 | return values.volume.GetValue(); | ||
| 102 | } | ||
| 103 | |||
| 104 | void RestoreGlobalState(bool is_powered_on) { | ||
| 100 | // If a game is running, DO NOT restore the global settings state | 105 | // If a game is running, DO NOT restore the global settings state |
| 101 | if (Core::System::GetInstance().IsPoweredOn()) { | 106 | if (is_powered_on) { |
| 102 | return; | 107 | return; |
| 103 | } | 108 | } |
| 104 | 109 | ||
| @@ -119,6 +124,7 @@ void RestoreGlobalState() { | |||
| 119 | values.use_disk_shader_cache.SetGlobal(true); | 124 | values.use_disk_shader_cache.SetGlobal(true); |
| 120 | values.gpu_accuracy.SetGlobal(true); | 125 | values.gpu_accuracy.SetGlobal(true); |
| 121 | values.use_asynchronous_gpu_emulation.SetGlobal(true); | 126 | values.use_asynchronous_gpu_emulation.SetGlobal(true); |
| 127 | values.use_nvdec_emulation.SetGlobal(true); | ||
| 122 | values.use_vsync.SetGlobal(true); | 128 | values.use_vsync.SetGlobal(true); |
| 123 | values.use_assembly_shaders.SetGlobal(true); | 129 | values.use_assembly_shaders.SetGlobal(true); |
| 124 | values.use_asynchronous_shaders.SetGlobal(true); | 130 | values.use_asynchronous_shaders.SetGlobal(true); |
| @@ -134,11 +140,12 @@ void RestoreGlobalState() { | |||
| 134 | values.rng_seed.SetGlobal(true); | 140 | values.rng_seed.SetGlobal(true); |
| 135 | values.custom_rtc.SetGlobal(true); | 141 | values.custom_rtc.SetGlobal(true); |
| 136 | values.sound_index.SetGlobal(true); | 142 | values.sound_index.SetGlobal(true); |
| 137 | } | ||
| 138 | 143 | ||
| 139 | void Sanitize() { | 144 | // Controls |
| 140 | values.use_asynchronous_gpu_emulation.SetValue( | 145 | values.players.SetGlobal(true); |
| 141 | values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue()); | 146 | values.use_docked_mode.SetGlobal(true); |
| 147 | values.vibration_enabled.SetGlobal(true); | ||
| 148 | values.motion_enabled.SetGlobal(true); | ||
| 142 | } | 149 | } |
| 143 | 150 | ||
| 144 | } // namespace Settings | 151 | } // namespace Settings |
diff --git a/src/core/settings.h b/src/core/settings.h index 9834f44bb..a324530bd 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -14,6 +14,10 @@ | |||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "input_common/settings.h" | 15 | #include "input_common/settings.h" |
| 16 | 16 | ||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 17 | namespace Settings { | 21 | namespace Settings { |
| 18 | 22 | ||
| 19 | enum class RendererBackend { | 23 | enum class RendererBackend { |
| @@ -33,8 +37,6 @@ enum class CPUAccuracy { | |||
| 33 | DebugMode = 2, | 37 | DebugMode = 2, |
| 34 | }; | 38 | }; |
| 35 | 39 | ||
| 36 | extern bool configuring_global; | ||
| 37 | |||
| 38 | template <typename Type> | 40 | template <typename Type> |
| 39 | class Setting final { | 41 | class Setting final { |
| 40 | public: | 42 | public: |
| @@ -67,6 +69,38 @@ private: | |||
| 67 | Type local{}; | 69 | Type local{}; |
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 72 | /** | ||
| 73 | * The InputSetting class allows for getting a reference to either the global or local members. | ||
| 74 | * This is required as we cannot easily modify the values of user-defined types within containers | ||
| 75 | * using the SetValue() member function found in the Setting class. The primary purpose of this | ||
| 76 | * class is to store an array of 10 PlayerInput structs for both the global and local (per-game) | ||
| 77 | * setting and allows for easily accessing and modifying both settings. | ||
| 78 | */ | ||
| 79 | template <typename Type> | ||
| 80 | class InputSetting final { | ||
| 81 | public: | ||
| 82 | InputSetting() = default; | ||
| 83 | explicit InputSetting(Type val) : global{val} {} | ||
| 84 | ~InputSetting() = default; | ||
| 85 | void SetGlobal(bool to_global) { | ||
| 86 | use_global = to_global; | ||
| 87 | } | ||
| 88 | bool UsingGlobal() const { | ||
| 89 | return use_global; | ||
| 90 | } | ||
| 91 | Type& GetValue(bool need_global = false) { | ||
| 92 | if (use_global || need_global) { | ||
| 93 | return global; | ||
| 94 | } | ||
| 95 | return local; | ||
| 96 | } | ||
| 97 | |||
| 98 | private: | ||
| 99 | bool use_global = true; | ||
| 100 | Type global{}; | ||
| 101 | Type local{}; | ||
| 102 | }; | ||
| 103 | |||
| 70 | struct TouchFromButtonMap { | 104 | struct TouchFromButtonMap { |
| 71 | std::string name; | 105 | std::string name; |
| 72 | std::vector<std::string> buttons; | 106 | std::vector<std::string> buttons; |
| @@ -97,13 +131,14 @@ struct Values { | |||
| 97 | 131 | ||
| 98 | bool cpuopt_unsafe_unfuse_fma; | 132 | bool cpuopt_unsafe_unfuse_fma; |
| 99 | bool cpuopt_unsafe_reduce_fp_error; | 133 | bool cpuopt_unsafe_reduce_fp_error; |
| 134 | bool cpuopt_unsafe_inaccurate_nan; | ||
| 100 | 135 | ||
| 101 | // Renderer | 136 | // Renderer |
| 102 | Setting<RendererBackend> renderer_backend; | 137 | Setting<RendererBackend> renderer_backend; |
| 103 | bool renderer_debug; | 138 | bool renderer_debug; |
| 104 | Setting<int> vulkan_device; | 139 | Setting<int> vulkan_device; |
| 105 | 140 | ||
| 106 | Setting<u16> resolution_factor = Setting(static_cast<u16>(1)); | 141 | Setting<u16> resolution_factor{1}; |
| 107 | Setting<int> aspect_ratio; | 142 | Setting<int> aspect_ratio; |
| 108 | Setting<int> max_anisotropy; | 143 | Setting<int> max_anisotropy; |
| 109 | Setting<bool> use_frame_limit; | 144 | Setting<bool> use_frame_limit; |
| @@ -111,6 +146,7 @@ struct Values { | |||
| 111 | Setting<bool> use_disk_shader_cache; | 146 | Setting<bool> use_disk_shader_cache; |
| 112 | Setting<GPUAccuracy> gpu_accuracy; | 147 | Setting<GPUAccuracy> gpu_accuracy; |
| 113 | Setting<bool> use_asynchronous_gpu_emulation; | 148 | Setting<bool> use_asynchronous_gpu_emulation; |
| 149 | Setting<bool> use_nvdec_emulation; | ||
| 114 | Setting<bool> use_vsync; | 150 | Setting<bool> use_vsync; |
| 115 | Setting<bool> use_assembly_shaders; | 151 | Setting<bool> use_assembly_shaders; |
| 116 | Setting<bool> use_asynchronous_shaders; | 152 | Setting<bool> use_asynchronous_shaders; |
| @@ -134,9 +170,18 @@ struct Values { | |||
| 134 | Setting<s32> sound_index; | 170 | Setting<s32> sound_index; |
| 135 | 171 | ||
| 136 | // Controls | 172 | // Controls |
| 137 | std::array<PlayerInput, 10> players; | 173 | InputSetting<std::array<PlayerInput, 10>> players; |
| 174 | |||
| 175 | Setting<bool> use_docked_mode; | ||
| 176 | |||
| 177 | Setting<bool> vibration_enabled; | ||
| 178 | Setting<bool> enable_accurate_vibrations; | ||
| 179 | |||
| 180 | Setting<bool> motion_enabled; | ||
| 181 | std::string motion_device; | ||
| 182 | std::string udp_input_servers; | ||
| 138 | 183 | ||
| 139 | bool use_docked_mode; | 184 | bool emulate_analog_keyboard; |
| 140 | 185 | ||
| 141 | bool mouse_enabled; | 186 | bool mouse_enabled; |
| 142 | std::string mouse_device; | 187 | std::string mouse_device; |
| @@ -150,20 +195,15 @@ struct Values { | |||
| 150 | ButtonsRaw debug_pad_buttons; | 195 | ButtonsRaw debug_pad_buttons; |
| 151 | AnalogsRaw debug_pad_analogs; | 196 | AnalogsRaw debug_pad_analogs; |
| 152 | 197 | ||
| 153 | bool vibration_enabled; | ||
| 154 | |||
| 155 | bool motion_enabled; | ||
| 156 | std::string motion_device; | ||
| 157 | std::string touch_device; | ||
| 158 | TouchscreenInput touchscreen; | 198 | TouchscreenInput touchscreen; |
| 159 | std::atomic_bool is_device_reload_pending{true}; | 199 | |
| 160 | bool use_touch_from_button; | 200 | bool use_touch_from_button; |
| 201 | std::string touch_device; | ||
| 161 | int touch_from_button_map_index; | 202 | int touch_from_button_map_index; |
| 162 | std::string udp_input_address; | ||
| 163 | u16 udp_input_port; | ||
| 164 | u8 udp_pad_index; | ||
| 165 | std::vector<TouchFromButtonMap> touch_from_button_maps; | 203 | std::vector<TouchFromButtonMap> touch_from_button_maps; |
| 166 | 204 | ||
| 205 | std::atomic_bool is_device_reload_pending{true}; | ||
| 206 | |||
| 167 | // Data Storage | 207 | // Data Storage |
| 168 | bool use_virtual_sd; | 208 | bool use_virtual_sd; |
| 169 | bool gamecard_inserted; | 209 | bool gamecard_inserted; |
| @@ -180,8 +220,9 @@ struct Values { | |||
| 180 | bool reporting_services; | 220 | bool reporting_services; |
| 181 | bool quest_flag; | 221 | bool quest_flag; |
| 182 | bool disable_macro_jit; | 222 | bool disable_macro_jit; |
| 223 | bool extended_logging; | ||
| 183 | 224 | ||
| 184 | // Misceallaneous | 225 | // Miscellaneous |
| 185 | std::string log_filter; | 226 | std::string log_filter; |
| 186 | bool use_dev_keys; | 227 | bool use_dev_keys; |
| 187 | 228 | ||
| @@ -197,22 +238,24 @@ struct Values { | |||
| 197 | 238 | ||
| 198 | // Add-Ons | 239 | // Add-Ons |
| 199 | std::map<u64, std::vector<std::string>> disabled_addons; | 240 | std::map<u64, std::vector<std::string>> disabled_addons; |
| 200 | } extern values; | 241 | }; |
| 201 | 242 | ||
| 202 | float Volume(); | 243 | extern Values values; |
| 244 | |||
| 245 | bool IsConfiguringGlobal(); | ||
| 246 | void SetConfiguringGlobal(bool is_global); | ||
| 203 | 247 | ||
| 204 | bool IsGPULevelExtreme(); | 248 | bool IsGPULevelExtreme(); |
| 205 | bool IsGPULevelHigh(); | 249 | bool IsGPULevelHigh(); |
| 206 | 250 | ||
| 251 | float Volume(); | ||
| 252 | |||
| 207 | std::string GetTimeZoneString(); | 253 | std::string GetTimeZoneString(); |
| 208 | 254 | ||
| 209 | void Apply(); | 255 | void Apply(Core::System& system); |
| 210 | void LogSettings(); | 256 | void LogSettings(); |
| 211 | 257 | ||
| 212 | // Restore the global state of all applicable settings in the Values struct | 258 | // Restore the global state of all applicable settings in the Values struct |
| 213 | void RestoreGlobalState(); | 259 | void RestoreGlobalState(bool is_powered_on); |
| 214 | |||
| 215 | // Fixes settings that are known to cause issues with the emulator | ||
| 216 | void Sanitize(); | ||
| 217 | 260 | ||
| 218 | } // namespace Settings | 261 | } // namespace Settings |
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index da09c0dbc..d11b15f38 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp | |||
| @@ -147,7 +147,9 @@ TelemetrySession::~TelemetrySession() { | |||
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | 150 | void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, |
| 151 | const Service::FileSystem::FileSystemController& fsc, | ||
| 152 | const FileSys::ContentProvider& content_provider) { | ||
| 151 | // Log one-time top-level information | 153 | // Log one-time top-level information |
| 152 | AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); | 154 | AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); |
| 153 | 155 | ||
| @@ -167,7 +169,10 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | |||
| 167 | app_loader.ReadTitle(name); | 169 | app_loader.ReadTitle(name); |
| 168 | 170 | ||
| 169 | if (name.empty()) { | 171 | if (name.empty()) { |
| 170 | const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata(); | 172 | const auto metadata = [&content_provider, &fsc, program_id] { |
| 173 | const FileSys::PatchManager pm{program_id, fsc, content_provider}; | ||
| 174 | return pm.GetControlMetadata(); | ||
| 175 | }(); | ||
| 171 | if (metadata.first != nullptr) { | 176 | if (metadata.first != nullptr) { |
| 172 | name = metadata.first->GetApplicationName(); | 177 | name = metadata.first->GetApplicationName(); |
| 173 | } | 178 | } |
| @@ -206,12 +211,14 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | |||
| 206 | TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); | 211 | TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); |
| 207 | AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", | 212 | AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", |
| 208 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); | 213 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); |
| 214 | AddField(field_type, "Renderer_UseNvdecEmulation", | ||
| 215 | Settings::values.use_nvdec_emulation.GetValue()); | ||
| 209 | AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); | 216 | AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); |
| 210 | AddField(field_type, "Renderer_UseAssemblyShaders", | 217 | AddField(field_type, "Renderer_UseAssemblyShaders", |
| 211 | Settings::values.use_assembly_shaders.GetValue()); | 218 | Settings::values.use_assembly_shaders.GetValue()); |
| 212 | AddField(field_type, "Renderer_UseAsynchronousShaders", | 219 | AddField(field_type, "Renderer_UseAsynchronousShaders", |
| 213 | Settings::values.use_asynchronous_shaders.GetValue()); | 220 | Settings::values.use_asynchronous_shaders.GetValue()); |
| 214 | AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); | 221 | AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue()); |
| 215 | } | 222 | } |
| 216 | 223 | ||
| 217 | bool TelemetrySession::SubmitTestcase() { | 224 | bool TelemetrySession::SubmitTestcase() { |
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 66789d4bd..6f3d45bea 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h | |||
| @@ -7,10 +7,18 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include "common/telemetry.h" | 8 | #include "common/telemetry.h" |
| 9 | 9 | ||
| 10 | namespace FileSys { | ||
| 11 | class ContentProvider; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Loader { | 14 | namespace Loader { |
| 11 | class AppLoader; | 15 | class AppLoader; |
| 12 | } | 16 | } |
| 13 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 14 | namespace Core { | 22 | namespace Core { |
| 15 | 23 | ||
| 16 | /** | 24 | /** |
| @@ -40,10 +48,14 @@ public: | |||
| 40 | * - Title file format | 48 | * - Title file format |
| 41 | * - Miscellaneous settings values. | 49 | * - Miscellaneous settings values. |
| 42 | * | 50 | * |
| 43 | * @param app_loader The application loader to use to retrieve | 51 | * @param app_loader The application loader to use to retrieve |
| 44 | * title-specific information. | 52 | * title-specific information. |
| 53 | * @param fsc Filesystem controller to use to retrieve info. | ||
| 54 | * @param content_provider Content provider to use to retrieve info. | ||
| 45 | */ | 55 | */ |
| 46 | void AddInitialInfo(Loader::AppLoader& app_loader); | 56 | void AddInitialInfo(Loader::AppLoader& app_loader, |
| 57 | const Service::FileSystem::FileSystemController& fsc, | ||
| 58 | const FileSys::ContentProvider& content_provider); | ||
| 47 | 59 | ||
| 48 | /** | 60 | /** |
| 49 | * Wrapper around the Telemetry::FieldCollection::AddField method. | 61 | * Wrapper around the Telemetry::FieldCollection::AddField method. |