summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt20
-rw-r--r--src/core/core.cpp12
-rw-r--r--src/core/core.h11
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/bis_factory.cpp5
-rw-r--r--src/core/file_sys/bis_factory.h2
-rw-r--r--src/core/file_sys/romfs_factory.cpp4
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp5
-rw-r--r--src/core/file_sys/vfs_libzip.cpp79
-rw-r--r--src/core/file_sys/vfs_libzip.h13
-rw-r--r--src/core/gdbstub/gdbstub.cpp3
-rw-r--r--src/core/hle/kernel/handle_table.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp69
-rw-r--r--src/core/hle/service/am/am.h5
-rw-r--r--src/core/hle/service/am/applets/applets.cpp4
-rw-r--r--src/core/hle/service/am/applets/applets.h2
-rw-r--r--src/core/hle/service/apm/controller.cpp3
-rw-r--r--src/core/hle/service/apm/controller.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp137
-rw-r--r--src/core/hle/service/bcat/backend/backend.h150
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp504
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.h58
-rw-r--r--src/core/hle/service/bcat/bcat.cpp9
-rw-r--r--src/core/hle/service/bcat/bcat.h7
-rw-r--r--src/core/hle/service/bcat/module.cpp561
-rw-r--r--src/core/hle/service/bcat/module.h31
-rw-r--r--src/core/hle/service/fatal/fatal.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp29
-rw-r--r--src/core/hle/service/filesystem/filesystem.h10
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp2
-rw-r--r--src/core/hle/service/friend/friend.cpp1
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h1
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h1
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h1
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp18
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h1
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h1
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp19
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/ldr/ldr.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp.cpp9
-rw-r--r--src/core/hle/service/nifm/nifm.cpp13
-rw-r--r--src/core/hle/service/ns/pl_u.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp2
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/loader/nso.cpp1
-rw-r--r--src/core/memory.cpp10
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h4
63 files changed, 1758 insertions, 129 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index be3ffb779..3b1d72cf9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,3 +1,9 @@
1if (YUZU_ENABLE_BOXCAT)
2 set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
3else()
4 set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
5endif()
6
1add_library(core STATIC 7add_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
@@ -501,6 +512,15 @@ create_target_directory_groups(core)
501 512
502target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 513target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
503target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) 514target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives)
515
516if (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)
522endif()
523
504if (ENABLE_WEB_SERVICE) 524if (ENABLE_WEB_SERVICE)
505 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) 525 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
506 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 bf62085a8..4d0ac72a5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -112,7 +112,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
112} 112}
113struct System::Impl { 113struct System::Impl {
114 explicit Impl(System& system) 114 explicit Impl(System& system)
115 : 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} {}
116 117
117 Cpu& CurrentCpuCore() { 118 Cpu& CurrentCpuCore() {
118 return cpu_core_manager.GetCurrentCore(); 119 return cpu_core_manager.GetCurrentCore();
@@ -343,6 +344,7 @@ struct System::Impl {
343 Reporter reporter; 344 Reporter reporter;
344 std::unique_ptr<Memory::CheatEngine> cheat_engine; 345 std::unique_ptr<Memory::CheatEngine> cheat_engine;
345 std::unique_ptr<Tools::Freezer> memory_freezer; 346 std::unique_ptr<Tools::Freezer> memory_freezer;
347 std::array<u8, 0x20> build_id{};
346 348
347 /// Frontend applets 349 /// Frontend applets
348 Service::AM::Applets::AppletManager applet_manager; 350 Service::AM::Applets::AppletManager applet_manager;
@@ -651,6 +653,14 @@ bool System::GetExitLock() const {
651 return impl->exit_lock; 653 return impl->exit_lock;
652} 654}
653 655
656void System::SetCurrentProcessBuildID(const CurrentBuildProcessID& id) {
657 impl->build_id = id;
658}
659
660const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
661 return impl->build_id;
662}
663
654System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 664System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
655 return impl->Init(*this, emu_window); 665 return impl->Init(*this, emu_window);
656} 666}
diff --git a/src/core/core.h b/src/core/core.h
index 0170e0b05..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"
@@ -102,6 +101,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
102 101
103class System { 102class System {
104public: 103public:
104 using CurrentBuildProcessID = std::array<u8, 0x20>;
105
105 System(const System&) = delete; 106 System(const System&) = delete;
106 System& operator=(const System&) = delete; 107 System& operator=(const System&) = delete;
107 108
@@ -338,6 +339,10 @@ public:
338 339
339 bool GetExitLock() const; 340 bool GetExitLock() const;
340 341
342 void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
343
344 const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
345
341private: 346private:
342 System(); 347 System();
343 348
@@ -361,8 +366,4 @@ private:
361 static System s_instance; 366 static System s_instance;
362}; 367};
363 368
364inline Kernel::Process* CurrentProcess() {
365 return System::GetInstance().CurrentProcess();
366}
367
368} // 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) {
423std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, 423std::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
139VirtualDir 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
64private: 66private:
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
38ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const { 38ResultVal<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
39private: 39private:
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
12namespace FileSys {
13
14VirtualDir 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
9namespace FileSys {
10
11VirtualDir 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};
46constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; 47constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3};
47constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; 48constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
48 49
49constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; 50enum class LaunchParameterKind : u32 {
51 ApplicationSpecific = 1,
52 AccountPreselectedUser = 2,
53};
54
55constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
50 56
51struct LaunchParameters { 57struct 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};
57static_assert(sizeof(LaunchParameters) == 0x88); 63static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
58 64
59IWindowController::IWindowController(Core::System& system_) 65IWindowController::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
1130void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 1136void 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(), &params, 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(), &params, 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
1153void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( 1188void 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
161class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 160class 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
158AppletManager::~AppletManager() = default; 158AppletManager::~AppletManager() = default;
159 159
160const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
161 return frontend;
162}
163
160void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 164void 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
15Controller::Controller(Core::Timing::CoreTiming& core_timing) 15Controller::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
63void Controller::SetClockSpeed(u32 mhz) { 63void 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.
51class Controller { 51class Controller {
52public: 52public:
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:
62private: 62private:
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
11namespace Service::BCAT {
12
13ProgressServiceBackend::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
20Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const {
21 return event.readable;
22}
23
24DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
25 return impl;
26}
27
28void ProgressServiceBackend::SetNeedHLELock(bool need) {
29 need_hle_lock = need;
30}
31
32void ProgressServiceBackend::SetTotalSize(u64 size) {
33 impl.total_bytes = size;
34 SignalUpdate();
35}
36
37void ProgressServiceBackend::StartConnecting() {
38 impl.status = DeliveryCacheProgressImpl::Status::Connecting;
39 SignalUpdate();
40}
41
42void ProgressServiceBackend::StartProcessingDataList() {
43 impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList;
44 SignalUpdate();
45}
46
47void 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
59void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) {
60 impl.current_downloaded_bytes = downloaded;
61 SignalUpdate();
62}
63
64void ProgressServiceBackend::FinishDownloadingFile() {
65 impl.total_downloaded_bytes += impl.current_total_bytes;
66 SignalUpdate();
67}
68
69void 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
79void 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
86void 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
95Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}
96
97Backend::~Backend() = default;
98
99NullBackend::NullBackend(DirectoryGetter getter) : Backend(std::move(getter)) {}
100
101NullBackend::~NullBackend() = default;
102
103bool 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
111bool 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
120bool NullBackend::Clear(u64 title_id) {
121 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}");
122
123 return true;
124}
125
126void 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
131std::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
18namespace Service::BCAT {
19
20struct DeliveryCacheProgressImpl;
21
22using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>;
23using Passphrase = std::array<u8, 0x20>;
24
25struct TitleIDVersion {
26 u64 title_id;
27 u64 build_id;
28};
29
30using DirectoryName = std::array<char, 0x20>;
31using FileName = std::array<char, 0x20>;
32
33struct 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};
55static_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.
60class ProgressServiceBackend {
61 friend class IBcatService;
62
63public:
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
90private:
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.
104class Backend {
105public:
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
127protected:
128 DirectoryGetter dir_getter;
129};
130
131// A backend of BCAT that provides no operation.
132class NullBackend : public Backend {
133public:
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
148std::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
21namespace {
22
23// Prevents conflicts with windows macro called CreateFile
24FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) {
25 return dir->CreateFile(name);
26}
27
28// Prevents conflicts with windows macro called DeleteFile
29bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) {
30 return dir->DeleteFile(name);
31}
32
33} // Anonymous namespace
34
35namespace Service::BCAT {
36
37constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1};
38
39constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org";
40
41// Formatted using fmt with arg[0] = hex title id
42constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat";
43constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam";
44
45constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events";
46
47constexpr char BOXCAT_API_VERSION[] = "1";
48constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu";
49
50// HTTP status codes for Boxcat
51enum 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
60enum class DownloadResult {
61 Success = 0,
62 NoResponse,
63 GeneralWebError,
64 NoMatchTitleId,
65 NoMatchBuildId,
66 InvalidContentType,
67 GeneralFSError,
68 BadClientVersion,
69};
70
71constexpr 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
85std::ostream& operator<<(std::ostream& os, DownloadResult result) {
86 return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result));
87}
88
89constexpr u32 PORT = 443;
90constexpr u32 TIMEOUT_SECONDS = 30;
91[[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB
92
93namespace {
94
95std::string GetBINFilePath(u64 title_id) {
96 return fmt::format("{}bcat/{:016X}/launchparam.bin",
97 FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id);
98}
99
100std::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.
107void 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
120bool 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
150bool 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
166bool 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
183class Boxcat::Client {
184public:
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
198private:
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
267Boxcat::Boxcat(DirectoryGetter getter) : Backend(std::move(getter)) {}
268
269Boxcat::~Boxcat() = default;
270
271void 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
365bool 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
372bool 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
381bool 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
402void 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
407std::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
440Boxcat::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
12namespace Service::BCAT {
13
14struct 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.
22class Boxcat final : public Backend {
23 friend void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title,
24 ProgressServiceBackend& progress,
25 std::optional<std::string> dir_name);
26
27public:
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
51private:
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
7namespace Service::BCAT { 7namespace Service::BCAT {
8 8
9BCAT::BCAT(std::shared_ptr<Module> module, const char* name) 9BCAT::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
9namespace Core {
10class System;
11}
12
9namespace Service::BCAT { 13namespace Service::BCAT {
10 14
11class BCAT final : public Module::Interface { 15class BCAT final : public Module::Interface {
12public: 16public:
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
10namespace Service::BCAT { 22namespace Service::BCAT {
11 23
24constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::BCAT, 1};
25constexpr ResultCode ERROR_FAILED_OPEN_ENTITY{ErrorModule::BCAT, 2};
26constexpr ResultCode ERROR_ENTITY_ALREADY_OPEN{ErrorModule::BCAT, 6};
27constexpr 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.
32constexpr ResultCode ERROR_FAILED_CLEAR_CACHE{ErrorModule::FS, 6400};
33
34using BCATDigest = std::array<u8, 0x10>;
35
36namespace {
37
38u64 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.
46BCATDigest 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.
56bool 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
72bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) {
73 return VerifyNameValidInternal(ctx, name, '-');
74}
75
76bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) {
77 return VerifyNameValidInternal(ctx, name, '.');
78}
79
80} // Anonymous namespace
81
82struct DeliveryCacheDirectoryEntry {
83 FileName name;
84 u64 size;
85 BCATDigest digest;
86};
87
88class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
89public:
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
103private:
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
12class IBcatService final : public ServiceFramework<IBcatService> { 125class IBcatService final : public ServiceFramework<IBcatService> {
13public: 126public:
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
150private:
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
35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 258void 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
266class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
267public:
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
282private:
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
382class IDeliveryCacheDirectoryService final
383 : public ServiceFramework<IDeliveryCacheDirectoryService> {
384public:
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
398private:
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
481class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
482public:
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
503private:
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
539void 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
548void 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
560std::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
43Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 571Module::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
46Module::Interface::~Interface() = default; 577Module::Interface::~Interface() = default;
47 578
48void InstallInterfaces(SM::ServiceManager& service_manager) { 579void 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
9namespace Service::BCAT { 9namespace Core {
10class System;
11}
12
13namespace Service {
14
15namespace FileSystem {
16class FileSystemController;
17} // namespace FileSystem
18
19namespace BCAT {
20
21class Backend;
10 22
11class Module final { 23class Module final {
12public: 24public:
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.
26void InstallInterfaces(SM::ServiceManager& service_manager); 47void InstallInterfaces(Core::System& system);
48
49} // namespace BCAT
27 50
28} // namespace Service::BCAT 51} // namespace Service
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
67static void GenerateErrorReport(Core::System& system, ResultCode error_code, 67static 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
244FileSystemController::FileSystemController() = default; 244FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
245 245
246FileSystemController::~FileSystemController() = default; 246FileSystemController::~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
296ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( 296ResultVal<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
677FileSys::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
677void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { 686void 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
13namespace Core {
14class System;
15}
16
13namespace FileSys { 17namespace FileSys {
14class BISFactory; 18class BISFactory;
15class RegisteredCache; 19class RegisteredCache;
@@ -52,7 +56,7 @@ enum class ImageDirectoryId : u32 {
52 56
53class FileSystemController { 57class FileSystemController {
54public: 58public:
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
128void InstallInterfaces(Core::System& system); 136void 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 @@
11namespace Service::HID { 11namespace Service::HID {
12 12
13constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 13constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 14[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; 15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
16 16
17Controller_DebugPad::Controller_DebugPad(Core::System& system) 17Controller_DebugPad::Controller_DebugPad(Core::System& system) : ControllerBase(system) {}
18 : ControllerBase(system), system(system) {}
19Controller_DebugPad::~Controller_DebugPad() = default; 18Controller_DebugPad::~Controller_DebugPad() = default;
20 19
21void Controller_DebugPad::OnInit() {} 20void 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 @@
10namespace Service::HID { 10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; 11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
12 12
13Controller_Gesture::Controller_Gesture(Core::System& system) 13Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {}
14 : ControllerBase(system), system(system) {}
15Controller_Gesture::~Controller_Gesture() = default; 14Controller_Gesture::~Controller_Gesture() = default;
16 15
17void Controller_Gesture::OnInit() {} 16void 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 {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
13constexpr u8 KEYS_PER_BYTE = 8; 13constexpr u8 KEYS_PER_BYTE = 8;
14 14
15Controller_Keyboard::Controller_Keyboard(Core::System& system) 15Controller_Keyboard::Controller_Keyboard(Core::System& system) : ControllerBase(system) {}
16 : ControllerBase(system), system(system) {}
17Controller_Keyboard::~Controller_Keyboard() = default; 16Controller_Keyboard::~Controller_Keyboard() = default;
18 17
19void Controller_Keyboard::OnInit() {} 18void 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 @@
11namespace Service::HID { 11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
13 13
14Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {} 14Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system) {}
15Controller_Mouse::~Controller_Mouse() = default; 15Controller_Mouse::~Controller_Mouse() = default;
16 16
17void Controller_Mouse::OnInit() {} 17void 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
21namespace Service::HID { 21namespace Service::HID {
22constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 22constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
23constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 23[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
24constexpr std::size_t NPAD_OFFSET = 0x9A00; 24constexpr std::size_t NPAD_OFFSET = 0x9A00;
25constexpr u32 BATTERY_FULL = 2; 25constexpr u32 BATTERY_FULL = 2;
26constexpr u32 MAX_NPAD_ID = 7; 26constexpr 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
170void Controller_NPad::OnInit() { 173void 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
239void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { 242void 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
10namespace Service::HID { 10namespace Service::HID {
11 11
12Controller_Stubbed::Controller_Stubbed(Core::System& system) 12Controller_Stubbed::Controller_Stubbed(Core::System& system) : ControllerBase(system) {}
13 : ControllerBase(system), system(system) {}
14Controller_Stubbed::~Controller_Stubbed() = default; 13Controller_Stubbed::~Controller_Stubbed() = default;
15 14
16void Controller_Stubbed::OnInit() {} 15void 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:
30private: 30private:
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 @@
13namespace Service::HID { 13namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
15 15
16Controller_Touchscreen::Controller_Touchscreen(Core::System& system) 16Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {}
17 : ControllerBase(system), system(system) {}
18Controller_Touchscreen::~Controller_Touchscreen() = default; 17Controller_Touchscreen::~Controller_Touchscreen() = default;
19 18
20void Controller_Touchscreen::OnInit() {} 19void 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 @@
10namespace Service::HID { 10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; 11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
12 12
13Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {} 13Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system) {}
14Controller_XPad::~Controller_XPad() = default; 14Controller_XPad::~Controller_XPad() = default;
15 15
16void Controller_XPad::OnInit() {} 16void 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
40constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66); 40constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66);
41constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); 41[[maybe_unused]] constexpr s64 accelerometer_update_ticks =
42constexpr 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);
43constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 45constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
44 46
45IAppletResource::IAppletResource(Core::System& system) 47IAppletResource::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
473void 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
471void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 484void 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/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 @@
18namespace Service::NFP { 18namespace Service::NFP {
19 19
20namespace ErrCodes { 20namespace ErrCodes {
21constexpr 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
23constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); 23constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
24} // namespace ErrCodes 24} // namespace ErrCodes
25 25
@@ -35,7 +35,7 @@ Module::Interface::~Interface() = default;
35class IUser final : public ServiceFramework<IUser> { 35class IUser final : public ServiceFramework<IUser> {
36public: 36public:
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
330void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 331void 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
13namespace Service::NIFM { 13namespace Service::NIFM {
14 14
15enum 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
15class IScanRequest final : public ServiceFramework<IScanRequest> { 22class IScanRequest final : public ServiceFramework<IScanRequest> {
16public: 23public:
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) {
324void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 324void 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
46u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { 47u32 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
48u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 49u32 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 c12a746c8..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);
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 */
148static u8* GetPointerFromVMA(VAddr vaddr) { 148static u8* GetPointerFromVMA(VAddr vaddr) {
149 return GetPointerFromVMA(*Core::CurrentProcess(), vaddr); 149 return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr);
150} 150}
151 151
152template <typename T> 152template <typename T>
@@ -226,7 +226,7 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
226} 226}
227 227
228bool IsValidVirtualAddress(const VAddr vaddr) { 228bool IsValidVirtualAddress(const VAddr vaddr) {
229 return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); 229 return IsValidVirtualAddress(*Core::System::GetInstance().CurrentProcess(), vaddr);
230} 230}
231 231
232bool IsKernelVirtualAddress(const VAddr vaddr) { 232bool IsKernelVirtualAddress(const VAddr vaddr) {
@@ -387,7 +387,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
387} 387}
388 388
389void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { 389void 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
393void Write8(const VAddr addr, const u8 data) { 393void 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
452void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { 452void 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
456void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 456void 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
541void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { 541void 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/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;