diff options
Diffstat (limited to 'src/core')
70 files changed, 2131 insertions, 294 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a6b56c9c6..3b1d72cf9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,3 +1,9 @@ | |||
| 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 | |||
| 1 | add_library(core STATIC | 7 | add_library(core STATIC |
| 2 | arm/arm_interface.h | 8 | arm/arm_interface.h |
| 3 | arm/arm_interface.cpp | 9 | arm/arm_interface.cpp |
| @@ -82,6 +88,8 @@ add_library(core STATIC | |||
| 82 | file_sys/vfs_concat.h | 88 | file_sys/vfs_concat.h |
| 83 | file_sys/vfs_layered.cpp | 89 | file_sys/vfs_layered.cpp |
| 84 | file_sys/vfs_layered.h | 90 | file_sys/vfs_layered.h |
| 91 | file_sys/vfs_libzip.cpp | ||
| 92 | file_sys/vfs_libzip.h | ||
| 85 | file_sys/vfs_offset.cpp | 93 | file_sys/vfs_offset.cpp |
| 86 | file_sys/vfs_offset.h | 94 | file_sys/vfs_offset.h |
| 87 | file_sys/vfs_real.cpp | 95 | file_sys/vfs_real.cpp |
| @@ -241,6 +249,9 @@ add_library(core STATIC | |||
| 241 | hle/service/audio/errors.h | 249 | hle/service/audio/errors.h |
| 242 | hle/service/audio/hwopus.cpp | 250 | hle/service/audio/hwopus.cpp |
| 243 | hle/service/audio/hwopus.h | 251 | hle/service/audio/hwopus.h |
| 252 | hle/service/bcat/backend/backend.cpp | ||
| 253 | hle/service/bcat/backend/backend.h | ||
| 254 | ${BCAT_BOXCAT_ADDITIONAL_SOURCES} | ||
| 244 | hle/service/bcat/bcat.cpp | 255 | hle/service/bcat/bcat.cpp |
| 245 | hle/service/bcat/bcat.h | 256 | hle/service/bcat/bcat.h |
| 246 | hle/service/bcat/module.cpp | 257 | hle/service/bcat/module.cpp |
| @@ -324,6 +335,8 @@ add_library(core STATIC | |||
| 324 | hle/service/ldr/ldr.h | 335 | hle/service/ldr/ldr.h |
| 325 | hle/service/lm/lm.cpp | 336 | hle/service/lm/lm.cpp |
| 326 | hle/service/lm/lm.h | 337 | hle/service/lm/lm.h |
| 338 | hle/service/lm/manager.cpp | ||
| 339 | hle/service/lm/manager.h | ||
| 327 | hle/service/mig/mig.cpp | 340 | hle/service/mig/mig.cpp |
| 328 | hle/service/mig/mig.h | 341 | hle/service/mig/mig.h |
| 329 | hle/service/mii/mii.cpp | 342 | hle/service/mii/mii.cpp |
| @@ -499,6 +512,15 @@ create_target_directory_groups(core) | |||
| 499 | 512 | ||
| 500 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 513 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 501 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) | 514 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) |
| 515 | |||
| 516 | if (YUZU_ENABLE_BOXCAT) | ||
| 517 | get_directory_property(OPENSSL_LIBS | ||
| 518 | DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl | ||
| 519 | DEFINITION OPENSSL_LIBS) | ||
| 520 | target_compile_definitions(core PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT -DYUZU_ENABLE_BOXCAT) | ||
| 521 | target_link_libraries(core PRIVATE httplib json-headers ${OPENSSL_LIBS} zip) | ||
| 522 | endif() | ||
| 523 | |||
| 502 | if (ENABLE_WEB_SERVICE) | 524 | if (ENABLE_WEB_SERVICE) |
| 503 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) | 525 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) |
| 504 | target_link_libraries(core PRIVATE web_service) | 526 | target_link_libraries(core PRIVATE web_service) |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 92ba42fb9..4d0ac72a5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include "core/hle/service/apm/controller.h" | 35 | #include "core/hle/service/apm/controller.h" |
| 36 | #include "core/hle/service/filesystem/filesystem.h" | 36 | #include "core/hle/service/filesystem/filesystem.h" |
| 37 | #include "core/hle/service/glue/manager.h" | 37 | #include "core/hle/service/glue/manager.h" |
| 38 | #include "core/hle/service/lm/manager.h" | ||
| 38 | #include "core/hle/service/service.h" | 39 | #include "core/hle/service/service.h" |
| 39 | #include "core/hle/service/sm/sm.h" | 40 | #include "core/hle/service/sm/sm.h" |
| 40 | #include "core/loader/loader.h" | 41 | #include "core/loader/loader.h" |
| @@ -111,7 +112,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 111 | } | 112 | } |
| 112 | struct System::Impl { | 113 | struct System::Impl { |
| 113 | explicit Impl(System& system) | 114 | explicit Impl(System& system) |
| 114 | : kernel{system}, cpu_core_manager{system}, applet_manager{system}, reporter{system} {} | 115 | : kernel{system}, fs_controller{system}, cpu_core_manager{system}, |
| 116 | applet_manager{system}, reporter{system} {} | ||
| 115 | 117 | ||
| 116 | Cpu& CurrentCpuCore() { | 118 | Cpu& CurrentCpuCore() { |
| 117 | return cpu_core_manager.GetCurrentCore(); | 119 | return cpu_core_manager.GetCurrentCore(); |
| @@ -249,6 +251,8 @@ struct System::Impl { | |||
| 249 | telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", | 251 | telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", |
| 250 | perf_stats->GetMeanFrametime()); | 252 | perf_stats->GetMeanFrametime()); |
| 251 | 253 | ||
| 254 | lm_manager.Flush(); | ||
| 255 | |||
| 252 | is_powered_on = false; | 256 | is_powered_on = false; |
| 253 | exit_lock = false; | 257 | exit_lock = false; |
| 254 | 258 | ||
| @@ -337,8 +341,10 @@ struct System::Impl { | |||
| 337 | bool is_powered_on = false; | 341 | bool is_powered_on = false; |
| 338 | bool exit_lock = false; | 342 | bool exit_lock = false; |
| 339 | 343 | ||
| 344 | Reporter reporter; | ||
| 340 | std::unique_ptr<Memory::CheatEngine> cheat_engine; | 345 | std::unique_ptr<Memory::CheatEngine> cheat_engine; |
| 341 | std::unique_ptr<Tools::Freezer> memory_freezer; | 346 | std::unique_ptr<Tools::Freezer> memory_freezer; |
| 347 | std::array<u8, 0x20> build_id{}; | ||
| 342 | 348 | ||
| 343 | /// Frontend applets | 349 | /// Frontend applets |
| 344 | Service::AM::Applets::AppletManager applet_manager; | 350 | Service::AM::Applets::AppletManager applet_manager; |
| @@ -346,8 +352,9 @@ struct System::Impl { | |||
| 346 | /// APM (Performance) services | 352 | /// APM (Performance) services |
| 347 | Service::APM::Controller apm_controller{core_timing}; | 353 | Service::APM::Controller apm_controller{core_timing}; |
| 348 | 354 | ||
| 349 | /// Glue services | 355 | /// Service State |
| 350 | Service::Glue::ARPManager arp_manager; | 356 | Service::Glue::ARPManager arp_manager; |
| 357 | Service::LM::Manager lm_manager{reporter}; | ||
| 351 | 358 | ||
| 352 | /// Service manager | 359 | /// Service manager |
| 353 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 360 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| @@ -355,8 +362,6 @@ struct System::Impl { | |||
| 355 | /// Telemetry session for this emulation session | 362 | /// Telemetry session for this emulation session |
| 356 | std::unique_ptr<Core::TelemetrySession> telemetry_session; | 363 | std::unique_ptr<Core::TelemetrySession> telemetry_session; |
| 357 | 364 | ||
| 358 | Reporter reporter; | ||
| 359 | |||
| 360 | ResultStatus status = ResultStatus::Success; | 365 | ResultStatus status = ResultStatus::Success; |
| 361 | std::string status_details = ""; | 366 | std::string status_details = ""; |
| 362 | 367 | ||
| @@ -632,6 +637,14 @@ const Service::APM::Controller& System::GetAPMController() const { | |||
| 632 | return impl->apm_controller; | 637 | return impl->apm_controller; |
| 633 | } | 638 | } |
| 634 | 639 | ||
| 640 | Service::LM::Manager& System::GetLogManager() { | ||
| 641 | return impl->lm_manager; | ||
| 642 | } | ||
| 643 | |||
| 644 | const Service::LM::Manager& System::GetLogManager() const { | ||
| 645 | return impl->lm_manager; | ||
| 646 | } | ||
| 647 | |||
| 635 | void System::SetExitLock(bool locked) { | 648 | void System::SetExitLock(bool locked) { |
| 636 | impl->exit_lock = locked; | 649 | impl->exit_lock = locked; |
| 637 | } | 650 | } |
| @@ -640,6 +653,14 @@ bool System::GetExitLock() const { | |||
| 640 | return impl->exit_lock; | 653 | return impl->exit_lock; |
| 641 | } | 654 | } |
| 642 | 655 | ||
| 656 | void System::SetCurrentProcessBuildID(const CurrentBuildProcessID& id) { | ||
| 657 | impl->build_id = id; | ||
| 658 | } | ||
| 659 | |||
| 660 | const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const { | ||
| 661 | return impl->build_id; | ||
| 662 | } | ||
| 663 | |||
| 643 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 664 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 644 | return impl->Init(*this, emu_window); | 665 | return impl->Init(*this, emu_window); |
| 645 | } | 666 | } |
diff --git a/src/core/core.h b/src/core/core.h index ff10ebe12..90e7ac607 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | 10 | ||
| 11 | #include <map> | ||
| 12 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 13 | #include "core/file_sys/vfs_types.h" | 12 | #include "core/file_sys/vfs_types.h" |
| 14 | #include "core/hle/kernel/object.h" | 13 | #include "core/hle/kernel/object.h" |
| @@ -58,6 +57,10 @@ namespace Glue { | |||
| 58 | class ARPManager; | 57 | class ARPManager; |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 60 | namespace LM { | ||
| 61 | class Manager; | ||
| 62 | } // namespace LM | ||
| 63 | |||
| 61 | namespace SM { | 64 | namespace SM { |
| 62 | class ServiceManager; | 65 | class ServiceManager; |
| 63 | } // namespace SM | 66 | } // namespace SM |
| @@ -98,6 +101,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 98 | 101 | ||
| 99 | class System { | 102 | class System { |
| 100 | public: | 103 | public: |
| 104 | using CurrentBuildProcessID = std::array<u8, 0x20>; | ||
| 105 | |||
| 101 | System(const System&) = delete; | 106 | System(const System&) = delete; |
| 102 | System& operator=(const System&) = delete; | 107 | System& operator=(const System&) = delete; |
| 103 | 108 | ||
| @@ -326,10 +331,18 @@ public: | |||
| 326 | 331 | ||
| 327 | const Service::APM::Controller& GetAPMController() const; | 332 | const Service::APM::Controller& GetAPMController() const; |
| 328 | 333 | ||
| 334 | Service::LM::Manager& GetLogManager(); | ||
| 335 | |||
| 336 | const Service::LM::Manager& GetLogManager() const; | ||
| 337 | |||
| 329 | void SetExitLock(bool locked); | 338 | void SetExitLock(bool locked); |
| 330 | 339 | ||
| 331 | bool GetExitLock() const; | 340 | bool GetExitLock() const; |
| 332 | 341 | ||
| 342 | void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); | ||
| 343 | |||
| 344 | const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | ||
| 345 | |||
| 333 | private: | 346 | private: |
| 334 | System(); | 347 | System(); |
| 335 | 348 | ||
| @@ -353,8 +366,4 @@ private: | |||
| 353 | static System s_instance; | 366 | static System s_instance; |
| 354 | }; | 367 | }; |
| 355 | 368 | ||
| 356 | inline Kernel::Process* CurrentProcess() { | ||
| 357 | return System::GetInstance().CurrentProcess(); | ||
| 358 | } | ||
| 359 | |||
| 360 | } // namespace Core | 369 | } // namespace Core |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 46aceec3d..222fc95ba 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -423,7 +423,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { | |||
| 423 | std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, | 423 | std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, |
| 424 | const RSAKeyPair<2048>& key) { | 424 | const RSAKeyPair<2048>& key) { |
| 425 | const auto issuer = ticket.GetData().issuer; | 425 | const auto issuer = ticket.GetData().issuer; |
| 426 | if (issuer == std::array<u8, 0x40>{}) | 426 | if (IsAllZeroArray(issuer)) |
| 427 | return {}; | 427 | return {}; |
| 428 | if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { | 428 | if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { |
| 429 | LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); | 429 | LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); |
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 8f758d6d9..0af44f340 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -136,4 +136,9 @@ u64 BISFactory::GetFullNANDTotalSpace() const { | |||
| 136 | return static_cast<u64>(Settings::values.nand_total_size); | 136 | return static_cast<u64>(Settings::values.nand_total_size); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { | ||
| 140 | return GetOrCreateDirectoryRelative(nand_root, | ||
| 141 | fmt::format("/system/save/bcat/{:016X}", title_id)); | ||
| 142 | } | ||
| 143 | |||
| 139 | } // namespace FileSys | 144 | } // namespace FileSys |
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index bdfe728c9..8f0451c98 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h | |||
| @@ -61,6 +61,8 @@ public: | |||
| 61 | u64 GetUserNANDTotalSpace() const; | 61 | u64 GetUserNANDTotalSpace() const; |
| 62 | u64 GetFullNANDTotalSpace() const; | 62 | u64 GetFullNANDTotalSpace() const; |
| 63 | 63 | ||
| 64 | VirtualDir GetBCATDirectory(u64 title_id) const; | ||
| 65 | |||
| 64 | private: | 66 | private: |
| 65 | VirtualDir nand_root; | 67 | VirtualDir nand_root; |
| 66 | VirtualDir load_root; | 68 | VirtualDir load_root; |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 84cd4684c..4bd2e6183 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -35,11 +35,11 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) { | |||
| 35 | this->update_raw = std::move(update_raw); | 35 | this->update_raw = std::move(update_raw); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const { | 38 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { |
| 39 | if (!updatable) | 39 | if (!updatable) |
| 40 | return MakeResult<VirtualFile>(file); | 40 | return MakeResult<VirtualFile>(file); |
| 41 | 41 | ||
| 42 | const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID()); | 42 | const PatchManager patch_manager(current_process_title_id); |
| 43 | return MakeResult<VirtualFile>( | 43 | return MakeResult<VirtualFile>( |
| 44 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); | 44 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); |
| 45 | } | 45 | } |
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index da63a313a..c5d40285c 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | ~RomFSFactory(); | 33 | ~RomFSFactory(); |
| 34 | 34 | ||
| 35 | void SetPackedUpdate(VirtualFile update_raw); | 35 | void SetPackedUpdate(VirtualFile update_raw); |
| 36 | ResultVal<VirtualFile> OpenCurrentProcess() const; | 36 | ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; |
| 37 | ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const; | 37 | ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const; |
| 38 | 38 | ||
| 39 | private: | 39 | private: |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index f77cc02ac..fc8755c78 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -127,8 +127,9 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 127 | u128 user_id, u64 save_id) { | 127 | u128 user_id, u64 save_id) { |
| 128 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 128 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 129 | // be interpreted as the title id of the current process. | 129 | // be interpreted as the title id of the current process. |
| 130 | if (type == SaveDataType::SaveData && title_id == 0) | 130 | if (type == SaveDataType::SaveData && title_id == 0) { |
| 131 | title_id = Core::CurrentProcess()->GetTitleID(); | 131 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 132 | } | ||
| 132 | 133 | ||
| 133 | std::string out = GetSaveDataSpaceIdPath(space); | 134 | std::string out = GetSaveDataSpaceIdPath(space); |
| 134 | 135 | ||
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp new file mode 100644 index 000000000..8bdaa7e4a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.cpp | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | #include <zip.h> | ||
| 7 | #include "common/logging/backend.h" | ||
| 8 | #include "core/file_sys/vfs.h" | ||
| 9 | #include "core/file_sys/vfs_libzip.h" | ||
| 10 | #include "core/file_sys/vfs_vector.h" | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | VirtualDir ExtractZIP(VirtualFile file) { | ||
| 15 | zip_error_t error{}; | ||
| 16 | |||
| 17 | const auto data = file->ReadAllBytes(); | ||
| 18 | std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{ | ||
| 19 | zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close}; | ||
| 20 | if (src == nullptr) | ||
| 21 | return nullptr; | ||
| 22 | |||
| 23 | std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error), | ||
| 24 | zip_close}; | ||
| 25 | if (zip == nullptr) | ||
| 26 | return nullptr; | ||
| 27 | |||
| 28 | std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>(); | ||
| 29 | |||
| 30 | const auto num_entries = zip_get_num_entries(zip.get(), 0); | ||
| 31 | |||
| 32 | zip_stat_t stat{}; | ||
| 33 | zip_stat_init(&stat); | ||
| 34 | |||
| 35 | for (std::size_t i = 0; i < num_entries; ++i) { | ||
| 36 | const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat); | ||
| 37 | if (stat_res == -1) | ||
| 38 | return nullptr; | ||
| 39 | |||
| 40 | const std::string name(stat.name); | ||
| 41 | if (name.empty()) | ||
| 42 | continue; | ||
| 43 | |||
| 44 | if (name.back() != '/') { | ||
| 45 | std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file{ | ||
| 46 | zip_fopen_index(zip.get(), i, 0), zip_fclose}; | ||
| 47 | |||
| 48 | std::vector<u8> buf(stat.size); | ||
| 49 | if (zip_fread(file.get(), buf.data(), buf.size()) != buf.size()) | ||
| 50 | return nullptr; | ||
| 51 | |||
| 52 | const auto parts = FileUtil::SplitPathComponents(stat.name); | ||
| 53 | const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back()); | ||
| 54 | |||
| 55 | std::shared_ptr<VectorVfsDirectory> dtrv = out; | ||
| 56 | for (std::size_t j = 0; j < parts.size() - 1; ++j) { | ||
| 57 | if (dtrv == nullptr) | ||
| 58 | return nullptr; | ||
| 59 | const auto subdir = dtrv->GetSubdirectory(parts[j]); | ||
| 60 | if (subdir == nullptr) { | ||
| 61 | const auto temp = std::make_shared<VectorVfsDirectory>( | ||
| 62 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]); | ||
| 63 | dtrv->AddDirectory(temp); | ||
| 64 | dtrv = temp; | ||
| 65 | } else { | ||
| 66 | dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | if (dtrv == nullptr) | ||
| 71 | return nullptr; | ||
| 72 | dtrv->AddFile(new_file); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | return out; | ||
| 77 | } | ||
| 78 | |||
| 79 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/vfs_libzip.h b/src/core/file_sys/vfs_libzip.h new file mode 100644 index 000000000..f68af576a --- /dev/null +++ b/src/core/file_sys/vfs_libzip.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/file_sys/vfs_types.h" | ||
| 8 | |||
| 9 | namespace FileSys { | ||
| 10 | |||
| 11 | VirtualDir ExtractZIP(VirtualFile zip); | ||
| 12 | |||
| 13 | } // namespace FileSys | ||
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index afa812598..db51d722f 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -641,7 +641,8 @@ static void HandleQuery() { | |||
| 641 | strlen("Xfer:features:read:target.xml:")) == 0) { | 641 | strlen("Xfer:features:read:target.xml:")) == 0) { |
| 642 | SendReply(target_xml); | 642 | SendReply(target_xml); |
| 643 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { | 643 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { |
| 644 | const VAddr base_address = Core::CurrentProcess()->VMManager().GetCodeRegionBaseAddress(); | 644 | const VAddr base_address = |
| 645 | Core::System::GetInstance().CurrentProcess()->VMManager().GetCodeRegionBaseAddress(); | ||
| 645 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); | 646 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); |
| 646 | SendReply(buffer.c_str()); | 647 | SendReply(buffer.c_str()); |
| 647 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | 648 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { |
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index bdfaa977f..2cc5d536b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -103,7 +103,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { | |||
| 103 | if (handle == CurrentThread) { | 103 | if (handle == CurrentThread) { |
| 104 | return GetCurrentThread(); | 104 | return GetCurrentThread(); |
| 105 | } else if (handle == CurrentProcess) { | 105 | } else if (handle == CurrentProcess) { |
| 106 | return Core::CurrentProcess(); | 106 | return Core::System::GetInstance().CurrentProcess(); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | if (!IsValid(handle)) { | 109 | if (!IsValid(handle)) { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 797c9a06f..941ebc93a 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "core/hle/service/am/tcap.h" | 31 | #include "core/hle/service/am/tcap.h" |
| 32 | #include "core/hle/service/apm/controller.h" | 32 | #include "core/hle/service/apm/controller.h" |
| 33 | #include "core/hle/service/apm/interface.h" | 33 | #include "core/hle/service/apm/interface.h" |
| 34 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 34 | #include "core/hle/service/filesystem/filesystem.h" | 35 | #include "core/hle/service/filesystem/filesystem.h" |
| 35 | #include "core/hle/service/ns/ns.h" | 36 | #include "core/hle/service/ns/ns.h" |
| 36 | #include "core/hle/service/nvflinger/nvflinger.h" | 37 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -46,15 +47,20 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; | |||
| 46 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; | 47 | constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; |
| 47 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | 48 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; |
| 48 | 49 | ||
| 49 | constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; | 50 | enum class LaunchParameterKind : u32 { |
| 51 | ApplicationSpecific = 1, | ||
| 52 | AccountPreselectedUser = 2, | ||
| 53 | }; | ||
| 54 | |||
| 55 | constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; | ||
| 50 | 56 | ||
| 51 | struct LaunchParameters { | 57 | struct LaunchParameterAccountPreselectedUser { |
| 52 | u32_le magic; | 58 | u32_le magic; |
| 53 | u32_le is_account_selected; | 59 | u32_le is_account_selected; |
| 54 | u128 current_user; | 60 | u128 current_user; |
| 55 | INSERT_PADDING_BYTES(0x70); | 61 | INSERT_PADDING_BYTES(0x70); |
| 56 | }; | 62 | }; |
| 57 | static_assert(sizeof(LaunchParameters) == 0x88); | 63 | static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |
| 58 | 64 | ||
| 59 | IWindowController::IWindowController(Core::System& system_) | 65 | IWindowController::IWindowController(Core::System& system_) |
| 60 | : ServiceFramework("IWindowController"), system{system_} { | 66 | : ServiceFramework("IWindowController"), system{system_} { |
| @@ -1128,26 +1134,55 @@ void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx | |||
| 1128 | } | 1134 | } |
| 1129 | 1135 | ||
| 1130 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | 1136 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { |
| 1131 | LOG_DEBUG(Service_AM, "called"); | 1137 | IPC::RequestParser rp{ctx}; |
| 1138 | const auto kind = rp.PopEnum<LaunchParameterKind>(); | ||
| 1132 | 1139 | ||
| 1133 | LaunchParameters params{}; | 1140 | LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); |
| 1134 | 1141 | ||
| 1135 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; | 1142 | if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { |
| 1136 | params.is_account_selected = 1; | 1143 | const auto backend = BCAT::CreateBackendFromSettings( |
| 1144 | [this](u64 tid) { return system.GetFileSystemController().GetBCATDirectory(tid); }); | ||
| 1145 | const auto build_id_full = system.GetCurrentProcessBuildID(); | ||
| 1146 | u64 build_id{}; | ||
| 1147 | std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); | ||
| 1137 | 1148 | ||
| 1138 | Account::ProfileManager profile_manager{}; | 1149 | const auto data = |
| 1139 | const auto uuid = profile_manager.GetUser(Settings::values.current_user); | 1150 | backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); |
| 1140 | ASSERT(uuid); | ||
| 1141 | params.current_user = uuid->uuid; | ||
| 1142 | 1151 | ||
| 1143 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1152 | if (data.has_value()) { |
| 1153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1154 | rb.Push(RESULT_SUCCESS); | ||
| 1155 | rb.PushIpcInterface<AM::IStorage>(*data); | ||
| 1156 | launch_popped_application_specific = true; | ||
| 1157 | return; | ||
| 1158 | } | ||
| 1159 | } else if (kind == LaunchParameterKind::AccountPreselectedUser && | ||
| 1160 | !launch_popped_account_preselect) { | ||
| 1161 | LaunchParameterAccountPreselectedUser params{}; | ||
| 1144 | 1162 | ||
| 1145 | rb.Push(RESULT_SUCCESS); | 1163 | params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; |
| 1164 | params.is_account_selected = 1; | ||
| 1146 | 1165 | ||
| 1147 | std::vector<u8> buffer(sizeof(LaunchParameters)); | 1166 | Account::ProfileManager profile_manager{}; |
| 1148 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 1167 | const auto uuid = profile_manager.GetUser(Settings::values.current_user); |
| 1168 | ASSERT(uuid); | ||
| 1169 | params.current_user = uuid->uuid; | ||
| 1149 | 1170 | ||
| 1150 | rb.PushIpcInterface<AM::IStorage>(buffer); | 1171 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1172 | |||
| 1173 | rb.Push(RESULT_SUCCESS); | ||
| 1174 | |||
| 1175 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | ||
| 1176 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | ||
| 1177 | |||
| 1178 | rb.PushIpcInterface<AM::IStorage>(buffer); | ||
| 1179 | launch_popped_account_preselect = true; | ||
| 1180 | return; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); | ||
| 1184 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1185 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 1151 | } | 1186 | } |
| 1152 | 1187 | ||
| 1153 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( | 1188 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( |
| @@ -1165,7 +1200,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | |||
| 1165 | LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); | 1200 | LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); |
| 1166 | 1201 | ||
| 1167 | FileSys::SaveDataDescriptor descriptor{}; | 1202 | FileSys::SaveDataDescriptor descriptor{}; |
| 1168 | descriptor.title_id = Core::CurrentProcess()->GetTitleID(); | 1203 | descriptor.title_id = system.CurrentProcess()->GetTitleID(); |
| 1169 | descriptor.user_id = user_id; | 1204 | descriptor.user_id = user_id; |
| 1170 | descriptor.type = FileSys::SaveDataType::SaveData; | 1205 | descriptor.type = FileSys::SaveDataType::SaveData; |
| 1171 | const auto res = system.GetFileSystemController().CreateSaveData( | 1206 | const auto res = system.GetFileSystemController().CreateSaveData( |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index a3baeb673..ccd053c13 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -147,6 +147,7 @@ private: | |||
| 147 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); | 147 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); |
| 148 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); | 148 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); |
| 149 | 149 | ||
| 150 | Core::System& system; | ||
| 150 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 151 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 151 | Kernel::EventPair launchable_event; | 152 | Kernel::EventPair launchable_event; |
| 152 | Kernel::EventPair accumulated_suspended_tick_changed_event; | 153 | Kernel::EventPair accumulated_suspended_tick_changed_event; |
| @@ -154,8 +155,6 @@ private: | |||
| 154 | u32 idle_time_detection_extension = 0; | 155 | u32 idle_time_detection_extension = 0; |
| 155 | u64 num_fatal_sections_entered = 0; | 156 | u64 num_fatal_sections_entered = 0; |
| 156 | bool is_auto_sleep_disabled = false; | 157 | bool is_auto_sleep_disabled = false; |
| 157 | |||
| 158 | Core::System& system; | ||
| 159 | }; | 158 | }; |
| 160 | 159 | ||
| 161 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { | 160 | class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
| @@ -255,6 +254,8 @@ private: | |||
| 255 | void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); | 254 | void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); |
| 256 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 255 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 257 | 256 | ||
| 257 | bool launch_popped_application_specific = false; | ||
| 258 | bool launch_popped_account_preselect = false; | ||
| 258 | Kernel::EventPair gpu_error_detected_event; | 259 | Kernel::EventPair gpu_error_detected_event; |
| 259 | Core::System& system; | 260 | Core::System& system; |
| 260 | }; | 261 | }; |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index d2e35362f..720fe766f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -157,6 +157,10 @@ AppletManager::AppletManager(Core::System& system_) : system{system_} {} | |||
| 157 | 157 | ||
| 158 | AppletManager::~AppletManager() = default; | 158 | AppletManager::~AppletManager() = default; |
| 159 | 159 | ||
| 160 | const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { | ||
| 161 | return frontend; | ||
| 162 | } | ||
| 163 | |||
| 160 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | 164 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { |
| 161 | if (set.parental_controls != nullptr) | 165 | if (set.parental_controls != nullptr) |
| 162 | frontend.parental_controls = std::move(set.parental_controls); | 166 | frontend.parental_controls = std::move(set.parental_controls); |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 764c3418c..226be88b1 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -190,6 +190,8 @@ public: | |||
| 190 | explicit AppletManager(Core::System& system_); | 190 | explicit AppletManager(Core::System& system_); |
| 191 | ~AppletManager(); | 191 | ~AppletManager(); |
| 192 | 192 | ||
| 193 | const AppletFrontendSet& GetAppletFrontendSet() const; | ||
| 194 | |||
| 193 | void SetAppletFrontendSet(AppletFrontendSet set); | 195 | void SetAppletFrontendSet(AppletFrontendSet set); |
| 194 | void SetDefaultAppletFrontendSet(); | 196 | void SetDefaultAppletFrontendSet(); |
| 195 | void SetDefaultAppletsIfMissing(); | 197 | void SetDefaultAppletsIfMissing(); |
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp index 4376612eb..073d0f6fa 100644 --- a/src/core/hle/service/apm/controller.cpp +++ b/src/core/hle/service/apm/controller.cpp | |||
| @@ -13,7 +13,7 @@ constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION = | |||
| 13 | PerformanceConfiguration::Config7; | 13 | PerformanceConfiguration::Config7; |
| 14 | 14 | ||
| 15 | Controller::Controller(Core::Timing::CoreTiming& core_timing) | 15 | Controller::Controller(Core::Timing::CoreTiming& core_timing) |
| 16 | : core_timing(core_timing), configs{ | 16 | : core_timing{core_timing}, configs{ |
| 17 | {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, | 17 | {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, |
| 18 | {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, | 18 | {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, |
| 19 | } {} | 19 | } {} |
| @@ -63,6 +63,7 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa | |||
| 63 | void Controller::SetClockSpeed(u32 mhz) { | 63 | void Controller::SetClockSpeed(u32 mhz) { |
| 64 | LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); | 64 | LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); |
| 65 | // TODO(DarkLordZach): Actually signal core_timing to change clock speed. | 65 | // TODO(DarkLordZach): Actually signal core_timing to change clock speed. |
| 66 | // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. | ||
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | } // namespace Service::APM | 69 | } // namespace Service::APM |
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h index 8ac80eaea..454caa6eb 100644 --- a/src/core/hle/service/apm/controller.h +++ b/src/core/hle/service/apm/controller.h | |||
| @@ -50,7 +50,7 @@ enum class PerformanceMode : u8 { | |||
| 50 | // system during times of high load -- this simply maps to different PerformanceConfigs to use. | 50 | // system during times of high load -- this simply maps to different PerformanceConfigs to use. |
| 51 | class Controller { | 51 | class Controller { |
| 52 | public: | 52 | public: |
| 53 | Controller(Core::Timing::CoreTiming& core_timing); | 53 | explicit Controller(Core::Timing::CoreTiming& core_timing); |
| 54 | ~Controller(); | 54 | ~Controller(); |
| 55 | 55 | ||
| 56 | void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); | 56 | void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); |
| @@ -62,9 +62,9 @@ public: | |||
| 62 | private: | 62 | private: |
| 63 | void SetClockSpeed(u32 mhz); | 63 | void SetClockSpeed(u32 mhz); |
| 64 | 64 | ||
| 65 | std::map<PerformanceMode, PerformanceConfiguration> configs; | 65 | [[maybe_unused]] Core::Timing::CoreTiming& core_timing; |
| 66 | 66 | ||
| 67 | Core::Timing::CoreTiming& core_timing; | 67 | std::map<PerformanceMode, PerformanceConfiguration> configs; |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | } // namespace Service::APM | 70 | } // namespace Service::APM |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index fb84a8f13..9afefb5c6 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -205,7 +205,7 @@ private: | |||
| 205 | AudioCore::StreamPtr stream; | 205 | AudioCore::StreamPtr stream; |
| 206 | std::string device_name; | 206 | std::string device_name; |
| 207 | 207 | ||
| 208 | AudoutParams audio_params{}; | 208 | [[maybe_unused]] AudoutParams audio_params {}; |
| 209 | 209 | ||
| 210 | /// This is the event handle used to check if the audio buffer was released | 210 | /// This is the event handle used to check if the audio buffer was released |
| 211 | Kernel::EventPair buffer_event; | 211 | Kernel::EventPair buffer_event; |
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp new file mode 100644 index 000000000..9d6946bc5 --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.cpp | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/hex_util.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/hle/lock.h" | ||
| 9 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 10 | |||
| 11 | namespace Service::BCAT { | ||
| 12 | |||
| 13 | ProgressServiceBackend::ProgressServiceBackend(std::string_view event_name) { | ||
| 14 | auto& kernel{Core::System::GetInstance().Kernel()}; | ||
| 15 | event = Kernel::WritableEvent::CreateEventPair( | ||
| 16 | kernel, Kernel::ResetType::Automatic, | ||
| 17 | std::string("ProgressServiceBackend:UpdateEvent:").append(event_name)); | ||
| 18 | } | ||
| 19 | |||
| 20 | Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { | ||
| 21 | return event.readable; | ||
| 22 | } | ||
| 23 | |||
| 24 | DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { | ||
| 25 | return impl; | ||
| 26 | } | ||
| 27 | |||
| 28 | void ProgressServiceBackend::SetNeedHLELock(bool need) { | ||
| 29 | need_hle_lock = need; | ||
| 30 | } | ||
| 31 | |||
| 32 | void ProgressServiceBackend::SetTotalSize(u64 size) { | ||
| 33 | impl.total_bytes = size; | ||
| 34 | SignalUpdate(); | ||
| 35 | } | ||
| 36 | |||
| 37 | void ProgressServiceBackend::StartConnecting() { | ||
| 38 | impl.status = DeliveryCacheProgressImpl::Status::Connecting; | ||
| 39 | SignalUpdate(); | ||
| 40 | } | ||
| 41 | |||
| 42 | void ProgressServiceBackend::StartProcessingDataList() { | ||
| 43 | impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList; | ||
| 44 | SignalUpdate(); | ||
| 45 | } | ||
| 46 | |||
| 47 | void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name, | ||
| 48 | std::string_view file_name, u64 file_size) { | ||
| 49 | impl.status = DeliveryCacheProgressImpl::Status::Downloading; | ||
| 50 | impl.current_downloaded_bytes = 0; | ||
| 51 | impl.current_total_bytes = file_size; | ||
| 52 | std::memcpy(impl.current_directory.data(), dir_name.data(), | ||
| 53 | std::min<u64>(dir_name.size(), 0x31ull)); | ||
| 54 | std::memcpy(impl.current_file.data(), file_name.data(), | ||
| 55 | std::min<u64>(file_name.size(), 0x31ull)); | ||
| 56 | SignalUpdate(); | ||
| 57 | } | ||
| 58 | |||
| 59 | void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) { | ||
| 60 | impl.current_downloaded_bytes = downloaded; | ||
| 61 | SignalUpdate(); | ||
| 62 | } | ||
| 63 | |||
| 64 | void ProgressServiceBackend::FinishDownloadingFile() { | ||
| 65 | impl.total_downloaded_bytes += impl.current_total_bytes; | ||
| 66 | SignalUpdate(); | ||
| 67 | } | ||
| 68 | |||
| 69 | void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) { | ||
| 70 | impl.status = DeliveryCacheProgressImpl::Status::Committing; | ||
| 71 | impl.current_file.fill(0); | ||
| 72 | impl.current_downloaded_bytes = 0; | ||
| 73 | impl.current_total_bytes = 0; | ||
| 74 | std::memcpy(impl.current_directory.data(), dir_name.data(), | ||
| 75 | std::min<u64>(dir_name.size(), 0x31ull)); | ||
| 76 | SignalUpdate(); | ||
| 77 | } | ||
| 78 | |||
| 79 | void ProgressServiceBackend::FinishDownload(ResultCode result) { | ||
| 80 | impl.total_downloaded_bytes = impl.total_bytes; | ||
| 81 | impl.status = DeliveryCacheProgressImpl::Status::Done; | ||
| 82 | impl.result = result; | ||
| 83 | SignalUpdate(); | ||
| 84 | } | ||
| 85 | |||
| 86 | void ProgressServiceBackend::SignalUpdate() const { | ||
| 87 | if (need_hle_lock) { | ||
| 88 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 89 | event.writable->Signal(); | ||
| 90 | } else { | ||
| 91 | event.writable->Signal(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} | ||
| 96 | |||
| 97 | Backend::~Backend() = default; | ||
| 98 | |||
| 99 | NullBackend::NullBackend(DirectoryGetter getter) : Backend(std::move(getter)) {} | ||
| 100 | |||
| 101 | NullBackend::~NullBackend() = default; | ||
| 102 | |||
| 103 | bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { | ||
| 104 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, | ||
| 105 | title.build_id); | ||
| 106 | |||
| 107 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 108 | return true; | ||
| 109 | } | ||
| 110 | |||
| 111 | bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 112 | ProgressServiceBackend& progress) { | ||
| 113 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id, | ||
| 114 | title.build_id, name); | ||
| 115 | |||
| 116 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 117 | return true; | ||
| 118 | } | ||
| 119 | |||
| 120 | bool NullBackend::Clear(u64 title_id) { | ||
| 121 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}"); | ||
| 122 | |||
| 123 | return true; | ||
| 124 | } | ||
| 125 | |||
| 126 | void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { | ||
| 127 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id, | ||
| 128 | Common::HexToString(passphrase)); | ||
| 129 | } | ||
| 130 | |||
| 131 | std::optional<std::vector<u8>> NullBackend::GetLaunchParameter(TitleIDVersion title) { | ||
| 132 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id, | ||
| 133 | title.build_id); | ||
| 134 | return std::nullopt; | ||
| 135 | } | ||
| 136 | |||
| 137 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h new file mode 100644 index 000000000..51dbd3316 --- /dev/null +++ b/src/core/hle/service/bcat/backend/backend.h | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include <optional> | ||
| 9 | #include <string> | ||
| 10 | #include <string_view> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "core/file_sys/vfs_types.h" | ||
| 14 | #include "core/hle/kernel/readable_event.h" | ||
| 15 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | |||
| 18 | namespace Service::BCAT { | ||
| 19 | |||
| 20 | struct DeliveryCacheProgressImpl; | ||
| 21 | |||
| 22 | using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>; | ||
| 23 | using Passphrase = std::array<u8, 0x20>; | ||
| 24 | |||
| 25 | struct TitleIDVersion { | ||
| 26 | u64 title_id; | ||
| 27 | u64 build_id; | ||
| 28 | }; | ||
| 29 | |||
| 30 | using DirectoryName = std::array<char, 0x20>; | ||
| 31 | using FileName = std::array<char, 0x20>; | ||
| 32 | |||
| 33 | struct DeliveryCacheProgressImpl { | ||
| 34 | enum class Status : s32 { | ||
| 35 | None = 0x0, | ||
| 36 | Queued = 0x1, | ||
| 37 | Connecting = 0x2, | ||
| 38 | ProcessingDataList = 0x3, | ||
| 39 | Downloading = 0x4, | ||
| 40 | Committing = 0x5, | ||
| 41 | Done = 0x9, | ||
| 42 | }; | ||
| 43 | |||
| 44 | Status status; | ||
| 45 | ResultCode result = RESULT_SUCCESS; | ||
| 46 | DirectoryName current_directory; | ||
| 47 | FileName current_file; | ||
| 48 | s64 current_downloaded_bytes; ///< Bytes downloaded on current file. | ||
| 49 | s64 current_total_bytes; ///< Bytes total on current file. | ||
| 50 | s64 total_downloaded_bytes; ///< Bytes downloaded on overall download. | ||
| 51 | s64 total_bytes; ///< Bytes total on overall download. | ||
| 52 | INSERT_PADDING_BYTES( | ||
| 53 | 0x198); ///< Appears to be unused in official code, possibly reserved for future use. | ||
| 54 | }; | ||
| 55 | static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200, | ||
| 56 | "DeliveryCacheProgressImpl has incorrect size."); | ||
| 57 | |||
| 58 | // A class to manage the signalling to the game about BCAT download progress. | ||
| 59 | // Some of this class is implemented in module.cpp to avoid exposing the implementation structure. | ||
| 60 | class ProgressServiceBackend { | ||
| 61 | friend class IBcatService; | ||
| 62 | |||
| 63 | public: | ||
| 64 | // Clients should call this with true if any of the functions are going to be called from a | ||
| 65 | // non-HLE thread and this class need to lock the hle mutex. (default is false) | ||
| 66 | void SetNeedHLELock(bool need); | ||
| 67 | |||
| 68 | // Sets the number of bytes total in the entire download. | ||
| 69 | void SetTotalSize(u64 size); | ||
| 70 | |||
| 71 | // Notifies the application that the backend has started connecting to the server. | ||
| 72 | void StartConnecting(); | ||
| 73 | // Notifies the application that the backend has begun accumulating and processing metadata. | ||
| 74 | void StartProcessingDataList(); | ||
| 75 | |||
| 76 | // Notifies the application that a file is starting to be downloaded. | ||
| 77 | void StartDownloadingFile(std::string_view dir_name, std::string_view file_name, u64 file_size); | ||
| 78 | // Updates the progress of the current file to the size passed. | ||
| 79 | void UpdateFileProgress(u64 downloaded); | ||
| 80 | // Notifies the application that the current file has completed download. | ||
| 81 | void FinishDownloadingFile(); | ||
| 82 | |||
| 83 | // Notifies the application that all files in this directory have completed and are being | ||
| 84 | // finalized. | ||
| 85 | void CommitDirectory(std::string_view dir_name); | ||
| 86 | |||
| 87 | // Notifies the application that the operation completed with result code result. | ||
| 88 | void FinishDownload(ResultCode result); | ||
| 89 | |||
| 90 | private: | ||
| 91 | explicit ProgressServiceBackend(std::string_view event_name); | ||
| 92 | |||
| 93 | Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const; | ||
| 94 | DeliveryCacheProgressImpl& GetImpl(); | ||
| 95 | |||
| 96 | void SignalUpdate() const; | ||
| 97 | |||
| 98 | DeliveryCacheProgressImpl impl{}; | ||
| 99 | Kernel::EventPair event; | ||
| 100 | bool need_hle_lock = false; | ||
| 101 | }; | ||
| 102 | |||
| 103 | // A class representing an abstract backend for BCAT functionality. | ||
| 104 | class Backend { | ||
| 105 | public: | ||
| 106 | explicit Backend(DirectoryGetter getter); | ||
| 107 | virtual ~Backend(); | ||
| 108 | |||
| 109 | // Called when the backend is needed to synchronize the data for the game with title ID and | ||
| 110 | // version in title. A ProgressServiceBackend object is provided to alert the application of | ||
| 111 | // status. | ||
| 112 | virtual bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) = 0; | ||
| 113 | // Very similar to Synchronize, but only for the directory provided. Backends should not alter | ||
| 114 | // the data for any other directories. | ||
| 115 | virtual bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 116 | ProgressServiceBackend& progress) = 0; | ||
| 117 | |||
| 118 | // Removes all cached data associated with title id provided. | ||
| 119 | virtual bool Clear(u64 title_id) = 0; | ||
| 120 | |||
| 121 | // Sets the BCAT Passphrase to be used with the associated title ID. | ||
| 122 | virtual void SetPassphrase(u64 title_id, const Passphrase& passphrase) = 0; | ||
| 123 | |||
| 124 | // Gets the launch parameter used by AM associated with the title ID and version provided. | ||
| 125 | virtual std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) = 0; | ||
| 126 | |||
| 127 | protected: | ||
| 128 | DirectoryGetter dir_getter; | ||
| 129 | }; | ||
| 130 | |||
| 131 | // A backend of BCAT that provides no operation. | ||
| 132 | class NullBackend : public Backend { | ||
| 133 | public: | ||
| 134 | explicit NullBackend(DirectoryGetter getter); | ||
| 135 | ~NullBackend() override; | ||
| 136 | |||
| 137 | bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; | ||
| 138 | bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 139 | ProgressServiceBackend& progress) override; | ||
| 140 | |||
| 141 | bool Clear(u64 title_id) override; | ||
| 142 | |||
| 143 | void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; | ||
| 144 | |||
| 145 | std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; | ||
| 146 | }; | ||
| 147 | |||
| 148 | std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter); | ||
| 149 | |||
| 150 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp new file mode 100644 index 000000000..64022982b --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.cpp | |||
| @@ -0,0 +1,504 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <fmt/ostream.h> | ||
| 6 | #include <httplib.h> | ||
| 7 | #include <json.hpp> | ||
| 8 | #include <mbedtls/sha256.h> | ||
| 9 | #include "common/hex_util.h" | ||
| 10 | #include "common/logging/backend.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/file_sys/vfs.h" | ||
| 14 | #include "core/file_sys/vfs_libzip.h" | ||
| 15 | #include "core/file_sys/vfs_vector.h" | ||
| 16 | #include "core/frontend/applets/error.h" | ||
| 17 | #include "core/hle/service/am/applets/applets.h" | ||
| 18 | #include "core/hle/service/bcat/backend/boxcat.h" | ||
| 19 | #include "core/settings.h" | ||
| 20 | |||
| 21 | namespace { | ||
| 22 | |||
| 23 | // Prevents conflicts with windows macro called CreateFile | ||
| 24 | FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) { | ||
| 25 | return dir->CreateFile(name); | ||
| 26 | } | ||
| 27 | |||
| 28 | // Prevents conflicts with windows macro called DeleteFile | ||
| 29 | bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) { | ||
| 30 | return dir->DeleteFile(name); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // Anonymous namespace | ||
| 34 | |||
| 35 | namespace Service::BCAT { | ||
| 36 | |||
| 37 | constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1}; | ||
| 38 | |||
| 39 | constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org"; | ||
| 40 | |||
| 41 | // Formatted using fmt with arg[0] = hex title id | ||
| 42 | constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat"; | ||
| 43 | constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam"; | ||
| 44 | |||
| 45 | constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events"; | ||
| 46 | |||
| 47 | constexpr char BOXCAT_API_VERSION[] = "1"; | ||
| 48 | constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu"; | ||
| 49 | |||
| 50 | // HTTP status codes for Boxcat | ||
| 51 | enum class ResponseStatus { | ||
| 52 | Ok = 200, ///< Operation completed successfully. | ||
| 53 | BadClientVersion = 301, ///< The Boxcat-Client-Version doesn't match the server. | ||
| 54 | NoUpdate = 304, ///< The digest provided would match the new data, no need to update. | ||
| 55 | NoMatchTitleId = 404, ///< The title ID provided doesn't have a boxcat implementation. | ||
| 56 | NoMatchBuildId = 406, ///< The build ID provided is blacklisted (potentially because of format | ||
| 57 | ///< issues or whatnot) and has no data. | ||
| 58 | }; | ||
| 59 | |||
| 60 | enum class DownloadResult { | ||
| 61 | Success = 0, | ||
| 62 | NoResponse, | ||
| 63 | GeneralWebError, | ||
| 64 | NoMatchTitleId, | ||
| 65 | NoMatchBuildId, | ||
| 66 | InvalidContentType, | ||
| 67 | GeneralFSError, | ||
| 68 | BadClientVersion, | ||
| 69 | }; | ||
| 70 | |||
| 71 | constexpr std::array<const char*, 8> DOWNLOAD_RESULT_LOG_MESSAGES{ | ||
| 72 | "Success", | ||
| 73 | "There was no response from the server.", | ||
| 74 | "There was a general web error code returned from the server.", | ||
| 75 | "The title ID of the current game doesn't have a boxcat implementation. If you believe an " | ||
| 76 | "implementation should be added, contact yuzu support.", | ||
| 77 | "The build ID of the current version of the game is marked as incompatible with the current " | ||
| 78 | "BCAT distribution. Try upgrading or downgrading your game version or contacting yuzu support.", | ||
| 79 | "The content type of the web response was invalid.", | ||
| 80 | "There was a general filesystem error while saving the zip file.", | ||
| 81 | "The server is either too new or too old to serve the request. Try using the latest version of " | ||
| 82 | "an official release of yuzu.", | ||
| 83 | }; | ||
| 84 | |||
| 85 | std::ostream& operator<<(std::ostream& os, DownloadResult result) { | ||
| 86 | return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result)); | ||
| 87 | } | ||
| 88 | |||
| 89 | constexpr u32 PORT = 443; | ||
| 90 | constexpr u32 TIMEOUT_SECONDS = 30; | ||
| 91 | [[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB | ||
| 92 | |||
| 93 | namespace { | ||
| 94 | |||
| 95 | std::string GetBINFilePath(u64 title_id) { | ||
| 96 | return fmt::format("{}bcat/{:016X}/launchparam.bin", | ||
| 97 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); | ||
| 98 | } | ||
| 99 | |||
| 100 | std::string GetZIPFilePath(u64 title_id) { | ||
| 101 | return fmt::format("{}bcat/{:016X}/data.zip", | ||
| 102 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); | ||
| 103 | } | ||
| 104 | |||
| 105 | // If the error is something the user should know about (build ID mismatch, bad client version), | ||
| 106 | // display an error. | ||
| 107 | void HandleDownloadDisplayResult(DownloadResult res) { | ||
| 108 | if (res == DownloadResult::Success || res == DownloadResult::NoResponse || | ||
| 109 | res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError || | ||
| 110 | res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) { | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | const auto& frontend{Core::System::GetInstance().GetAppletManager().GetAppletFrontendSet()}; | ||
| 115 | frontend.error->ShowCustomErrorText( | ||
| 116 | ResultCode(-1), "There was an error while attempting to use Boxcat.", | ||
| 117 | DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {}); | ||
| 118 | } | ||
| 119 | |||
| 120 | bool VfsRawCopyProgress(FileSys::VirtualFile src, FileSys::VirtualFile dest, | ||
| 121 | std::string_view dir_name, ProgressServiceBackend& progress, | ||
| 122 | std::size_t block_size = 0x1000) { | ||
| 123 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 124 | return false; | ||
| 125 | if (!dest->Resize(src->GetSize())) | ||
| 126 | return false; | ||
| 127 | |||
| 128 | progress.StartDownloadingFile(dir_name, src->GetName(), src->GetSize()); | ||
| 129 | |||
| 130 | std::vector<u8> temp(std::min(block_size, src->GetSize())); | ||
| 131 | for (std::size_t i = 0; i < src->GetSize(); i += block_size) { | ||
| 132 | const auto read = std::min(block_size, src->GetSize() - i); | ||
| 133 | |||
| 134 | if (src->Read(temp.data(), read, i) != read) { | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (dest->Write(temp.data(), read, i) != read) { | ||
| 139 | return false; | ||
| 140 | } | ||
| 141 | |||
| 142 | progress.UpdateFileProgress(i); | ||
| 143 | } | ||
| 144 | |||
| 145 | progress.FinishDownloadingFile(); | ||
| 146 | |||
| 147 | return true; | ||
| 148 | } | ||
| 149 | |||
| 150 | bool VfsRawCopyDProgressSingle(FileSys::VirtualDir src, FileSys::VirtualDir dest, | ||
| 151 | ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { | ||
| 152 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 153 | return false; | ||
| 154 | |||
| 155 | for (const auto& file : src->GetFiles()) { | ||
| 156 | const auto out_file = VfsCreateFileWrap(dest, file->GetName()); | ||
| 157 | if (!VfsRawCopyProgress(file, out_file, src->GetName(), progress, block_size)) { | ||
| 158 | return false; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | progress.CommitDirectory(src->GetName()); | ||
| 162 | |||
| 163 | return true; | ||
| 164 | } | ||
| 165 | |||
| 166 | bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest, | ||
| 167 | ProgressServiceBackend& progress, std::size_t block_size = 0x1000) { | ||
| 168 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 169 | return false; | ||
| 170 | |||
| 171 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 172 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 173 | if (!VfsRawCopyDProgressSingle(dir, out, progress, block_size)) { | ||
| 174 | return false; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | return true; | ||
| 179 | } | ||
| 180 | |||
| 181 | } // Anonymous namespace | ||
| 182 | |||
| 183 | class Boxcat::Client { | ||
| 184 | public: | ||
| 185 | Client(std::string path, u64 title_id, u64 build_id) | ||
| 186 | : path(std::move(path)), title_id(title_id), build_id(build_id) {} | ||
| 187 | |||
| 188 | DownloadResult DownloadDataZip() { | ||
| 189 | return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS, | ||
| 190 | "application/zip"); | ||
| 191 | } | ||
| 192 | |||
| 193 | DownloadResult DownloadLaunchParam() { | ||
| 194 | return DownloadInternal(fmt::format(BOXCAT_PATHNAME_LAUNCHPARAM, title_id), | ||
| 195 | TIMEOUT_SECONDS / 3, "application/octet-stream"); | ||
| 196 | } | ||
| 197 | |||
| 198 | private: | ||
| 199 | DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds, | ||
| 200 | const std::string& content_type_name) { | ||
| 201 | if (client == nullptr) { | ||
| 202 | client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT, timeout_seconds); | ||
| 203 | } | ||
| 204 | |||
| 205 | httplib::Headers headers{ | ||
| 206 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, | ||
| 207 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, | ||
| 208 | {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)}, | ||
| 209 | }; | ||
| 210 | |||
| 211 | if (FileUtil::Exists(path)) { | ||
| 212 | FileUtil::IOFile file{path, "rb"}; | ||
| 213 | if (file.IsOpen()) { | ||
| 214 | std::vector<u8> bytes(file.GetSize()); | ||
| 215 | file.ReadBytes(bytes.data(), bytes.size()); | ||
| 216 | const auto digest = DigestFile(bytes); | ||
| 217 | headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)}); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | const auto response = client->Get(resolved_path.c_str(), headers); | ||
| 222 | if (response == nullptr) | ||
| 223 | return DownloadResult::NoResponse; | ||
| 224 | |||
| 225 | if (response->status == static_cast<int>(ResponseStatus::NoUpdate)) | ||
| 226 | return DownloadResult::Success; | ||
| 227 | if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) | ||
| 228 | return DownloadResult::BadClientVersion; | ||
| 229 | if (response->status == static_cast<int>(ResponseStatus::NoMatchTitleId)) | ||
| 230 | return DownloadResult::NoMatchTitleId; | ||
| 231 | if (response->status == static_cast<int>(ResponseStatus::NoMatchBuildId)) | ||
| 232 | return DownloadResult::NoMatchBuildId; | ||
| 233 | if (response->status != static_cast<int>(ResponseStatus::Ok)) | ||
| 234 | return DownloadResult::GeneralWebError; | ||
| 235 | |||
| 236 | const auto content_type = response->headers.find("content-type"); | ||
| 237 | if (content_type == response->headers.end() || | ||
| 238 | content_type->second.find(content_type_name) == std::string::npos) { | ||
| 239 | return DownloadResult::InvalidContentType; | ||
| 240 | } | ||
| 241 | |||
| 242 | FileUtil::CreateFullPath(path); | ||
| 243 | FileUtil::IOFile file{path, "wb"}; | ||
| 244 | if (!file.IsOpen()) | ||
| 245 | return DownloadResult::GeneralFSError; | ||
| 246 | if (!file.Resize(response->body.size())) | ||
| 247 | return DownloadResult::GeneralFSError; | ||
| 248 | if (file.WriteBytes(response->body.data(), response->body.size()) != response->body.size()) | ||
| 249 | return DownloadResult::GeneralFSError; | ||
| 250 | |||
| 251 | return DownloadResult::Success; | ||
| 252 | } | ||
| 253 | |||
| 254 | using Digest = std::array<u8, 0x20>; | ||
| 255 | static Digest DigestFile(std::vector<u8> bytes) { | ||
| 256 | Digest out{}; | ||
| 257 | mbedtls_sha256(bytes.data(), bytes.size(), out.data(), 0); | ||
| 258 | return out; | ||
| 259 | } | ||
| 260 | |||
| 261 | std::unique_ptr<httplib::Client> client; | ||
| 262 | std::string path; | ||
| 263 | u64 title_id; | ||
| 264 | u64 build_id; | ||
| 265 | }; | ||
| 266 | |||
| 267 | Boxcat::Boxcat(DirectoryGetter getter) : Backend(std::move(getter)) {} | ||
| 268 | |||
| 269 | Boxcat::~Boxcat() = default; | ||
| 270 | |||
| 271 | void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, | ||
| 272 | ProgressServiceBackend& progress, | ||
| 273 | std::optional<std::string> dir_name = {}) { | ||
| 274 | progress.SetNeedHLELock(true); | ||
| 275 | |||
| 276 | if (Settings::values.bcat_boxcat_local) { | ||
| 277 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); | ||
| 278 | const auto dir = dir_getter(title.title_id); | ||
| 279 | if (dir) | ||
| 280 | progress.SetTotalSize(dir->GetSize()); | ||
| 281 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 282 | return; | ||
| 283 | } | ||
| 284 | |||
| 285 | const auto zip_path{GetZIPFilePath(title.title_id)}; | ||
| 286 | Boxcat::Client client{zip_path, title.title_id, title.build_id}; | ||
| 287 | |||
| 288 | progress.StartConnecting(); | ||
| 289 | |||
| 290 | const auto res = client.DownloadDataZip(); | ||
| 291 | if (res != DownloadResult::Success) { | ||
| 292 | LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); | ||
| 293 | |||
| 294 | if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { | ||
| 295 | FileUtil::Delete(zip_path); | ||
| 296 | } | ||
| 297 | |||
| 298 | HandleDownloadDisplayResult(res); | ||
| 299 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 300 | return; | ||
| 301 | } | ||
| 302 | |||
| 303 | progress.StartProcessingDataList(); | ||
| 304 | |||
| 305 | FileUtil::IOFile zip{zip_path, "rb"}; | ||
| 306 | const auto size = zip.GetSize(); | ||
| 307 | std::vector<u8> bytes(size); | ||
| 308 | if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { | ||
| 309 | LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", zip_path); | ||
| 310 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | const auto extracted = FileSys::ExtractZIP(std::make_shared<FileSys::VectorVfsFile>(bytes)); | ||
| 315 | if (extracted == nullptr) { | ||
| 316 | LOG_ERROR(Service_BCAT, "Boxcat failed to extract ZIP file!"); | ||
| 317 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (dir_name == std::nullopt) { | ||
| 322 | progress.SetTotalSize(extracted->GetSize()); | ||
| 323 | |||
| 324 | const auto target_dir = dir_getter(title.title_id); | ||
| 325 | if (target_dir == nullptr || !VfsRawCopyDProgress(extracted, target_dir, progress)) { | ||
| 326 | LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); | ||
| 327 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | } else { | ||
| 331 | const auto target_dir = dir_getter(title.title_id); | ||
| 332 | if (target_dir == nullptr) { | ||
| 333 | LOG_ERROR(Service_BCAT, "Boxcat failed to get directory for title ID!"); | ||
| 334 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | |||
| 338 | const auto target_sub = target_dir->GetSubdirectory(*dir_name); | ||
| 339 | const auto source_sub = extracted->GetSubdirectory(*dir_name); | ||
| 340 | |||
| 341 | progress.SetTotalSize(source_sub->GetSize()); | ||
| 342 | |||
| 343 | std::vector<std::string> filenames; | ||
| 344 | { | ||
| 345 | const auto files = target_sub->GetFiles(); | ||
| 346 | std::transform(files.begin(), files.end(), std::back_inserter(filenames), | ||
| 347 | [](const auto& vfile) { return vfile->GetName(); }); | ||
| 348 | } | ||
| 349 | |||
| 350 | for (const auto& filename : filenames) { | ||
| 351 | VfsDeleteFileWrap(target_sub, filename); | ||
| 352 | } | ||
| 353 | |||
| 354 | if (target_sub == nullptr || source_sub == nullptr || | ||
| 355 | !VfsRawCopyDProgressSingle(source_sub, target_sub, progress)) { | ||
| 356 | LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!"); | ||
| 357 | progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); | ||
| 358 | return; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | progress.FinishDownload(RESULT_SUCCESS); | ||
| 363 | } | ||
| 364 | |||
| 365 | bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { | ||
| 366 | is_syncing.exchange(true); | ||
| 367 | std::thread([this, title, &progress] { SynchronizeInternal(dir_getter, title, progress); }) | ||
| 368 | .detach(); | ||
| 369 | return true; | ||
| 370 | } | ||
| 371 | |||
| 372 | bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 373 | ProgressServiceBackend& progress) { | ||
| 374 | is_syncing.exchange(true); | ||
| 375 | std::thread( | ||
| 376 | [this, title, name, &progress] { SynchronizeInternal(dir_getter, title, progress, name); }) | ||
| 377 | .detach(); | ||
| 378 | return true; | ||
| 379 | } | ||
| 380 | |||
| 381 | bool Boxcat::Clear(u64 title_id) { | ||
| 382 | if (Settings::values.bcat_boxcat_local) { | ||
| 383 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping clear."); | ||
| 384 | return true; | ||
| 385 | } | ||
| 386 | |||
| 387 | const auto dir = dir_getter(title_id); | ||
| 388 | |||
| 389 | std::vector<std::string> dirnames; | ||
| 390 | |||
| 391 | for (const auto& subdir : dir->GetSubdirectories()) | ||
| 392 | dirnames.push_back(subdir->GetName()); | ||
| 393 | |||
| 394 | for (const auto& subdir : dirnames) { | ||
| 395 | if (!dir->DeleteSubdirectoryRecursive(subdir)) | ||
| 396 | return false; | ||
| 397 | } | ||
| 398 | |||
| 399 | return true; | ||
| 400 | } | ||
| 401 | |||
| 402 | void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) { | ||
| 403 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, | ||
| 404 | Common::HexToString(passphrase)); | ||
| 405 | } | ||
| 406 | |||
| 407 | std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) { | ||
| 408 | const auto path{GetBINFilePath(title.title_id)}; | ||
| 409 | |||
| 410 | if (Settings::values.bcat_boxcat_local) { | ||
| 411 | LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); | ||
| 412 | } else { | ||
| 413 | Boxcat::Client client{path, title.title_id, title.build_id}; | ||
| 414 | |||
| 415 | const auto res = client.DownloadLaunchParam(); | ||
| 416 | if (res != DownloadResult::Success) { | ||
| 417 | LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); | ||
| 418 | |||
| 419 | if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { | ||
| 420 | FileUtil::Delete(path); | ||
| 421 | } | ||
| 422 | |||
| 423 | HandleDownloadDisplayResult(res); | ||
| 424 | return std::nullopt; | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | FileUtil::IOFile bin{path, "rb"}; | ||
| 429 | const auto size = bin.GetSize(); | ||
| 430 | std::vector<u8> bytes(size); | ||
| 431 | if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { | ||
| 432 | LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!", | ||
| 433 | path); | ||
| 434 | return std::nullopt; | ||
| 435 | } | ||
| 436 | |||
| 437 | return bytes; | ||
| 438 | } | ||
| 439 | |||
| 440 | Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, | ||
| 441 | std::map<std::string, EventStatus>& games) { | ||
| 442 | httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT), | ||
| 443 | static_cast<int>(TIMEOUT_SECONDS)}; | ||
| 444 | |||
| 445 | httplib::Headers headers{ | ||
| 446 | {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, | ||
| 447 | {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, | ||
| 448 | }; | ||
| 449 | |||
| 450 | const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); | ||
| 451 | if (response == nullptr) | ||
| 452 | return StatusResult::Offline; | ||
| 453 | |||
| 454 | if (response->status == static_cast<int>(ResponseStatus::BadClientVersion)) | ||
| 455 | return StatusResult::BadClientVersion; | ||
| 456 | |||
| 457 | try { | ||
| 458 | nlohmann::json json = nlohmann::json::parse(response->body); | ||
| 459 | |||
| 460 | if (!json["online"].get<bool>()) | ||
| 461 | return StatusResult::Offline; | ||
| 462 | |||
| 463 | if (json["global"].is_null()) | ||
| 464 | global = std::nullopt; | ||
| 465 | else | ||
| 466 | global = json["global"].get<std::string>(); | ||
| 467 | |||
| 468 | if (json["games"].is_array()) { | ||
| 469 | for (const auto object : json["games"]) { | ||
| 470 | if (object.is_object() && object.find("name") != object.end()) { | ||
| 471 | EventStatus detail{}; | ||
| 472 | if (object["header"].is_string()) { | ||
| 473 | detail.header = object["header"].get<std::string>(); | ||
| 474 | } else { | ||
| 475 | detail.header = std::nullopt; | ||
| 476 | } | ||
| 477 | |||
| 478 | if (object["footer"].is_string()) { | ||
| 479 | detail.footer = object["footer"].get<std::string>(); | ||
| 480 | } else { | ||
| 481 | detail.footer = std::nullopt; | ||
| 482 | } | ||
| 483 | |||
| 484 | if (object["events"].is_array()) { | ||
| 485 | for (const auto& event : object["events"]) { | ||
| 486 | if (!event.is_string()) | ||
| 487 | continue; | ||
| 488 | detail.events.push_back(event.get<std::string>()); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | games.insert_or_assign(object["name"], std::move(detail)); | ||
| 493 | } | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | return StatusResult::Success; | ||
| 498 | } catch (const nlohmann::json::parse_error& error) { | ||
| 499 | LOG_ERROR(Service_BCAT, "{}", error.what()); | ||
| 500 | return StatusResult::ParseError; | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h new file mode 100644 index 000000000..601151189 --- /dev/null +++ b/src/core/hle/service/bcat/backend/boxcat.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <map> | ||
| 9 | #include <optional> | ||
| 10 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 11 | |||
| 12 | namespace Service::BCAT { | ||
| 13 | |||
| 14 | struct EventStatus { | ||
| 15 | std::optional<std::string> header; | ||
| 16 | std::optional<std::string> footer; | ||
| 17 | std::vector<std::string> events; | ||
| 18 | }; | ||
| 19 | |||
| 20 | /// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and | ||
| 21 | /// doesn't require a switch or nintendo account. The content is controlled by the yuzu team. | ||
| 22 | class Boxcat final : public Backend { | ||
| 23 | friend void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, | ||
| 24 | ProgressServiceBackend& progress, | ||
| 25 | std::optional<std::string> dir_name); | ||
| 26 | |||
| 27 | public: | ||
| 28 | explicit Boxcat(DirectoryGetter getter); | ||
| 29 | ~Boxcat() override; | ||
| 30 | |||
| 31 | bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; | ||
| 32 | bool SynchronizeDirectory(TitleIDVersion title, std::string name, | ||
| 33 | ProgressServiceBackend& progress) override; | ||
| 34 | |||
| 35 | bool Clear(u64 title_id) override; | ||
| 36 | |||
| 37 | void SetPassphrase(u64 title_id, const Passphrase& passphrase) override; | ||
| 38 | |||
| 39 | std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; | ||
| 40 | |||
| 41 | enum class StatusResult { | ||
| 42 | Success, | ||
| 43 | Offline, | ||
| 44 | ParseError, | ||
| 45 | BadClientVersion, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static StatusResult GetStatus(std::optional<std::string>& global, | ||
| 49 | std::map<std::string, EventStatus>& games); | ||
| 50 | |||
| 51 | private: | ||
| 52 | std::atomic_bool is_syncing{false}; | ||
| 53 | |||
| 54 | class Client; | ||
| 55 | std::unique_ptr<Client> client; | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace Service::BCAT | ||
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 179aa4949..8bb2528c9 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp | |||
| @@ -6,11 +6,16 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::BCAT { | 7 | namespace Service::BCAT { |
| 8 | 8 | ||
| 9 | BCAT::BCAT(std::shared_ptr<Module> module, const char* name) | 9 | BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module, |
| 10 | : Module::Interface(std::move(module), name) { | 10 | FileSystem::FileSystemController& fsc, const char* name) |
| 11 | : Interface(system, std::move(module), fsc, name) { | ||
| 12 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | 13 | static const FunctionInfo functions[] = { |
| 12 | {0, &BCAT::CreateBcatService, "CreateBcatService"}, | 14 | {0, &BCAT::CreateBcatService, "CreateBcatService"}, |
| 15 | {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"}, | ||
| 16 | {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"}, | ||
| 13 | }; | 17 | }; |
| 18 | // clang-format on | ||
| 14 | RegisterHandlers(functions); | 19 | RegisterHandlers(functions); |
| 15 | } | 20 | } |
| 16 | 21 | ||
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index 802bd689a..6354465fc 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h | |||
| @@ -6,11 +6,16 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/bcat/module.h" | 7 | #include "core/hle/service/bcat/module.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::BCAT { | 13 | namespace Service::BCAT { |
| 10 | 14 | ||
| 11 | class BCAT final : public Module::Interface { | 15 | class BCAT final : public Module::Interface { |
| 12 | public: | 16 | public: |
| 13 | explicit BCAT(std::shared_ptr<Module> module, const char* name); | 17 | explicit BCAT(Core::System& system, std::shared_ptr<Module> module, |
| 18 | FileSystem::FileSystemController& fsc, const char* name); | ||
| 14 | ~BCAT() override; | 19 | ~BCAT() override; |
| 15 | }; | 20 | }; |
| 16 | 21 | ||
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index b7bd738fc..4e4aa758b 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -2,34 +2,257 @@ | |||
| 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 <cctype> | ||
| 6 | #include <mbedtls/md5.h> | ||
| 7 | #include "backend/boxcat.h" | ||
| 8 | #include "common/hex_util.h" | ||
| 5 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | ||
| 11 | #include "core/file_sys/vfs.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/process.h" | ||
| 14 | #include "core/hle/kernel/readable_event.h" | ||
| 15 | #include "core/hle/kernel/writable_event.h" | ||
| 16 | #include "core/hle/service/bcat/backend/backend.h" | ||
| 7 | #include "core/hle/service/bcat/bcat.h" | 17 | #include "core/hle/service/bcat/bcat.h" |
| 8 | #include "core/hle/service/bcat/module.h" | 18 | #include "core/hle/service/bcat/module.h" |
| 19 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 20 | #include "core/settings.h" | ||
| 9 | 21 | ||
| 10 | namespace Service::BCAT { | 22 | namespace Service::BCAT { |
| 11 | 23 | ||
| 24 | constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1}; | ||
| 25 | constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2}; | ||
| 26 | constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6}; | ||
| 27 | constexpr ResultCode ERROR_NO_OPEN_ENTITY{ErrorModule::BCAT, 7}; | ||
| 28 | |||
| 29 | // The command to clear the delivery cache just calls fs IFileSystem DeleteFile on all of the files | ||
| 30 | // and if any of them have a non-zero result it just forwards that result. This is the FS error code | ||
| 31 | // for permission denied, which is the closest approximation of this scenario. | ||
| 32 | constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400}; | ||
| 33 | |||
| 34 | using BCATDigest = std::array<u8, 0x10>; | ||
| 35 | |||
| 36 | namespace { | ||
| 37 | |||
| 38 | u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) { | ||
| 39 | u64 out{}; | ||
| 40 | std::memcpy(&out, id.data(), sizeof(u64)); | ||
| 41 | return out; | ||
| 42 | } | ||
| 43 | |||
| 44 | // The digest is only used to determine if a file is unique compared to others of the same name. | ||
| 45 | // Since the algorithm isn't ever checked in game, MD5 is safe. | ||
| 46 | BCATDigest DigestFile(const FileSys::VirtualFile& file) { | ||
| 47 | BCATDigest out{}; | ||
| 48 | const auto bytes = file->ReadAllBytes(); | ||
| 49 | mbedtls_md5(bytes.data(), bytes.size(), out.data()); | ||
| 50 | return out; | ||
| 51 | } | ||
| 52 | |||
| 53 | // For a name to be valid it must be non-empty, must have a null terminating character as the final | ||
| 54 | // char, can only contain numbers, letters, underscores and a hyphen if directory and a period if | ||
| 55 | // file. | ||
| 56 | bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x20> name, | ||
| 57 | char match_char) { | ||
| 58 | const auto null_chars = std::count(name.begin(), name.end(), 0); | ||
| 59 | const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) { | ||
| 60 | return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0'; | ||
| 61 | }); | ||
| 62 | if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') { | ||
| 63 | LOG_ERROR(Service_BCAT, "Name passed was invalid!"); | ||
| 64 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 65 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 69 | return true; | ||
| 70 | } | ||
| 71 | |||
| 72 | bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) { | ||
| 73 | return VerifyNameValidInternal(ctx, name, '-'); | ||
| 74 | } | ||
| 75 | |||
| 76 | bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) { | ||
| 77 | return VerifyNameValidInternal(ctx, name, '.'); | ||
| 78 | } | ||
| 79 | |||
| 80 | } // Anonymous namespace | ||
| 81 | |||
| 82 | struct DeliveryCacheDirectoryEntry { | ||
| 83 | FileName name; | ||
| 84 | u64 size; | ||
| 85 | BCATDigest digest; | ||
| 86 | }; | ||
| 87 | |||
| 88 | class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { | ||
| 89 | public: | ||
| 90 | IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event, | ||
| 91 | const DeliveryCacheProgressImpl& impl) | ||
| 92 | : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { | ||
| 93 | // clang-format off | ||
| 94 | static const FunctionInfo functions[] = { | ||
| 95 | {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, | ||
| 96 | {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"}, | ||
| 97 | }; | ||
| 98 | // clang-format on | ||
| 99 | |||
| 100 | RegisterHandlers(functions); | ||
| 101 | } | ||
| 102 | |||
| 103 | private: | ||
| 104 | void GetEvent(Kernel::HLERequestContext& ctx) { | ||
| 105 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 106 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 108 | rb.Push(RESULT_SUCCESS); | ||
| 109 | rb.PushCopyObjects(event); | ||
| 110 | } | ||
| 111 | |||
| 112 | void GetImpl(Kernel::HLERequestContext& ctx) { | ||
| 113 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 114 | |||
| 115 | ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl)); | ||
| 116 | |||
| 117 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 118 | rb.Push(RESULT_SUCCESS); | ||
| 119 | } | ||
| 120 | |||
| 121 | Kernel::SharedPtr<Kernel::ReadableEvent> event; | ||
| 122 | const DeliveryCacheProgressImpl& impl; | ||
| 123 | }; | ||
| 124 | |||
| 12 | class IBcatService final : public ServiceFramework<IBcatService> { | 125 | class IBcatService final : public ServiceFramework<IBcatService> { |
| 13 | public: | 126 | public: |
| 14 | IBcatService() : ServiceFramework("IBcatService") { | 127 | explicit IBcatService(Core::System& system_, Backend& backend_) |
| 128 | : ServiceFramework("IBcatService"), system{system_}, backend{backend_} { | ||
| 129 | // clang-format off | ||
| 15 | static const FunctionInfo functions[] = { | 130 | static const FunctionInfo functions[] = { |
| 16 | {10100, nullptr, "RequestSyncDeliveryCache"}, | 131 | {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, |
| 17 | {10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"}, | 132 | {10101, &IBcatService::RequestSyncDeliveryCacheWithDirectoryName, "RequestSyncDeliveryCacheWithDirectoryName"}, |
| 18 | {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, | 133 | {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, |
| 19 | {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, | 134 | {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, |
| 20 | {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, | 135 | {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, |
| 21 | {30100, nullptr, "SetPassphrase"}, | 136 | {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, |
| 22 | {30200, nullptr, "RegisterBackgroundDeliveryTask"}, | 137 | {30200, nullptr, "RegisterBackgroundDeliveryTask"}, |
| 23 | {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, | 138 | {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, |
| 24 | {30202, nullptr, "BlockDeliveryTask"}, | 139 | {30202, nullptr, "BlockDeliveryTask"}, |
| 25 | {30203, nullptr, "UnblockDeliveryTask"}, | 140 | {30203, nullptr, "UnblockDeliveryTask"}, |
| 26 | {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, | 141 | {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, |
| 27 | {90200, nullptr, "GetDeliveryList"}, | 142 | {90200, nullptr, "GetDeliveryList"}, |
| 28 | {90201, nullptr, "ClearDeliveryCacheStorage"}, | 143 | {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, |
| 29 | {90300, nullptr, "GetPushNotificationLog"}, | 144 | {90300, nullptr, "GetPushNotificationLog"}, |
| 30 | }; | 145 | }; |
| 146 | // clang-format on | ||
| 31 | RegisterHandlers(functions); | 147 | RegisterHandlers(functions); |
| 32 | } | 148 | } |
| 149 | |||
| 150 | private: | ||
| 151 | enum class SyncType { | ||
| 152 | Normal, | ||
| 153 | Directory, | ||
| 154 | Count, | ||
| 155 | }; | ||
| 156 | |||
| 157 | std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { | ||
| 158 | auto& backend{progress.at(static_cast<std::size_t>(type))}; | ||
| 159 | return std::make_shared<IDeliveryCacheProgressService>(backend.GetEvent(), | ||
| 160 | backend.GetImpl()); | ||
| 161 | } | ||
| 162 | |||
| 163 | void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { | ||
| 164 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 165 | |||
| 166 | backend.Synchronize({system.CurrentProcess()->GetTitleID(), | ||
| 167 | GetCurrentBuildID(system.GetCurrentProcessBuildID())}, | ||
| 168 | progress.at(static_cast<std::size_t>(SyncType::Normal))); | ||
| 169 | |||
| 170 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 171 | rb.Push(RESULT_SUCCESS); | ||
| 172 | rb.PushIpcInterface(CreateProgressService(SyncType::Normal)); | ||
| 173 | } | ||
| 174 | |||
| 175 | void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) { | ||
| 176 | IPC::RequestParser rp{ctx}; | ||
| 177 | const auto name_raw = rp.PopRaw<DirectoryName>(); | ||
| 178 | const auto name = | ||
| 179 | Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); | ||
| 180 | |||
| 181 | LOG_DEBUG(Service_BCAT, "called, name={}", name); | ||
| 182 | |||
| 183 | backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(), | ||
| 184 | GetCurrentBuildID(system.GetCurrentProcessBuildID())}, | ||
| 185 | name, | ||
| 186 | progress.at(static_cast<std::size_t>(SyncType::Directory))); | ||
| 187 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 189 | rb.Push(RESULT_SUCCESS); | ||
| 190 | rb.PushIpcInterface(CreateProgressService(SyncType::Directory)); | ||
| 191 | } | ||
| 192 | |||
| 193 | void SetPassphrase(Kernel::HLERequestContext& ctx) { | ||
| 194 | IPC::RequestParser rp{ctx}; | ||
| 195 | const auto title_id = rp.PopRaw<u64>(); | ||
| 196 | |||
| 197 | const auto passphrase_raw = ctx.ReadBuffer(); | ||
| 198 | |||
| 199 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id, | ||
| 200 | Common::HexToString(passphrase_raw)); | ||
| 201 | |||
| 202 | if (title_id == 0) { | ||
| 203 | LOG_ERROR(Service_BCAT, "Invalid title ID!"); | ||
| 204 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 205 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 206 | } | ||
| 207 | |||
| 208 | if (passphrase_raw.size() > 0x40) { | ||
| 209 | LOG_ERROR(Service_BCAT, "Passphrase too large!"); | ||
| 210 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 211 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 212 | return; | ||
| 213 | } | ||
| 214 | |||
| 215 | Passphrase passphrase{}; | ||
| 216 | std::memcpy(passphrase.data(), passphrase_raw.data(), | ||
| 217 | std::min(passphrase.size(), passphrase_raw.size())); | ||
| 218 | |||
| 219 | backend.SetPassphrase(title_id, passphrase); | ||
| 220 | |||
| 221 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 222 | rb.Push(RESULT_SUCCESS); | ||
| 223 | } | ||
| 224 | |||
| 225 | void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) { | ||
| 226 | IPC::RequestParser rp{ctx}; | ||
| 227 | const auto title_id = rp.PopRaw<u64>(); | ||
| 228 | |||
| 229 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); | ||
| 230 | |||
| 231 | if (title_id == 0) { | ||
| 232 | LOG_ERROR(Service_BCAT, "Invalid title ID!"); | ||
| 233 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 234 | rb.Push(ERROR_INVALID_ARGUMENT); | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (!backend.Clear(title_id)) { | ||
| 239 | LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!"); | ||
| 240 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 241 | rb.Push(ERROR_FAILED_CLEAR_CACHE); | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | |||
| 245 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 246 | rb.Push(RESULT_SUCCESS); | ||
| 247 | } | ||
| 248 | |||
| 249 | Core::System& system; | ||
| 250 | Backend& backend; | ||
| 251 | |||
| 252 | std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress{ | ||
| 253 | ProgressServiceBackend{"Normal"}, | ||
| 254 | ProgressServiceBackend{"Directory"}, | ||
| 255 | }; | ||
| 33 | }; | 256 | }; |
| 34 | 257 | ||
| 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | 258 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { |
| @@ -37,20 +260,332 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | |||
| 37 | 260 | ||
| 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 261 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 39 | rb.Push(RESULT_SUCCESS); | 262 | rb.Push(RESULT_SUCCESS); |
| 40 | rb.PushIpcInterface<IBcatService>(); | 263 | rb.PushIpcInterface<IBcatService>(system, *backend); |
| 264 | } | ||
| 265 | |||
| 266 | class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { | ||
| 267 | public: | ||
| 268 | IDeliveryCacheFileService(FileSys::VirtualDir root_) | ||
| 269 | : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { | ||
| 270 | // clang-format off | ||
| 271 | static const FunctionInfo functions[] = { | ||
| 272 | {0, &IDeliveryCacheFileService::Open, "Open"}, | ||
| 273 | {1, &IDeliveryCacheFileService::Read, "Read"}, | ||
| 274 | {2, &IDeliveryCacheFileService::GetSize, "GetSize"}, | ||
| 275 | {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"}, | ||
| 276 | }; | ||
| 277 | // clang-format on | ||
| 278 | |||
| 279 | RegisterHandlers(functions); | ||
| 280 | } | ||
| 281 | |||
| 282 | private: | ||
| 283 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 284 | IPC::RequestParser rp{ctx}; | ||
| 285 | const auto dir_name_raw = rp.PopRaw<DirectoryName>(); | ||
| 286 | const auto file_name_raw = rp.PopRaw<FileName>(); | ||
| 287 | |||
| 288 | const auto dir_name = | ||
| 289 | Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size()); | ||
| 290 | const auto file_name = | ||
| 291 | Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size()); | ||
| 292 | |||
| 293 | LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); | ||
| 294 | |||
| 295 | if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw)) | ||
| 296 | return; | ||
| 297 | |||
| 298 | if (current_file != nullptr) { | ||
| 299 | LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); | ||
| 300 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 301 | rb.Push(ERROR_ENTITY_ALREADY_OPEN); | ||
| 302 | return; | ||
| 303 | } | ||
| 304 | |||
| 305 | const auto dir = root->GetSubdirectory(dir_name); | ||
| 306 | |||
| 307 | if (dir == nullptr) { | ||
| 308 | LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name); | ||
| 309 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 310 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | current_file = dir->GetFile(file_name); | ||
| 315 | |||
| 316 | if (current_file == nullptr) { | ||
| 317 | LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name); | ||
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 319 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 320 | return; | ||
| 321 | } | ||
| 322 | |||
| 323 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 324 | rb.Push(RESULT_SUCCESS); | ||
| 325 | } | ||
| 326 | |||
| 327 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 328 | IPC::RequestParser rp{ctx}; | ||
| 329 | const auto offset{rp.PopRaw<u64>()}; | ||
| 330 | |||
| 331 | auto size = ctx.GetWriteBufferSize(); | ||
| 332 | |||
| 333 | LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size); | ||
| 334 | |||
| 335 | if (current_file == nullptr) { | ||
| 336 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 337 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 338 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 339 | } | ||
| 340 | |||
| 341 | size = std::min<u64>(current_file->GetSize() - offset, size); | ||
| 342 | const auto buffer = current_file->ReadBytes(size, offset); | ||
| 343 | ctx.WriteBuffer(buffer); | ||
| 344 | |||
| 345 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 346 | rb.Push(RESULT_SUCCESS); | ||
| 347 | rb.Push<u64>(buffer.size()); | ||
| 348 | } | ||
| 349 | |||
| 350 | void GetSize(Kernel::HLERequestContext& ctx) { | ||
| 351 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 352 | |||
| 353 | if (current_file == nullptr) { | ||
| 354 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 355 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 356 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 357 | } | ||
| 358 | |||
| 359 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 360 | rb.Push(RESULT_SUCCESS); | ||
| 361 | rb.Push<u64>(current_file->GetSize()); | ||
| 362 | } | ||
| 363 | |||
| 364 | void GetDigest(Kernel::HLERequestContext& ctx) { | ||
| 365 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 366 | |||
| 367 | if (current_file == nullptr) { | ||
| 368 | LOG_ERROR(Service_BCAT, "There is no file currently open!"); | ||
| 369 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 370 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 371 | } | ||
| 372 | |||
| 373 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 374 | rb.Push(RESULT_SUCCESS); | ||
| 375 | rb.PushRaw(DigestFile(current_file)); | ||
| 376 | } | ||
| 377 | |||
| 378 | FileSys::VirtualDir root; | ||
| 379 | FileSys::VirtualFile current_file; | ||
| 380 | }; | ||
| 381 | |||
| 382 | class IDeliveryCacheDirectoryService final | ||
| 383 | : public ServiceFramework<IDeliveryCacheDirectoryService> { | ||
| 384 | public: | ||
| 385 | IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) | ||
| 386 | : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { | ||
| 387 | // clang-format off | ||
| 388 | static const FunctionInfo functions[] = { | ||
| 389 | {0, &IDeliveryCacheDirectoryService::Open, "Open"}, | ||
| 390 | {1, &IDeliveryCacheDirectoryService::Read, "Read"}, | ||
| 391 | {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, | ||
| 392 | }; | ||
| 393 | // clang-format on | ||
| 394 | |||
| 395 | RegisterHandlers(functions); | ||
| 396 | } | ||
| 397 | |||
| 398 | private: | ||
| 399 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 400 | IPC::RequestParser rp{ctx}; | ||
| 401 | const auto name_raw = rp.PopRaw<DirectoryName>(); | ||
| 402 | const auto name = | ||
| 403 | Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); | ||
| 404 | |||
| 405 | LOG_DEBUG(Service_BCAT, "called, name={}", name); | ||
| 406 | |||
| 407 | if (!VerifyNameValidDir(ctx, name_raw)) | ||
| 408 | return; | ||
| 409 | |||
| 410 | if (current_dir != nullptr) { | ||
| 411 | LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); | ||
| 412 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 413 | rb.Push(ERROR_ENTITY_ALREADY_OPEN); | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 417 | current_dir = root->GetSubdirectory(name); | ||
| 418 | |||
| 419 | if (current_dir == nullptr) { | ||
| 420 | LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); | ||
| 421 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 422 | rb.Push(ERROR_FAILED_OPEN_ENTITY); | ||
| 423 | return; | ||
| 424 | } | ||
| 425 | |||
| 426 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 427 | rb.Push(RESULT_SUCCESS); | ||
| 428 | } | ||
| 429 | |||
| 430 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 431 | auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); | ||
| 432 | |||
| 433 | LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); | ||
| 434 | |||
| 435 | if (current_dir == nullptr) { | ||
| 436 | LOG_ERROR(Service_BCAT, "There is no open directory!"); | ||
| 437 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 438 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 439 | return; | ||
| 440 | } | ||
| 441 | |||
| 442 | const auto files = current_dir->GetFiles(); | ||
| 443 | write_size = std::min<u64>(write_size, files.size()); | ||
| 444 | std::vector<DeliveryCacheDirectoryEntry> entries(write_size); | ||
| 445 | std::transform( | ||
| 446 | files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { | ||
| 447 | FileName name{}; | ||
| 448 | std::memcpy(name.data(), file->GetName().data(), | ||
| 449 | std::min(file->GetName().size(), name.size())); | ||
| 450 | return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; | ||
| 451 | }); | ||
| 452 | |||
| 453 | ctx.WriteBuffer(entries); | ||
| 454 | |||
| 455 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 456 | rb.Push(RESULT_SUCCESS); | ||
| 457 | rb.Push(static_cast<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry))); | ||
| 458 | } | ||
| 459 | |||
| 460 | void GetCount(Kernel::HLERequestContext& ctx) { | ||
| 461 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 462 | |||
| 463 | if (current_dir == nullptr) { | ||
| 464 | LOG_ERROR(Service_BCAT, "There is no open directory!"); | ||
| 465 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 466 | rb.Push(ERROR_NO_OPEN_ENTITY); | ||
| 467 | return; | ||
| 468 | } | ||
| 469 | |||
| 470 | const auto files = current_dir->GetFiles(); | ||
| 471 | |||
| 472 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 473 | rb.Push(RESULT_SUCCESS); | ||
| 474 | rb.Push(static_cast<u32>(files.size())); | ||
| 475 | } | ||
| 476 | |||
| 477 | FileSys::VirtualDir root; | ||
| 478 | FileSys::VirtualDir current_dir; | ||
| 479 | }; | ||
| 480 | |||
| 481 | class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { | ||
| 482 | public: | ||
| 483 | IDeliveryCacheStorageService(FileSys::VirtualDir root_) | ||
| 484 | : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { | ||
| 485 | // clang-format off | ||
| 486 | static const FunctionInfo functions[] = { | ||
| 487 | {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, | ||
| 488 | {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"}, | ||
| 489 | {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"}, | ||
| 490 | }; | ||
| 491 | // clang-format on | ||
| 492 | |||
| 493 | RegisterHandlers(functions); | ||
| 494 | |||
| 495 | for (const auto& subdir : root->GetSubdirectories()) { | ||
| 496 | DirectoryName name{}; | ||
| 497 | std::memcpy(name.data(), subdir->GetName().data(), | ||
| 498 | std::min(sizeof(DirectoryName) - 1, subdir->GetName().size())); | ||
| 499 | entries.push_back(name); | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | private: | ||
| 504 | void CreateFileService(Kernel::HLERequestContext& ctx) { | ||
| 505 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 506 | |||
| 507 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 508 | rb.Push(RESULT_SUCCESS); | ||
| 509 | rb.PushIpcInterface<IDeliveryCacheFileService>(root); | ||
| 510 | } | ||
| 511 | |||
| 512 | void CreateDirectoryService(Kernel::HLERequestContext& ctx) { | ||
| 513 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 514 | |||
| 515 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 516 | rb.Push(RESULT_SUCCESS); | ||
| 517 | rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root); | ||
| 518 | } | ||
| 519 | |||
| 520 | void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { | ||
| 521 | auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); | ||
| 522 | |||
| 523 | LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); | ||
| 524 | |||
| 525 | size = std::min<u64>(size, entries.size() - next_read_index); | ||
| 526 | ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName)); | ||
| 527 | next_read_index += size; | ||
| 528 | |||
| 529 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 530 | rb.Push(RESULT_SUCCESS); | ||
| 531 | rb.Push(static_cast<u32>(size)); | ||
| 532 | } | ||
| 533 | |||
| 534 | FileSys::VirtualDir root; | ||
| 535 | std::vector<DirectoryName> entries; | ||
| 536 | u64 next_read_index = 0; | ||
| 537 | }; | ||
| 538 | |||
| 539 | void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { | ||
| 540 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 541 | |||
| 542 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 543 | rb.Push(RESULT_SUCCESS); | ||
| 544 | rb.PushIpcInterface<IDeliveryCacheStorageService>( | ||
| 545 | fsc.GetBCATDirectory(system.CurrentProcess()->GetTitleID())); | ||
| 546 | } | ||
| 547 | |||
| 548 | void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( | ||
| 549 | Kernel::HLERequestContext& ctx) { | ||
| 550 | IPC::RequestParser rp{ctx}; | ||
| 551 | const auto title_id = rp.PopRaw<u64>(); | ||
| 552 | |||
| 553 | LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id); | ||
| 554 | |||
| 555 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 556 | rb.Push(RESULT_SUCCESS); | ||
| 557 | rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); | ||
| 558 | } | ||
| 559 | |||
| 560 | std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) { | ||
| 561 | const auto backend = Settings::values.bcat_backend; | ||
| 562 | |||
| 563 | #ifdef YUZU_ENABLE_BOXCAT | ||
| 564 | if (backend == "boxcat") | ||
| 565 | return std::make_unique<Boxcat>(std::move(getter)); | ||
| 566 | #endif | ||
| 567 | |||
| 568 | return std::make_unique<NullBackend>(std::move(getter)); | ||
| 41 | } | 569 | } |
| 42 | 570 | ||
| 43 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 571 | Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 44 | : ServiceFramework(name), module(std::move(module)) {} | 572 | FileSystem::FileSystemController& fsc_, const char* name) |
| 573 | : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)}, | ||
| 574 | backend{CreateBackendFromSettings([&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })}, | ||
| 575 | system{system_} {} | ||
| 45 | 576 | ||
| 46 | Module::Interface::~Interface() = default; | 577 | Module::Interface::~Interface() = default; |
| 47 | 578 | ||
| 48 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 579 | void InstallInterfaces(Core::System& system) { |
| 49 | auto module = std::make_shared<Module>(); | 580 | auto module = std::make_shared<Module>(); |
| 50 | std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); | 581 | std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:a") |
| 51 | std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager); | 582 | ->InstallAsService(system.ServiceManager()); |
| 52 | std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager); | 583 | std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m") |
| 53 | std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager); | 584 | ->InstallAsService(system.ServiceManager()); |
| 585 | std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u") | ||
| 586 | ->InstallAsService(system.ServiceManager()); | ||
| 587 | std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:s") | ||
| 588 | ->InstallAsService(system.ServiceManager()); | ||
| 54 | } | 589 | } |
| 55 | 590 | ||
| 56 | } // namespace Service::BCAT | 591 | } // namespace Service::BCAT |
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index f0d63cab0..e4ba23ba0 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h | |||
| @@ -6,23 +6,46 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Service::BCAT { | 9 | namespace Core { |
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | |||
| 15 | namespace FileSystem { | ||
| 16 | class FileSystemController; | ||
| 17 | } // namespace FileSystem | ||
| 18 | |||
| 19 | namespace BCAT { | ||
| 20 | |||
| 21 | class Backend; | ||
| 10 | 22 | ||
| 11 | class Module final { | 23 | class Module final { |
| 12 | public: | 24 | public: |
| 13 | class Interface : public ServiceFramework<Interface> { | 25 | class Interface : public ServiceFramework<Interface> { |
| 14 | public: | 26 | public: |
| 15 | explicit Interface(std::shared_ptr<Module> module, const char* name); | 27 | explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, |
| 28 | FileSystem::FileSystemController& fsc_, const char* name); | ||
| 16 | ~Interface() override; | 29 | ~Interface() override; |
| 17 | 30 | ||
| 18 | void CreateBcatService(Kernel::HLERequestContext& ctx); | 31 | void CreateBcatService(Kernel::HLERequestContext& ctx); |
| 32 | void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx); | ||
| 33 | void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx); | ||
| 19 | 34 | ||
| 20 | protected: | 35 | protected: |
| 36 | FileSystem::FileSystemController& fsc; | ||
| 37 | |||
| 21 | std::shared_ptr<Module> module; | 38 | std::shared_ptr<Module> module; |
| 39 | std::unique_ptr<Backend> backend; | ||
| 40 | |||
| 41 | private: | ||
| 42 | Core::System& system; | ||
| 22 | }; | 43 | }; |
| 23 | }; | 44 | }; |
| 24 | 45 | ||
| 25 | /// Registers all BCAT services with the specified service manager. | 46 | /// Registers all BCAT services with the specified service manager. |
| 26 | void InstallInterfaces(SM::ServiceManager& service_manager); | 47 | void InstallInterfaces(Core::System& system); |
| 48 | |||
| 49 | } // namespace BCAT | ||
| 27 | 50 | ||
| 28 | } // namespace Service::BCAT | 51 | } // namespace Service |
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index af70d174d..f77ddd739 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp | |||
| @@ -128,7 +128,7 @@ private: | |||
| 128 | void CountCommonTicket(Kernel::HLERequestContext& ctx) { | 128 | void CountCommonTicket(Kernel::HLERequestContext& ctx) { |
| 129 | LOG_DEBUG(Service_ETicket, "called"); | 129 | LOG_DEBUG(Service_ETicket, "called"); |
| 130 | 130 | ||
| 131 | const auto count = keys.GetCommonTickets().size(); | 131 | const u32 count = static_cast<u32>(keys.GetCommonTickets().size()); |
| 132 | 132 | ||
| 133 | IPC::ResponseBuilder rb{ctx, 3}; | 133 | IPC::ResponseBuilder rb{ctx, 3}; |
| 134 | rb.Push(RESULT_SUCCESS); | 134 | rb.Push(RESULT_SUCCESS); |
| @@ -138,7 +138,7 @@ private: | |||
| 138 | void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) { | 138 | void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) { |
| 139 | LOG_DEBUG(Service_ETicket, "called"); | 139 | LOG_DEBUG(Service_ETicket, "called"); |
| 140 | 140 | ||
| 141 | const auto count = keys.GetPersonalizedTickets().size(); | 141 | const u32 count = static_cast<u32>(keys.GetPersonalizedTickets().size()); |
| 142 | 142 | ||
| 143 | IPC::ResponseBuilder rb{ctx, 3}; | 143 | IPC::ResponseBuilder rb{ctx, 3}; |
| 144 | rb.Push(RESULT_SUCCESS); | 144 | rb.Push(RESULT_SUCCESS); |
| @@ -150,7 +150,7 @@ private: | |||
| 150 | if (keys.GetCommonTickets().empty()) | 150 | if (keys.GetCommonTickets().empty()) |
| 151 | out_entries = 0; | 151 | out_entries = 0; |
| 152 | else | 152 | else |
| 153 | out_entries = ctx.GetWriteBufferSize() / sizeof(u128); | 153 | out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); |
| 154 | 154 | ||
| 155 | LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); | 155 | LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); |
| 156 | 156 | ||
| @@ -160,7 +160,7 @@ private: | |||
| 160 | std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), | 160 | std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), |
| 161 | [](const auto& pair) { return pair.first; }); | 161 | [](const auto& pair) { return pair.first; }); |
| 162 | 162 | ||
| 163 | out_entries = std::min<u32>(ids.size(), out_entries); | 163 | out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); |
| 164 | ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); | 164 | ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); |
| 165 | 165 | ||
| 166 | IPC::ResponseBuilder rb{ctx, 3}; | 166 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -173,7 +173,7 @@ private: | |||
| 173 | if (keys.GetPersonalizedTickets().empty()) | 173 | if (keys.GetPersonalizedTickets().empty()) |
| 174 | out_entries = 0; | 174 | out_entries = 0; |
| 175 | else | 175 | else |
| 176 | out_entries = ctx.GetWriteBufferSize() / sizeof(u128); | 176 | out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); |
| 177 | 177 | ||
| 178 | LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); | 178 | LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); |
| 179 | 179 | ||
| @@ -183,7 +183,7 @@ private: | |||
| 183 | std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), | 183 | std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), |
| 184 | [](const auto& pair) { return pair.first; }); | 184 | [](const auto& pair) { return pair.first; }); |
| 185 | 185 | ||
| 186 | out_entries = std::min<u32>(ids.size(), out_entries); | 186 | out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); |
| 187 | ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); | 187 | ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); |
| 188 | 188 | ||
| 189 | IPC::ResponseBuilder rb{ctx, 3}; | 189 | IPC::ResponseBuilder rb{ctx, 3}; |
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index b2ebf6240..2546d7595 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -66,7 +66,7 @@ enum class FatalType : u32 { | |||
| 66 | 66 | ||
| 67 | static void GenerateErrorReport(Core::System& system, ResultCode error_code, | 67 | static void GenerateErrorReport(Core::System& system, ResultCode error_code, |
| 68 | const FatalInfo& info) { | 68 | const FatalInfo& info) { |
| 69 | const auto title_id = Core::CurrentProcess()->GetTitleID(); | 69 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 70 | std::string crash_report = fmt::format( | 70 | std::string crash_report = fmt::format( |
| 71 | "Yuzu {}-{} crash report\n" | 71 | "Yuzu {}-{} crash report\n" |
| 72 | "Title ID: {:016x}\n" | 72 | "Title ID: {:016x}\n" |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 14cd0e322..11e5c56b7 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -241,7 +241,7 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( | |||
| 241 | return FileSys::ERROR_PATH_NOT_FOUND; | 241 | return FileSys::ERROR_PATH_NOT_FOUND; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | FileSystemController::FileSystemController() = default; | 244 | FileSystemController::FileSystemController(Core::System& system_) : system{system_} {} |
| 245 | 245 | ||
| 246 | FileSystemController::~FileSystemController() = default; | 246 | FileSystemController::~FileSystemController() = default; |
| 247 | 247 | ||
| @@ -290,7 +290,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() | |||
| 290 | return ResultCode(-1); | 290 | return ResultCode(-1); |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | return romfs_factory->OpenCurrentProcess(); | 293 | return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( | 296 | ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( |
| @@ -447,10 +447,10 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy | |||
| 447 | FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; | 447 | FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; |
| 448 | 448 | ||
| 449 | FileSys::NACP nacp; | 449 | FileSys::NACP nacp; |
| 450 | const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp); | 450 | const auto res = system.GetAppLoader().ReadControlData(nacp); |
| 451 | 451 | ||
| 452 | if (res != Loader::ResultStatus::Success) { | 452 | if (res != Loader::ResultStatus::Success) { |
| 453 | FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()}; | 453 | FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; |
| 454 | auto [nacp_unique, discard] = pm.GetControlMetadata(); | 454 | auto [nacp_unique, discard] = pm.GetControlMetadata(); |
| 455 | 455 | ||
| 456 | if (nacp_unique != nullptr) { | 456 | if (nacp_unique != nullptr) { |
| @@ -674,6 +674,15 @@ FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) | |||
| 674 | return bis_factory->GetModificationDumpRoot(title_id); | 674 | return bis_factory->GetModificationDumpRoot(title_id); |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { | ||
| 678 | LOG_TRACE(Service_FS, "Opening BCAT root for tid={:016X}", title_id); | ||
| 679 | |||
| 680 | if (bis_factory == nullptr) | ||
| 681 | return nullptr; | ||
| 682 | |||
| 683 | return bis_factory->GetBCATDirectory(title_id); | ||
| 684 | } | ||
| 685 | |||
| 677 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 686 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { |
| 678 | if (overwrite) { | 687 | if (overwrite) { |
| 679 | bis_factory = nullptr; | 688 | bis_factory = nullptr; |
| @@ -693,10 +702,10 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 693 | if (bis_factory == nullptr) { | 702 | if (bis_factory == nullptr) { |
| 694 | bis_factory = | 703 | bis_factory = |
| 695 | std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory); | 704 | std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory); |
| 696 | Core::System::GetInstance().RegisterContentProvider( | 705 | system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SysNAND, |
| 697 | FileSys::ContentProviderUnionSlot::SysNAND, bis_factory->GetSystemNANDContents()); | 706 | bis_factory->GetSystemNANDContents()); |
| 698 | Core::System::GetInstance().RegisterContentProvider( | 707 | system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::UserNAND, |
| 699 | FileSys::ContentProviderUnionSlot::UserNAND, bis_factory->GetUserNANDContents()); | 708 | bis_factory->GetUserNANDContents()); |
| 700 | } | 709 | } |
| 701 | 710 | ||
| 702 | if (save_data_factory == nullptr) { | 711 | if (save_data_factory == nullptr) { |
| @@ -705,8 +714,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 705 | 714 | ||
| 706 | if (sdmc_factory == nullptr) { | 715 | if (sdmc_factory == nullptr) { |
| 707 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); | 716 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); |
| 708 | Core::System::GetInstance().RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC, | 717 | system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC, |
| 709 | sdmc_factory->GetSDMCContents()); | 718 | sdmc_factory->GetSDMCContents()); |
| 710 | } | 719 | } |
| 711 | } | 720 | } |
| 712 | 721 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 3e0c03ec0..1b0a6a949 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include "core/file_sys/vfs.h" | 10 | #include "core/file_sys/vfs.h" |
| 11 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 12 | 12 | ||
| 13 | namespace Core { | ||
| 14 | class System; | ||
| 15 | } | ||
| 16 | |||
| 13 | namespace FileSys { | 17 | namespace FileSys { |
| 14 | class BISFactory; | 18 | class BISFactory; |
| 15 | class RegisteredCache; | 19 | class RegisteredCache; |
| @@ -52,7 +56,7 @@ enum class ImageDirectoryId : u32 { | |||
| 52 | 56 | ||
| 53 | class FileSystemController { | 57 | class FileSystemController { |
| 54 | public: | 58 | public: |
| 55 | FileSystemController(); | 59 | explicit FileSystemController(Core::System& system_); |
| 56 | ~FileSystemController(); | 60 | ~FileSystemController(); |
| 57 | 61 | ||
| 58 | ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); | 62 | ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); |
| @@ -110,6 +114,8 @@ public: | |||
| 110 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; | 114 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; |
| 111 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; | 115 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; |
| 112 | 116 | ||
| 117 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; | ||
| 118 | |||
| 113 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function | 119 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function |
| 114 | // above is called. | 120 | // above is called. |
| 115 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); | 121 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); |
| @@ -123,6 +129,8 @@ private: | |||
| 123 | std::unique_ptr<FileSys::XCI> gamecard; | 129 | std::unique_ptr<FileSys::XCI> gamecard; |
| 124 | std::unique_ptr<FileSys::RegisteredCache> gamecard_registered; | 130 | std::unique_ptr<FileSys::RegisteredCache> gamecard_registered; |
| 125 | std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder; | 131 | std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder; |
| 132 | |||
| 133 | Core::System& system; | ||
| 126 | }; | 134 | }; |
| 127 | 135 | ||
| 128 | void InstallInterfaces(Core::System& system); | 136 | void InstallInterfaces(Core::System& system); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index eb982ad49..cbd5466c1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -803,7 +803,7 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 803 | IPC::RequestParser rp{ctx}; | 803 | IPC::RequestParser rp{ctx}; |
| 804 | 804 | ||
| 805 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); | 805 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); |
| 806 | auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); | 806 | [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); |
| 807 | u128 uid = rp.PopRaw<u128>(); | 807 | u128 uid = rp.PopRaw<u128>(); |
| 808 | 808 | ||
| 809 | LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), | 809 | LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 42b4ee861..75dd9043b 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -237,7 +237,6 @@ private: | |||
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | Common::UUID uuid; | 239 | Common::UUID uuid; |
| 240 | bool is_event_created = false; | ||
| 241 | Kernel::EventPair notification_event; | 240 | Kernel::EventPair notification_event; |
| 242 | std::queue<SizedNotificationInfo> notifications; | 241 | std::queue<SizedNotificationInfo> notifications; |
| 243 | States states{}; | 242 | States states{}; |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 8e8263f5b..1f2131ec8 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -11,11 +11,10 @@ | |||
| 11 | namespace Service::HID { | 11 | namespace Service::HID { |
| 12 | 12 | ||
| 13 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | 13 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; |
| 14 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 14 | [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
| 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; |
| 16 | 16 | ||
| 17 | Controller_DebugPad::Controller_DebugPad(Core::System& system) | 17 | Controller_DebugPad::Controller_DebugPad(Core::System& system) : ControllerBase(system) {} |
| 18 | : ControllerBase(system), system(system) {} | ||
| 19 | Controller_DebugPad::~Controller_DebugPad() = default; | 18 | Controller_DebugPad::~Controller_DebugPad() = default; |
| 20 | 19 | ||
| 21 | void Controller_DebugPad::OnInit() {} | 20 | void Controller_DebugPad::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 6c4de817e..555b29d76 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h | |||
| @@ -89,6 +89,5 @@ private: | |||
| 89 | buttons; | 89 | buttons; |
| 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> | 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> |
| 91 | analogs; | 91 | analogs; |
| 92 | Core::System& system; | ||
| 93 | }; | 92 | }; |
| 94 | } // namespace Service::HID | 93 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 80da0a0d3..6e990dd00 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -10,8 +10,7 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; | 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; |
| 12 | 12 | ||
| 13 | Controller_Gesture::Controller_Gesture(Core::System& system) | 13 | Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} |
| 14 | : ControllerBase(system), system(system) {} | ||
| 15 | Controller_Gesture::~Controller_Gesture() = default; | 14 | Controller_Gesture::~Controller_Gesture() = default; |
| 16 | 15 | ||
| 17 | void Controller_Gesture::OnInit() {} | 16 | void Controller_Gesture::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 396897527..f650b8338 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -59,6 +59,5 @@ private: | |||
| 59 | std::array<GestureState, 17> gesture_states; | 59 | std::array<GestureState, 17> gesture_states; |
| 60 | }; | 60 | }; |
| 61 | SharedMemory shared_memory{}; | 61 | SharedMemory shared_memory{}; |
| 62 | Core::System& system; | ||
| 63 | }; | 62 | }; |
| 64 | } // namespace Service::HID | 63 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index e587b2e15..358cb9329 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -12,8 +12,7 @@ namespace Service::HID { | |||
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; |
| 13 | constexpr u8 KEYS_PER_BYTE = 8; | 13 | constexpr u8 KEYS_PER_BYTE = 8; |
| 14 | 14 | ||
| 15 | Controller_Keyboard::Controller_Keyboard(Core::System& system) | 15 | Controller_Keyboard::Controller_Keyboard(Core::System& system) : ControllerBase(system) {} |
| 16 | : ControllerBase(system), system(system) {} | ||
| 17 | Controller_Keyboard::~Controller_Keyboard() = default; | 16 | Controller_Keyboard::~Controller_Keyboard() = default; |
| 18 | 17 | ||
| 19 | void Controller_Keyboard::OnInit() {} | 18 | void Controller_Keyboard::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index ef586f7eb..f3eef5936 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -53,6 +53,5 @@ private: | |||
| 53 | keyboard_keys; | 53 | keyboard_keys; |
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> | 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> |
| 55 | keyboard_mods; | 55 | keyboard_mods; |
| 56 | Core::System& system; | ||
| 57 | }; | 56 | }; |
| 58 | } // namespace Service::HID | 57 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 88f2ca4c1..93d88ea50 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | namespace Service::HID { | 11 | namespace Service::HID { |
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; |
| 13 | 13 | ||
| 14 | Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {} | 14 | Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system) {} |
| 15 | Controller_Mouse::~Controller_Mouse() = default; | 15 | Controller_Mouse::~Controller_Mouse() = default; |
| 16 | 16 | ||
| 17 | void Controller_Mouse::OnInit() {} | 17 | void Controller_Mouse::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index df2da6ae3..357ab7107 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -53,6 +53,5 @@ private: | |||
| 53 | std::unique_ptr<Input::MouseDevice> mouse_device; | 53 | std::unique_ptr<Input::MouseDevice> mouse_device; |
| 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> | 54 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> |
| 55 | mouse_button_devices; | 55 | mouse_button_devices; |
| 56 | Core::System& system; | ||
| 57 | }; | 56 | }; |
| 58 | } // namespace Service::HID | 57 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 44b668fbf..a2b25a796 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | namespace Service::HID { | 21 | namespace Service::HID { |
| 22 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | 22 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; |
| 23 | constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 23 | [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; |
| 24 | constexpr std::size_t NPAD_OFFSET = 0x9A00; | 24 | constexpr std::size_t NPAD_OFFSET = 0x9A00; |
| 25 | constexpr u32 BATTERY_FULL = 2; | 25 | constexpr u32 BATTERY_FULL = 2; |
| 26 | constexpr u32 MAX_NPAD_ID = 7; | 26 | constexpr u32 MAX_NPAD_ID = 7; |
| @@ -105,6 +105,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 105 | controller.joy_styles.raw = 0; // Zero out | 105 | controller.joy_styles.raw = 0; // Zero out |
| 106 | controller.device_type.raw = 0; | 106 | controller.device_type.raw = 0; |
| 107 | switch (controller_type) { | 107 | switch (controller_type) { |
| 108 | case NPadControllerType::None: | ||
| 109 | UNREACHABLE(); | ||
| 108 | case NPadControllerType::Handheld: | 110 | case NPadControllerType::Handheld: |
| 109 | controller.joy_styles.handheld.Assign(1); | 111 | controller.joy_styles.handheld.Assign(1); |
| 110 | controller.device_type.handheld.Assign(1); | 112 | controller.device_type.handheld.Assign(1); |
| @@ -165,13 +167,14 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 165 | controller.battery_level[0] = BATTERY_FULL; | 167 | controller.battery_level[0] = BATTERY_FULL; |
| 166 | controller.battery_level[1] = BATTERY_FULL; | 168 | controller.battery_level[1] = BATTERY_FULL; |
| 167 | controller.battery_level[2] = BATTERY_FULL; | 169 | controller.battery_level[2] = BATTERY_FULL; |
| 170 | styleset_changed_events[controller_idx].writable->Signal(); | ||
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | void Controller_NPad::OnInit() { | 173 | void Controller_NPad::OnInit() { |
| 171 | auto& kernel = system.Kernel(); | 174 | auto& kernel = system.Kernel(); |
| 172 | for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { | 175 | for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { |
| 173 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( | 176 | styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( |
| 174 | kernel, Kernel::ResetType::Automatic, fmt::format("npad:NpadStyleSetChanged_{}", i)); | 177 | kernel, Kernel::ResetType::Manual, fmt::format("npad:NpadStyleSetChanged_{}", i)); |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | if (!IsControllerActivated()) { | 180 | if (!IsControllerActivated()) { |
| @@ -238,7 +241,7 @@ void Controller_NPad::OnRelease() {} | |||
| 238 | 241 | ||
| 239 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | 242 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { |
| 240 | const auto controller_idx = NPadIdToIndex(npad_id); | 243 | const auto controller_idx = NPadIdToIndex(npad_id); |
| 241 | const auto controller_type = connected_controllers[controller_idx].type; | 244 | [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type; |
| 242 | if (!connected_controllers[controller_idx].is_connected) { | 245 | if (!connected_controllers[controller_idx].is_connected) { |
| 243 | return; | 246 | return; |
| 244 | } | 247 | } |
| @@ -345,6 +348,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 345 | libnx_entry.connection_status.raw = 0; | 348 | libnx_entry.connection_status.raw = 0; |
| 346 | 349 | ||
| 347 | switch (controller_type) { | 350 | switch (controller_type) { |
| 351 | case NPadControllerType::None: | ||
| 352 | UNREACHABLE(); | ||
| 348 | case NPadControllerType::Handheld: | 353 | case NPadControllerType::Handheld: |
| 349 | handheld_entry.connection_status.raw = 0; | 354 | handheld_entry.connection_status.raw = 0; |
| 350 | handheld_entry.connection_status.IsWired.Assign(1); | 355 | handheld_entry.connection_status.IsWired.Assign(1); |
| @@ -433,7 +438,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 433 | supported_npad_id_types.clear(); | 438 | supported_npad_id_types.clear(); |
| 434 | supported_npad_id_types.resize(length / sizeof(u32)); | 439 | supported_npad_id_types.resize(length / sizeof(u32)); |
| 435 | std::memcpy(supported_npad_id_types.data(), data, length); | 440 | std::memcpy(supported_npad_id_types.data(), data, length); |
| 436 | bool had_controller_update = false; | ||
| 437 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { | 441 | for (std::size_t i = 0; i < connected_controllers.size(); i++) { |
| 438 | auto& controller = connected_controllers[i]; | 442 | auto& controller = connected_controllers[i]; |
| 439 | if (!controller.is_connected) { | 443 | if (!controller.is_connected) { |
| @@ -452,10 +456,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 452 | controller.type = requested_controller; | 456 | controller.type = requested_controller; |
| 453 | InitNewlyAddedControler(i); | 457 | InitNewlyAddedControler(i); |
| 454 | } | 458 | } |
| 455 | had_controller_update = true; | ||
| 456 | } | ||
| 457 | if (had_controller_update) { | ||
| 458 | styleset_changed_events[i].writable->Signal(); | ||
| 459 | } | 459 | } |
| 460 | } | 460 | } |
| 461 | } | 461 | } |
| @@ -481,7 +481,6 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) | |||
| 481 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 481 | const std::size_t npad_index = NPadIdToIndex(npad_id); |
| 482 | ASSERT(npad_index < shared_memory_entries.size()); | 482 | ASSERT(npad_index < shared_memory_entries.size()); |
| 483 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { | 483 | if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { |
| 484 | styleset_changed_events[npad_index].writable->Signal(); | ||
| 485 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; | 484 | shared_memory_entries[npad_index].pad_assignment = assignment_mode; |
| 486 | } | 485 | } |
| 487 | } | 486 | } |
| @@ -507,7 +506,6 @@ Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEven | |||
| 507 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should | 506 | // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should |
| 508 | // be signalled at least once, and signaled after a new controller is connected? | 507 | // be signalled at least once, and signaled after a new controller is connected? |
| 509 | const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; | 508 | const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; |
| 510 | styleset_event.writable->Signal(); | ||
| 511 | return styleset_event.readable; | 509 | return styleset_event.readable; |
| 512 | } | 510 | } |
| 513 | 511 | ||
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 9b829341e..9e527d176 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp | |||
| @@ -9,8 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | 11 | ||
| 12 | Controller_Stubbed::Controller_Stubbed(Core::System& system) | 12 | Controller_Stubbed::Controller_Stubbed(Core::System& system) : ControllerBase(system) {} |
| 13 | : ControllerBase(system), system(system) {} | ||
| 14 | Controller_Stubbed::~Controller_Stubbed() = default; | 13 | Controller_Stubbed::~Controller_Stubbed() = default; |
| 15 | 14 | ||
| 16 | void Controller_Stubbed::OnInit() {} | 15 | void Controller_Stubbed::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 37d7d8538..4fa83ac85 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h | |||
| @@ -30,6 +30,5 @@ public: | |||
| 30 | private: | 30 | private: |
| 31 | bool smart_update{}; | 31 | bool smart_update{}; |
| 32 | std::size_t common_offset{}; | 32 | std::size_t common_offset{}; |
| 33 | Core::System& system; | ||
| 34 | }; | 33 | }; |
| 35 | } // namespace Service::HID | 34 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 25912fd69..1c6e55566 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -13,8 +13,7 @@ | |||
| 13 | namespace Service::HID { | 13 | namespace Service::HID { |
| 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; |
| 15 | 15 | ||
| 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) | 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} |
| 17 | : ControllerBase(system), system(system) {} | ||
| 18 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 17 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 19 | 18 | ||
| 20 | void Controller_Touchscreen::OnInit() {} | 19 | void Controller_Touchscreen::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 3429c84db..a1d97269e 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -69,6 +69,5 @@ private: | |||
| 69 | TouchScreenSharedMemory shared_memory{}; | 69 | TouchScreenSharedMemory shared_memory{}; |
| 70 | std::unique_ptr<Input::TouchDevice> touch_device; | 70 | std::unique_ptr<Input::TouchDevice> touch_device; |
| 71 | s64_le last_touch{}; | 71 | s64_le last_touch{}; |
| 72 | Core::System& system; | ||
| 73 | }; | 72 | }; |
| 74 | } // namespace Service::HID | 73 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 1bce044b4..27511b27b 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; | 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; |
| 12 | 12 | ||
| 13 | Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {} | 13 | Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system) {} |
| 14 | Controller_XPad::~Controller_XPad() = default; | 14 | Controller_XPad::~Controller_XPad() = default; |
| 15 | 15 | ||
| 16 | void Controller_XPad::OnInit() {} | 16 | void Controller_XPad::OnInit() {} |
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index c445ebec0..ad229787c 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h | |||
| @@ -56,6 +56,5 @@ private: | |||
| 56 | }; | 56 | }; |
| 57 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); | 57 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); |
| 58 | SharedMemory shared_memory{}; | 58 | SharedMemory shared_memory{}; |
| 59 | Core::System& system; | ||
| 60 | }; | 59 | }; |
| 61 | } // namespace Service::HID | 60 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 8d76ba746..ba1da4181 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -38,8 +38,10 @@ namespace Service::HID { | |||
| 38 | // Updating period for each HID device. | 38 | // Updating period for each HID device. |
| 39 | // TODO(ogniK): Find actual polling rate of hid | 39 | // TODO(ogniK): Find actual polling rate of hid |
| 40 | constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); | 40 | constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); |
| 41 | constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); | 41 | [[maybe_unused]] constexpr s64 accelerometer_update_ticks = |
| 42 | constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); | 42 | static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); |
| 43 | [[maybe_unused]] constexpr s64 gyroscope_update_ticks = | ||
| 44 | static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); | ||
| 43 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 45 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 44 | 46 | ||
| 45 | IAppletResource::IAppletResource(Core::System& system) | 47 | IAppletResource::IAppletResource(Core::System& system) |
| @@ -193,7 +195,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 193 | {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, | 195 | {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, |
| 194 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, | 196 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, |
| 195 | {103, &Hid::ActivateNpad, "ActivateNpad"}, | 197 | {103, &Hid::ActivateNpad, "ActivateNpad"}, |
| 196 | {104, nullptr, "DeactivateNpad"}, | 198 | {104, &Hid::DeactivateNpad, "DeactivateNpad"}, |
| 197 | {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, | 199 | {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, |
| 198 | {107, &Hid::DisconnectNpad, "DisconnectNpad"}, | 200 | {107, &Hid::DisconnectNpad, "DisconnectNpad"}, |
| 199 | {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, | 201 | {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, |
| @@ -468,6 +470,17 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { | |||
| 468 | applet_resource->ActivateController(HidController::NPad); | 470 | applet_resource->ActivateController(HidController::NPad); |
| 469 | } | 471 | } |
| 470 | 472 | ||
| 473 | void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { | ||
| 474 | IPC::RequestParser rp{ctx}; | ||
| 475 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 476 | |||
| 477 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 478 | |||
| 479 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 480 | rb.Push(RESULT_SUCCESS); | ||
| 481 | applet_resource->DeactivateController(HidController::NPad); | ||
| 482 | } | ||
| 483 | |||
| 471 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 484 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 472 | IPC::RequestParser rp{ctx}; | 485 | IPC::RequestParser rp{ctx}; |
| 473 | const auto npad_id{rp.Pop<u32>()}; | 486 | const auto npad_id{rp.Pop<u32>()}; |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 35b663679..01852e019 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -99,6 +99,7 @@ private: | |||
| 99 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); | 99 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); |
| 100 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); | 100 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); |
| 101 | void ActivateNpad(Kernel::HLERequestContext& ctx); | 101 | void ActivateNpad(Kernel::HLERequestContext& ctx); |
| 102 | void DeactivateNpad(Kernel::HLERequestContext& ctx); | ||
| 102 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); | 103 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); |
| 103 | void DisconnectNpad(Kernel::HLERequestContext& ctx); | 104 | void DisconnectNpad(Kernel::HLERequestContext& ctx); |
| 104 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); | 105 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 3164ca26e..499376bfc 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -163,7 +163,7 @@ public: | |||
| 163 | return; | 163 | return; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | if (Core::CurrentProcess()->GetTitleID() != header.title_id) { | 166 | if (system.CurrentProcess()->GetTitleID() != header.title_id) { |
| 167 | LOG_ERROR(Service_LDR, | 167 | LOG_ERROR(Service_LDR, |
| 168 | "Attempting to load NRR with title ID other than current process. (actual " | 168 | "Attempting to load NRR with title ID other than current process. (actual " |
| 169 | "{:016X})!", | 169 | "{:016X})!", |
| @@ -327,7 +327,7 @@ public: | |||
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | // Load NRO as new executable module | 329 | // Load NRO as new executable module |
| 330 | auto* process = Core::CurrentProcess(); | 330 | auto* process = system.CurrentProcess(); |
| 331 | auto& vm_manager = process->VMManager(); | 331 | auto& vm_manager = process->VMManager(); |
| 332 | auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size); | 332 | auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size); |
| 333 | 333 | ||
| @@ -411,7 +411,7 @@ public: | |||
| 411 | return; | 411 | return; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | auto& vm_manager = Core::CurrentProcess()->VMManager(); | 414 | auto& vm_manager = system.CurrentProcess()->VMManager(); |
| 415 | const auto& nro_info = iter->second; | 415 | const auto& nro_info = iter->second; |
| 416 | 416 | ||
| 417 | // Unmap the mirrored memory | 417 | // Unmap the mirrored memory |
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 2a61593e2..435f2d286 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -6,8 +6,10 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | 7 | ||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/scope_exit.h" | ||
| 9 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/service/lm/lm.h" | 11 | #include "core/hle/service/lm/lm.h" |
| 12 | #include "core/hle/service/lm/manager.h" | ||
| 11 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 12 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| 13 | 15 | ||
| @@ -15,65 +17,16 @@ namespace Service::LM { | |||
| 15 | 17 | ||
| 16 | class ILogger final : public ServiceFramework<ILogger> { | 18 | class ILogger final : public ServiceFramework<ILogger> { |
| 17 | public: | 19 | public: |
| 18 | ILogger() : ServiceFramework("ILogger") { | 20 | ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) { |
| 19 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 20 | {0x00000000, &ILogger::Initialize, "Initialize"}, | 22 | {0, &ILogger::Log, "Log"}, |
| 21 | {0x00000001, &ILogger::SetDestination, "SetDestination"}, | 23 | {1, &ILogger::SetDestination, "SetDestination"}, |
| 22 | }; | 24 | }; |
| 23 | RegisterHandlers(functions); | 25 | RegisterHandlers(functions); |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | private: | 28 | private: |
| 27 | struct MessageHeader { | 29 | void Log(Kernel::HLERequestContext& ctx) { |
| 28 | enum Flags : u32_le { | ||
| 29 | IsHead = 1, | ||
| 30 | IsTail = 2, | ||
| 31 | }; | ||
| 32 | enum Severity : u32_le { | ||
| 33 | Trace, | ||
| 34 | Info, | ||
| 35 | Warning, | ||
| 36 | Error, | ||
| 37 | Critical, | ||
| 38 | }; | ||
| 39 | |||
| 40 | u64_le pid; | ||
| 41 | u64_le threadContext; | ||
| 42 | union { | ||
| 43 | BitField<0, 16, Flags> flags; | ||
| 44 | BitField<16, 8, Severity> severity; | ||
| 45 | BitField<24, 8, u32> verbosity; | ||
| 46 | }; | ||
| 47 | u32_le payload_size; | ||
| 48 | |||
| 49 | bool IsHeadLog() const { | ||
| 50 | return flags & Flags::IsHead; | ||
| 51 | } | ||
| 52 | bool IsTailLog() const { | ||
| 53 | return flags & Flags::IsTail; | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); | ||
| 57 | |||
| 58 | /// Log field type | ||
| 59 | enum class Field : u8 { | ||
| 60 | Skip = 1, | ||
| 61 | Message = 2, | ||
| 62 | Line = 3, | ||
| 63 | Filename = 4, | ||
| 64 | Function = 5, | ||
| 65 | Module = 6, | ||
| 66 | Thread = 7, | ||
| 67 | }; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * ILogger::Initialize service function | ||
| 71 | * Inputs: | ||
| 72 | * 0: 0x00000000 | ||
| 73 | * Outputs: | ||
| 74 | * 0: ResultCode | ||
| 75 | */ | ||
| 76 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 77 | // This function only succeeds - Get that out of the way | 30 | // This function only succeeds - Get that out of the way |
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | 31 | IPC::ResponseBuilder rb{ctx, 2}; |
| 79 | rb.Push(RESULT_SUCCESS); | 32 | rb.Push(RESULT_SUCCESS); |
| @@ -85,140 +38,70 @@ private: | |||
| 85 | Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); | 38 | Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); |
| 86 | addr += sizeof(MessageHeader); | 39 | addr += sizeof(MessageHeader); |
| 87 | 40 | ||
| 88 | if (header.IsHeadLog()) { | 41 | FieldMap fields; |
| 89 | log_stream.str(""); | ||
| 90 | log_stream.clear(); | ||
| 91 | } | ||
| 92 | |||
| 93 | // Parse out log metadata | ||
| 94 | u32 line{}; | ||
| 95 | std::string module; | ||
| 96 | std::string message; | ||
| 97 | std::string filename; | ||
| 98 | std::string function; | ||
| 99 | std::string thread; | ||
| 100 | while (addr < end_addr) { | 42 | while (addr < end_addr) { |
| 101 | const Field field{static_cast<Field>(Memory::Read8(addr++))}; | 43 | const auto field = static_cast<Field>(Memory::Read8(addr++)); |
| 102 | const std::size_t length{Memory::Read8(addr++)}; | 44 | const auto length = Memory::Read8(addr++); |
| 103 | 45 | ||
| 104 | if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { | 46 | if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { |
| 105 | ++addr; | 47 | ++addr; |
| 106 | } | 48 | } |
| 107 | 49 | ||
| 108 | switch (field) { | 50 | SCOPE_EXIT({ addr += length; }); |
| 109 | case Field::Skip: | ||
| 110 | break; | ||
| 111 | case Field::Message: | ||
| 112 | message = Memory::ReadCString(addr, length); | ||
| 113 | break; | ||
| 114 | case Field::Line: | ||
| 115 | line = Memory::Read32(addr); | ||
| 116 | break; | ||
| 117 | case Field::Filename: | ||
| 118 | filename = Memory::ReadCString(addr, length); | ||
| 119 | break; | ||
| 120 | case Field::Function: | ||
| 121 | function = Memory::ReadCString(addr, length); | ||
| 122 | break; | ||
| 123 | case Field::Module: | ||
| 124 | module = Memory::ReadCString(addr, length); | ||
| 125 | break; | ||
| 126 | case Field::Thread: | ||
| 127 | thread = Memory::ReadCString(addr, length); | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | 51 | ||
| 131 | addr += length; | 52 | if (field == Field::Skip) { |
| 132 | } | 53 | continue; |
| 54 | } | ||
| 133 | 55 | ||
| 134 | // Empty log - nothing to do here | 56 | std::vector<u8> data(length); |
| 135 | if (log_stream.str().empty() && message.empty()) { | 57 | Memory::ReadBlock(addr, data.data(), length); |
| 136 | return; | 58 | fields.emplace(field, std::move(data)); |
| 137 | } | 59 | } |
| 138 | 60 | ||
| 139 | // Format a nicely printable string out of the log metadata | 61 | manager.Log({header, std::move(fields)}); |
| 140 | if (!filename.empty()) { | ||
| 141 | log_stream << filename << ':'; | ||
| 142 | } | ||
| 143 | if (!module.empty()) { | ||
| 144 | log_stream << module << ':'; | ||
| 145 | } | ||
| 146 | if (!function.empty()) { | ||
| 147 | log_stream << function << ':'; | ||
| 148 | } | ||
| 149 | if (line) { | ||
| 150 | log_stream << std::to_string(line) << ':'; | ||
| 151 | } | ||
| 152 | if (!thread.empty()) { | ||
| 153 | log_stream << thread << ':'; | ||
| 154 | } | ||
| 155 | if (log_stream.str().length() > 0 && log_stream.str().back() == ':') { | ||
| 156 | log_stream << ' '; | ||
| 157 | } | ||
| 158 | log_stream << message; | ||
| 159 | |||
| 160 | if (header.IsTailLog()) { | ||
| 161 | switch (header.severity) { | ||
| 162 | case MessageHeader::Severity::Trace: | ||
| 163 | LOG_DEBUG(Debug_Emulated, "{}", log_stream.str()); | ||
| 164 | break; | ||
| 165 | case MessageHeader::Severity::Info: | ||
| 166 | LOG_INFO(Debug_Emulated, "{}", log_stream.str()); | ||
| 167 | break; | ||
| 168 | case MessageHeader::Severity::Warning: | ||
| 169 | LOG_WARNING(Debug_Emulated, "{}", log_stream.str()); | ||
| 170 | break; | ||
| 171 | case MessageHeader::Severity::Error: | ||
| 172 | LOG_ERROR(Debug_Emulated, "{}", log_stream.str()); | ||
| 173 | break; | ||
| 174 | case MessageHeader::Severity::Critical: | ||
| 175 | LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | 62 | } |
| 180 | 63 | ||
| 181 | // This service function is intended to be used as a way to | ||
| 182 | // redirect logging output to different destinations, however, | ||
| 183 | // given we always want to see the logging output, it's sufficient | ||
| 184 | // to do nothing and return success here. | ||
| 185 | void SetDestination(Kernel::HLERequestContext& ctx) { | 64 | void SetDestination(Kernel::HLERequestContext& ctx) { |
| 186 | LOG_DEBUG(Service_LM, "called"); | 65 | IPC::RequestParser rp{ctx}; |
| 66 | const auto destination = rp.PopEnum<DestinationFlag>(); | ||
| 67 | |||
| 68 | LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination)); | ||
| 69 | |||
| 70 | manager.SetDestination(destination); | ||
| 187 | 71 | ||
| 188 | IPC::ResponseBuilder rb{ctx, 2}; | 72 | IPC::ResponseBuilder rb{ctx, 2}; |
| 189 | rb.Push(RESULT_SUCCESS); | 73 | rb.Push(RESULT_SUCCESS); |
| 190 | } | 74 | } |
| 191 | 75 | ||
| 192 | std::ostringstream log_stream; | 76 | Manager& manager; |
| 193 | }; | 77 | }; |
| 194 | 78 | ||
| 195 | class LM final : public ServiceFramework<LM> { | 79 | class LM final : public ServiceFramework<LM> { |
| 196 | public: | 80 | public: |
| 197 | explicit LM() : ServiceFramework{"lm"} { | 81 | explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) { |
| 82 | // clang-format off | ||
| 198 | static const FunctionInfo functions[] = { | 83 | static const FunctionInfo functions[] = { |
| 199 | {0x00000000, &LM::OpenLogger, "OpenLogger"}, | 84 | {0, &LM::OpenLogger, "OpenLogger"}, |
| 200 | }; | 85 | }; |
| 86 | // clang-format on | ||
| 87 | |||
| 201 | RegisterHandlers(functions); | 88 | RegisterHandlers(functions); |
| 202 | } | 89 | } |
| 203 | 90 | ||
| 204 | /** | 91 | private: |
| 205 | * LM::OpenLogger service function | ||
| 206 | * Inputs: | ||
| 207 | * 0: 0x00000000 | ||
| 208 | * Outputs: | ||
| 209 | * 0: ResultCode | ||
| 210 | */ | ||
| 211 | void OpenLogger(Kernel::HLERequestContext& ctx) { | 92 | void OpenLogger(Kernel::HLERequestContext& ctx) { |
| 212 | LOG_DEBUG(Service_LM, "called"); | 93 | LOG_DEBUG(Service_LM, "called"); |
| 213 | 94 | ||
| 214 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 95 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 215 | rb.Push(RESULT_SUCCESS); | 96 | rb.Push(RESULT_SUCCESS); |
| 216 | rb.PushIpcInterface<ILogger>(); | 97 | rb.PushIpcInterface<ILogger>(manager); |
| 217 | } | 98 | } |
| 99 | |||
| 100 | Manager& manager; | ||
| 218 | }; | 101 | }; |
| 219 | 102 | ||
| 220 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 103 | void InstallInterfaces(Core::System& system) { |
| 221 | std::make_shared<LM>()->InstallAsService(service_manager); | 104 | std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager()); |
| 222 | } | 105 | } |
| 223 | 106 | ||
| 224 | } // namespace Service::LM | 107 | } // namespace Service::LM |
diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h index 7806ae27b..d40410b5c 100644 --- a/src/core/hle/service/lm/lm.h +++ b/src/core/hle/service/lm/lm.h | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | namespace Service::SM { | 7 | namespace Core { |
| 8 | class ServiceManager; | 8 | class System; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | namespace Service::LM { | 11 | namespace Service::LM { |
| 12 | 12 | ||
| 13 | /// Registers all LM services with the specified service manager. | 13 | /// Registers all LM services with the specified service manager. |
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager); | 14 | void InstallInterfaces(Core::System& system); |
| 15 | 15 | ||
| 16 | } // namespace Service::LM | 16 | } // namespace Service::LM |
diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp new file mode 100644 index 000000000..b67081b86 --- /dev/null +++ b/src/core/hle/service/lm/manager.cpp | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/hle/service/lm/manager.h" | ||
| 9 | #include "core/reporter.h" | ||
| 10 | |||
| 11 | namespace Service::LM { | ||
| 12 | |||
| 13 | std::ostream& operator<<(std::ostream& os, DestinationFlag dest) { | ||
| 14 | std::vector<std::string> array; | ||
| 15 | const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) { | ||
| 16 | if ((static_cast<u32>(check) & static_cast<u32>(dest)) != 0) { | ||
| 17 | array.emplace_back(std::move(name)); | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | check_single_flag(DestinationFlag::Default, "Default"); | ||
| 22 | check_single_flag(DestinationFlag::UART, "UART"); | ||
| 23 | check_single_flag(DestinationFlag::UARTSleeping, "UART (Sleeping)"); | ||
| 24 | |||
| 25 | os << "["; | ||
| 26 | for (const auto& entry : array) { | ||
| 27 | os << entry << ", "; | ||
| 28 | } | ||
| 29 | return os << "]"; | ||
| 30 | } | ||
| 31 | |||
| 32 | std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity) { | ||
| 33 | switch (severity) { | ||
| 34 | case MessageHeader::Severity::Trace: | ||
| 35 | return os << "Trace"; | ||
| 36 | case MessageHeader::Severity::Info: | ||
| 37 | return os << "Info"; | ||
| 38 | case MessageHeader::Severity::Warning: | ||
| 39 | return os << "Warning"; | ||
| 40 | case MessageHeader::Severity::Error: | ||
| 41 | return os << "Error"; | ||
| 42 | case MessageHeader::Severity::Critical: | ||
| 43 | return os << "Critical"; | ||
| 44 | default: | ||
| 45 | return os << fmt::format("{:08X}", static_cast<u32>(severity)); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | std::ostream& operator<<(std::ostream& os, Field field) { | ||
| 50 | switch (field) { | ||
| 51 | case Field::Skip: | ||
| 52 | return os << "Skip"; | ||
| 53 | case Field::Message: | ||
| 54 | return os << "Message"; | ||
| 55 | case Field::Line: | ||
| 56 | return os << "Line"; | ||
| 57 | case Field::Filename: | ||
| 58 | return os << "Filename"; | ||
| 59 | case Field::Function: | ||
| 60 | return os << "Function"; | ||
| 61 | case Field::Module: | ||
| 62 | return os << "Module"; | ||
| 63 | case Field::Thread: | ||
| 64 | return os << "Thread"; | ||
| 65 | default: | ||
| 66 | return os << fmt::format("{:08X}", static_cast<u32>(field)); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | std::string FormatField(Field type, const std::vector<u8>& data) { | ||
| 71 | switch (type) { | ||
| 72 | case Field::Skip: | ||
| 73 | return ""; | ||
| 74 | case Field::Line: | ||
| 75 | if (data.size() >= sizeof(u32)) { | ||
| 76 | u32 line; | ||
| 77 | std::memcpy(&line, data.data(), sizeof(u32)); | ||
| 78 | return fmt::format("{}", line); | ||
| 79 | } | ||
| 80 | return "[ERROR DECODING LINE NUMBER]"; | ||
| 81 | case Field::Message: | ||
| 82 | case Field::Filename: | ||
| 83 | case Field::Function: | ||
| 84 | case Field::Module: | ||
| 85 | case Field::Thread: | ||
| 86 | return Common::StringFromFixedZeroTerminatedBuffer( | ||
| 87 | reinterpret_cast<const char*>(data.data()), data.size()); | ||
| 88 | default: | ||
| 89 | UNIMPLEMENTED(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {} | ||
| 94 | |||
| 95 | Manager::~Manager() = default; | ||
| 96 | |||
| 97 | void Manager::SetEnabled(bool enabled) { | ||
| 98 | this->enabled = enabled; | ||
| 99 | } | ||
| 100 | |||
| 101 | void Manager::SetDestination(DestinationFlag destination) { | ||
| 102 | this->destination = destination; | ||
| 103 | } | ||
| 104 | |||
| 105 | void Manager::Log(LogMessage message) { | ||
| 106 | if (message.header.IsHeadLog()) { | ||
| 107 | InitializeLog(); | ||
| 108 | } | ||
| 109 | |||
| 110 | current_log.emplace_back(std::move(message)); | ||
| 111 | |||
| 112 | if (current_log.back().header.IsTailLog()) { | ||
| 113 | FinalizeLog(); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | void Manager::Flush() { | ||
| 118 | FinalizeLog(); | ||
| 119 | } | ||
| 120 | |||
| 121 | void Manager::InitializeLog() { | ||
| 122 | current_log.clear(); | ||
| 123 | |||
| 124 | LOG_INFO(Service_LM, "Initialized new log session"); | ||
| 125 | } | ||
| 126 | |||
| 127 | void Manager::FinalizeLog() { | ||
| 128 | reporter.SaveLogReport(static_cast<u32>(destination), std::move(current_log)); | ||
| 129 | |||
| 130 | LOG_INFO(Service_LM, "Finalized current log session"); | ||
| 131 | } | ||
| 132 | |||
| 133 | } // namespace Service::LM | ||
diff --git a/src/core/hle/service/lm/manager.h b/src/core/hle/service/lm/manager.h new file mode 100644 index 000000000..544e636ba --- /dev/null +++ b/src/core/hle/service/lm/manager.h | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | #include <ostream> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class Reporter; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::LM { | ||
| 19 | |||
| 20 | enum class DestinationFlag : u32 { | ||
| 21 | Default = 1, | ||
| 22 | UART = 2, | ||
| 23 | UARTSleeping = 4, | ||
| 24 | |||
| 25 | All = 0xFFFF, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct MessageHeader { | ||
| 29 | enum Flags : u32_le { | ||
| 30 | IsHead = 1, | ||
| 31 | IsTail = 2, | ||
| 32 | }; | ||
| 33 | enum Severity : u32_le { | ||
| 34 | Trace, | ||
| 35 | Info, | ||
| 36 | Warning, | ||
| 37 | Error, | ||
| 38 | Critical, | ||
| 39 | }; | ||
| 40 | |||
| 41 | u64_le pid; | ||
| 42 | u64_le thread_context; | ||
| 43 | union { | ||
| 44 | BitField<0, 16, Flags> flags; | ||
| 45 | BitField<16, 8, Severity> severity; | ||
| 46 | BitField<24, 8, u32> verbosity; | ||
| 47 | }; | ||
| 48 | u32_le payload_size; | ||
| 49 | |||
| 50 | bool IsHeadLog() const { | ||
| 51 | return flags & IsHead; | ||
| 52 | } | ||
| 53 | bool IsTailLog() const { | ||
| 54 | return flags & IsTail; | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); | ||
| 58 | |||
| 59 | enum class Field : u8 { | ||
| 60 | Skip = 1, | ||
| 61 | Message = 2, | ||
| 62 | Line = 3, | ||
| 63 | Filename = 4, | ||
| 64 | Function = 5, | ||
| 65 | Module = 6, | ||
| 66 | Thread = 7, | ||
| 67 | }; | ||
| 68 | |||
| 69 | std::ostream& operator<<(std::ostream& os, DestinationFlag dest); | ||
| 70 | std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity); | ||
| 71 | std::ostream& operator<<(std::ostream& os, Field field); | ||
| 72 | |||
| 73 | using FieldMap = std::map<Field, std::vector<u8>>; | ||
| 74 | |||
| 75 | struct LogMessage { | ||
| 76 | MessageHeader header; | ||
| 77 | FieldMap fields; | ||
| 78 | }; | ||
| 79 | |||
| 80 | std::string FormatField(Field type, const std::vector<u8>& data); | ||
| 81 | |||
| 82 | class Manager { | ||
| 83 | public: | ||
| 84 | explicit Manager(Core::Reporter& reporter); | ||
| 85 | ~Manager(); | ||
| 86 | |||
| 87 | void SetEnabled(bool enabled); | ||
| 88 | void SetDestination(DestinationFlag destination); | ||
| 89 | |||
| 90 | void Log(LogMessage message); | ||
| 91 | |||
| 92 | void Flush(); | ||
| 93 | |||
| 94 | private: | ||
| 95 | void InitializeLog(); | ||
| 96 | void FinalizeLog(); | ||
| 97 | |||
| 98 | bool enabled = true; | ||
| 99 | DestinationFlag destination = DestinationFlag::All; | ||
| 100 | |||
| 101 | std::vector<LogMessage> current_log; | ||
| 102 | |||
| 103 | Core::Reporter& reporter; | ||
| 104 | }; | ||
| 105 | |||
| 106 | } // namespace Service::LM | ||
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a42c22d44..aa886cd3e 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -18,8 +18,8 @@ | |||
| 18 | namespace Service::NFP { | 18 | namespace Service::NFP { |
| 19 | 19 | ||
| 20 | namespace ErrCodes { | 20 | namespace ErrCodes { |
| 21 | constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, | 21 | [[maybe_unused]] constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, |
| 22 | -1); // TODO(ogniK): Find the actual error code | 22 | -1); // TODO(ogniK): Find the actual error code |
| 23 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); | 23 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); |
| 24 | } // namespace ErrCodes | 24 | } // namespace ErrCodes |
| 25 | 25 | ||
| @@ -35,7 +35,7 @@ Module::Interface::~Interface() = default; | |||
| 35 | class IUser final : public ServiceFramework<IUser> { | 35 | class IUser final : public ServiceFramework<IUser> { |
| 36 | public: | 36 | public: |
| 37 | IUser(Module::Interface& nfp_interface, Core::System& system) | 37 | IUser(Module::Interface& nfp_interface, Core::System& system) |
| 38 | : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) { | 38 | : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { |
| 39 | static const FunctionInfo functions[] = { | 39 | static const FunctionInfo functions[] = { |
| 40 | {0, &IUser::Initialize, "Initialize"}, | 40 | {0, &IUser::Initialize, "Initialize"}, |
| 41 | {1, &IUser::Finalize, "Finalize"}, | 41 | {1, &IUser::Finalize, "Finalize"}, |
| @@ -183,6 +183,8 @@ private: | |||
| 183 | case DeviceState::TagRemoved: | 183 | case DeviceState::TagRemoved: |
| 184 | device_state = DeviceState::Initialized; | 184 | device_state = DeviceState::Initialized; |
| 185 | break; | 185 | break; |
| 186 | default: | ||
| 187 | break; | ||
| 186 | } | 188 | } |
| 187 | IPC::ResponseBuilder rb{ctx, 2}; | 189 | IPC::ResponseBuilder rb{ctx, 2}; |
| 188 | rb.Push(RESULT_SUCCESS); | 190 | rb.Push(RESULT_SUCCESS); |
| @@ -324,7 +326,6 @@ private: | |||
| 324 | Kernel::EventPair deactivate_event; | 326 | Kernel::EventPair deactivate_event; |
| 325 | Kernel::EventPair availability_change_event; | 327 | Kernel::EventPair availability_change_event; |
| 326 | const Module::Interface& nfp_interface; | 328 | const Module::Interface& nfp_interface; |
| 327 | Core::System& system; | ||
| 328 | }; | 329 | }; |
| 329 | 330 | ||
| 330 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | 331 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 24d1813a7..756a2af57 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -12,6 +12,13 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::NIFM { | 13 | namespace Service::NIFM { |
| 14 | 14 | ||
| 15 | enum class RequestState : u32 { | ||
| 16 | NotSubmitted = 1, | ||
| 17 | Error = 1, ///< The duplicate 1 is intentional; it means both not submitted and error on HW. | ||
| 18 | Pending = 2, | ||
| 19 | Connected = 3, | ||
| 20 | }; | ||
| 21 | |||
| 15 | class IScanRequest final : public ServiceFramework<IScanRequest> { | 22 | class IScanRequest final : public ServiceFramework<IScanRequest> { |
| 16 | public: | 23 | public: |
| 17 | explicit IScanRequest() : ServiceFramework("IScanRequest") { | 24 | explicit IScanRequest() : ServiceFramework("IScanRequest") { |
| @@ -81,7 +88,7 @@ private: | |||
| 81 | 88 | ||
| 82 | IPC::ResponseBuilder rb{ctx, 3}; | 89 | IPC::ResponseBuilder rb{ctx, 3}; |
| 83 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 84 | rb.Push<u32>(0); | 91 | rb.PushEnum(RequestState::Connected); |
| 85 | } | 92 | } |
| 86 | 93 | ||
| 87 | void GetResult(Kernel::HLERequestContext& ctx) { | 94 | void GetResult(Kernel::HLERequestContext& ctx) { |
| @@ -189,14 +196,14 @@ private: | |||
| 189 | 196 | ||
| 190 | IPC::ResponseBuilder rb{ctx, 3}; | 197 | IPC::ResponseBuilder rb{ctx, 3}; |
| 191 | rb.Push(RESULT_SUCCESS); | 198 | rb.Push(RESULT_SUCCESS); |
| 192 | rb.Push<u8>(0); | 199 | rb.Push<u8>(1); |
| 193 | } | 200 | } |
| 194 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { | 201 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { |
| 195 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 202 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 196 | 203 | ||
| 197 | IPC::ResponseBuilder rb{ctx, 3}; | 204 | IPC::ResponseBuilder rb{ctx, 3}; |
| 198 | rb.Push(RESULT_SUCCESS); | 205 | rb.Push(RESULT_SUCCESS); |
| 199 | rb.Push<u8>(0); | 206 | rb.Push<u8>(1); |
| 200 | } | 207 | } |
| 201 | Core::System& system; | 208 | Core::System& system; |
| 202 | }; | 209 | }; |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 7dcdb4a07..f64535237 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -324,14 +324,14 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 324 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 324 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 325 | // Map backing memory for the font data | 325 | // Map backing memory for the font data |
| 326 | LOG_DEBUG(Service_NS, "called"); | 326 | LOG_DEBUG(Service_NS, "called"); |
| 327 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, | 327 | system.CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, |
| 328 | SHARED_FONT_MEM_SIZE, | 328 | SHARED_FONT_MEM_SIZE, |
| 329 | Kernel::MemoryState::Shared); | 329 | Kernel::MemoryState::Shared); |
| 330 | 330 | ||
| 331 | // Create shared font memory object | 331 | // Create shared font memory object |
| 332 | auto& kernel = system.Kernel(); | 332 | auto& kernel = system.Kernel(); |
| 333 | impl->shared_font_mem = Kernel::SharedMemory::Create( | 333 | impl->shared_font_mem = Kernel::SharedMemory::Create( |
| 334 | kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, | 334 | kernel, system.CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, |
| 335 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | 335 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, |
| 336 | "PL_U:shared_font_mem"); | 336 | "PL_U:shared_font_mem"); |
| 337 | 337 | ||
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 6bc053f27..07c88465e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -45,6 +45,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std: | |||
| 45 | return GetVARegions(input, output); | 45 | return GetVARegions(input, output); |
| 46 | case IoctlCommand::IocUnmapBufferCommand: | 46 | case IoctlCommand::IocUnmapBufferCommand: |
| 47 | return UnmapBuffer(input, output); | 47 | return UnmapBuffer(input, output); |
| 48 | default: | ||
| 49 | break; | ||
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) | 52 | if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index ff6b1abae..eb88fee1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -38,9 +38,10 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::v | |||
| 38 | return IocCtrlEventUnregister(input, output); | 38 | return IocCtrlEventUnregister(input, output); |
| 39 | case IoctlCommand::IocCtrlEventSignalCommand: | 39 | case IoctlCommand::IocCtrlEventSignalCommand: |
| 40 | return IocCtrlEventSignal(input, output); | 40 | return IocCtrlEventSignal(input, output); |
| 41 | default: | ||
| 42 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 43 | return 0; | ||
| 41 | } | 44 | } |
| 42 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 43 | return 0; | ||
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { | 47 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { |
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 389ace76f..cc2192e5c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -40,9 +40,10 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, | |||
| 40 | return FlushL2(input, output); | 40 | return FlushL2(input, output); |
| 41 | case IoctlCommand::IocGetGpuTime: | 41 | case IoctlCommand::IocGetGpuTime: |
| 42 | return GetGpuTime(input, output); | 42 | return GetGpuTime(input, output); |
| 43 | default: | ||
| 44 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 45 | return 0; | ||
| 43 | } | 46 | } |
| 44 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 45 | return 0; | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 49 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 2b8d1bef6..9de0ace22 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -44,6 +44,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve | |||
| 44 | return GetWaitbase(input, output); | 44 | return GetWaitbase(input, output); |
| 45 | case IoctlCommand::IocChannelSetTimeoutCommand: | 45 | case IoctlCommand::IocChannelSetTimeoutCommand: |
| 46 | return ChannelSetTimeout(input, output); | 46 | return ChannelSetTimeout(input, output); |
| 47 | default: | ||
| 48 | break; | ||
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | if (command.group == NVGPU_IOCTL_MAGIC) { | 51 | if (command.group == NVGPU_IOCTL_MAGIC) { |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 831a427de..7c5302017 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -208,7 +208,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 208 | AOC::InstallInterfaces(*sm, system); | 208 | AOC::InstallInterfaces(*sm, system); |
| 209 | APM::InstallInterfaces(system); | 209 | APM::InstallInterfaces(system); |
| 210 | Audio::InstallInterfaces(*sm, system); | 210 | Audio::InstallInterfaces(*sm, system); |
| 211 | BCAT::InstallInterfaces(*sm); | 211 | BCAT::InstallInterfaces(system); |
| 212 | BPC::InstallInterfaces(*sm); | 212 | BPC::InstallInterfaces(*sm); |
| 213 | BtDrv::InstallInterfaces(*sm, system); | 213 | BtDrv::InstallInterfaces(*sm, system); |
| 214 | BTM::InstallInterfaces(*sm, system); | 214 | BTM::InstallInterfaces(*sm, system); |
| @@ -226,7 +226,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 226 | LBL::InstallInterfaces(*sm); | 226 | LBL::InstallInterfaces(*sm); |
| 227 | LDN::InstallInterfaces(*sm); | 227 | LDN::InstallInterfaces(*sm); |
| 228 | LDR::InstallInterfaces(*sm, system); | 228 | LDR::InstallInterfaces(*sm, system); |
| 229 | LM::InstallInterfaces(*sm); | 229 | LM::InstallInterfaces(system); |
| 230 | Migration::InstallInterfaces(*sm); | 230 | Migration::InstallInterfaces(*sm); |
| 231 | Mii::InstallInterfaces(*sm); | 231 | Mii::InstallInterfaces(*sm); |
| 232 | MM::InstallInterfaces(*sm); | 232 | MM::InstallInterfaces(*sm); |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index e75c700ad..f629892ae 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -150,6 +150,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 150 | // Apply cheats if they exist and the program has a valid title ID | 150 | // Apply cheats if they exist and the program has a valid title ID |
| 151 | if (pm) { | 151 | if (pm) { |
| 152 | auto& system = Core::System::GetInstance(); | 152 | auto& system = Core::System::GetInstance(); |
| 153 | system.SetCurrentProcessBuildID(nso_header.build_id); | ||
| 153 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); | 154 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); |
| 154 | if (!cheats.empty()) { | 155 | if (!cheats.empty()) { |
| 155 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); | 156 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9e030789d..fa49f3dd0 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -146,7 +146,7 @@ static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { | |||
| 146 | * using a VMA from the current process. | 146 | * using a VMA from the current process. |
| 147 | */ | 147 | */ |
| 148 | static u8* GetPointerFromVMA(VAddr vaddr) { | 148 | static u8* GetPointerFromVMA(VAddr vaddr) { |
| 149 | return GetPointerFromVMA(*Core::CurrentProcess(), vaddr); | 149 | return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | template <typename T> | 152 | template <typename T> |
| @@ -226,7 +226,7 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | bool IsValidVirtualAddress(const VAddr vaddr) { | 228 | bool IsValidVirtualAddress(const VAddr vaddr) { |
| 229 | return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); | 229 | return IsValidVirtualAddress(*Core::System::GetInstance().CurrentProcess(), vaddr); |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | bool IsKernelVirtualAddress(const VAddr vaddr) { | 232 | bool IsKernelVirtualAddress(const VAddr vaddr) { |
| @@ -387,7 +387,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { | 389 | void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { |
| 390 | ReadBlock(*Core::CurrentProcess(), src_addr, dest_buffer, size); | 390 | ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size); |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | void Write8(const VAddr addr, const u8 data) { | 393 | void Write8(const VAddr addr, const u8 data) { |
| @@ -450,7 +450,7 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { | 452 | void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { |
| 453 | WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); | 453 | WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size); |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { | 456 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { |
| @@ -539,7 +539,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | |||
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { | 541 | void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { |
| 542 | CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); | 542 | CopyBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_addr, size); |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | } // namespace Memory | 545 | } // namespace Memory |
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 9c657929e..6f4af77fd 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include <fmt/chrono.h> | 8 | #include <fmt/chrono.h> |
| 9 | #include <fmt/format.h> | 9 | #include <fmt/format.h> |
| 10 | #include <fmt/ostream.h> | ||
| 10 | #include <json.hpp> | 11 | #include <json.hpp> |
| 11 | 12 | ||
| 12 | #include "common/file_util.h" | 13 | #include "common/file_util.h" |
| @@ -17,6 +18,7 @@ | |||
| 17 | #include "core/hle/kernel/hle_ipc.h" | 18 | #include "core/hle/kernel/hle_ipc.h" |
| 18 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/result.h" | 20 | #include "core/hle/result.h" |
| 21 | #include "core/hle/service/lm/manager.h" | ||
| 20 | #include "core/reporter.h" | 22 | #include "core/reporter.h" |
| 21 | #include "core/settings.h" | 23 | #include "core/settings.h" |
| 22 | 24 | ||
| @@ -354,6 +356,55 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result, | |||
| 354 | SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); | 356 | SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); |
| 355 | } | 357 | } |
| 356 | 358 | ||
| 359 | void Reporter::SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const { | ||
| 360 | if (!IsReportingEnabled()) { | ||
| 361 | return; | ||
| 362 | } | ||
| 363 | |||
| 364 | const auto timestamp = GetTimestamp(); | ||
| 365 | json out; | ||
| 366 | |||
| 367 | out["yuzu_version"] = GetYuzuVersionData(); | ||
| 368 | out["report_common"] = | ||
| 369 | GetReportCommonData(system.CurrentProcess()->GetTitleID(), RESULT_SUCCESS, timestamp); | ||
| 370 | |||
| 371 | out["log_destination"] = | ||
| 372 | fmt::format("{}", static_cast<Service::LM::DestinationFlag>(destination)); | ||
| 373 | |||
| 374 | auto json_messages = json::array(); | ||
| 375 | std::transform(messages.begin(), messages.end(), std::back_inserter(json_messages), | ||
| 376 | [](const Service::LM::LogMessage& message) { | ||
| 377 | json out; | ||
| 378 | out["is_head"] = fmt::format("{}", message.header.IsHeadLog()); | ||
| 379 | out["is_tail"] = fmt::format("{}", message.header.IsTailLog()); | ||
| 380 | out["pid"] = fmt::format("{:016X}", message.header.pid); | ||
| 381 | out["thread_context"] = | ||
| 382 | fmt::format("{:016X}", message.header.thread_context); | ||
| 383 | out["payload_size"] = fmt::format("{:016X}", message.header.payload_size); | ||
| 384 | out["flags"] = fmt::format("{:04X}", message.header.flags.Value()); | ||
| 385 | out["severity"] = fmt::format("{}", message.header.severity.Value()); | ||
| 386 | out["verbosity"] = fmt::format("{:02X}", message.header.verbosity); | ||
| 387 | |||
| 388 | auto fields = json::array(); | ||
| 389 | std::transform(message.fields.begin(), message.fields.end(), | ||
| 390 | std::back_inserter(fields), [](const auto& kv) { | ||
| 391 | json out; | ||
| 392 | out["type"] = fmt::format("{}", kv.first); | ||
| 393 | out["data"] = | ||
| 394 | Service::LM::FormatField(kv.first, kv.second); | ||
| 395 | return out; | ||
| 396 | }); | ||
| 397 | |||
| 398 | out["fields"] = std::move(fields); | ||
| 399 | return out; | ||
| 400 | }); | ||
| 401 | |||
| 402 | out["log_messages"] = std::move(json_messages); | ||
| 403 | |||
| 404 | SaveToFile(std::move(out), | ||
| 405 | GetPath("log_report", system.CurrentProcess()->GetTitleID(), timestamp)); | ||
| 406 | } | ||
| 407 | |||
| 357 | void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, | 408 | void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, |
| 358 | std::string log_message) const { | 409 | std::string log_message) const { |
| 359 | if (!IsReportingEnabled()) | 410 | if (!IsReportingEnabled()) |
diff --git a/src/core/reporter.h b/src/core/reporter.h index f08aa11fb..380941b1b 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h | |||
| @@ -20,6 +20,10 @@ namespace Service::FileSystem { | |||
| 20 | enum class LogMode : u32; | 20 | enum class LogMode : u32; |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | namespace Service::LM { | ||
| 24 | struct LogMessage; | ||
| 25 | } // namespace Service::LM | ||
| 26 | |||
| 23 | namespace Core { | 27 | namespace Core { |
| 24 | 28 | ||
| 25 | class System; | 29 | class System; |
| @@ -29,18 +33,22 @@ public: | |||
| 29 | explicit Reporter(System& system); | 33 | explicit Reporter(System& system); |
| 30 | ~Reporter(); | 34 | ~Reporter(); |
| 31 | 35 | ||
| 36 | // Used by fatal services | ||
| 32 | void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, | 37 | void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, |
| 33 | u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far, | 38 | u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far, |
| 34 | const std::array<u64, 31>& registers, const std::array<u64, 32>& backtrace, | 39 | const std::array<u64, 31>& registers, const std::array<u64, 32>& backtrace, |
| 35 | u32 backtrace_size, const std::string& arch, u32 unk10) const; | 40 | u32 backtrace_size, const std::string& arch, u32 unk10) const; |
| 36 | 41 | ||
| 42 | // Used by syscall svcBreak | ||
| 37 | void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, | 43 | void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, |
| 38 | std::optional<std::vector<u8>> resolved_buffer = {}) const; | 44 | std::optional<std::vector<u8>> resolved_buffer = {}) const; |
| 39 | 45 | ||
| 46 | // Used by HLE service handler | ||
| 40 | void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, | 47 | void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, |
| 41 | const std::string& name, | 48 | const std::string& name, |
| 42 | const std::string& service_name) const; | 49 | const std::string& service_name) const; |
| 43 | 50 | ||
| 51 | // Used by stub applet implementation | ||
| 44 | void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version, | 52 | void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version, |
| 45 | u32 theme_color, bool startup_sound, u64 system_tick, | 53 | u32 theme_color, bool startup_sound, u64 system_tick, |
| 46 | std::vector<std::vector<u8>> normal_channel, | 54 | std::vector<std::vector<u8>> normal_channel, |
| @@ -55,6 +63,7 @@ public: | |||
| 55 | void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data, | 63 | void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data, |
| 56 | std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const; | 64 | std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const; |
| 57 | 65 | ||
| 66 | // Used by error applet | ||
| 58 | void SaveErrorReport(u64 title_id, ResultCode result, | 67 | void SaveErrorReport(u64 title_id, ResultCode result, |
| 59 | std::optional<std::string> custom_text_main = {}, | 68 | std::optional<std::string> custom_text_main = {}, |
| 60 | std::optional<std::string> custom_text_detail = {}) const; | 69 | std::optional<std::string> custom_text_detail = {}) const; |
| @@ -62,6 +71,11 @@ public: | |||
| 62 | void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, | 71 | void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, |
| 63 | std::string log_message) const; | 72 | std::string log_message) const; |
| 64 | 73 | ||
| 74 | // Used by lm services | ||
| 75 | void SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const; | ||
| 76 | |||
| 77 | // Can be used anywhere to generate a backtrace and general info report at any point during | ||
| 78 | // execution. Not intended to be used for anything other than debugging or testing. | ||
| 65 | void SaveUserReport() const; | 79 | void SaveUserReport() const; |
| 66 | 80 | ||
| 67 | private: | 81 | private: |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 7de3fd1e5..d1fc94060 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -103,6 +103,8 @@ void LogSettings() { | |||
| 103 | LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); | 103 | LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); |
| 104 | LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); | 104 | LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); |
| 105 | LogSetting("Debugging_ProgramArgs", Settings::values.program_args); | 105 | LogSetting("Debugging_ProgramArgs", Settings::values.program_args); |
| 106 | LogSetting("Services_BCATBackend", Settings::values.bcat_backend); | ||
| 107 | LogSetting("Services_BCATBoxcatLocal", Settings::values.bcat_boxcat_local); | ||
| 106 | } | 108 | } |
| 107 | 109 | ||
| 108 | } // namespace Settings | 110 | } // namespace Settings |
diff --git a/src/core/settings.h b/src/core/settings.h index 47bddfb30..9c98a9287 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -448,6 +448,10 @@ struct Values { | |||
| 448 | bool reporting_services; | 448 | bool reporting_services; |
| 449 | bool quest_flag; | 449 | bool quest_flag; |
| 450 | 450 | ||
| 451 | // BCAT | ||
| 452 | std::string bcat_backend; | ||
| 453 | bool bcat_boxcat_local; | ||
| 454 | |||
| 451 | // WebService | 455 | // WebService |
| 452 | bool enable_telemetry; | 456 | bool enable_telemetry; |
| 453 | std::string web_api_url; | 457 | std::string web_api_url; |