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.cpp20
-rw-r--r--src/core/core.h8
-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/vfs_libzip.cpp79
-rw-r--r--src/core/file_sys/vfs_libzip.h13
-rw-r--r--src/core/hle/service/acc/acc.cpp14
-rw-r--r--src/core/hle/service/am/am.cpp100
-rw-r--r--src/core/hle/service/am/am.h7
-rw-r--r--src/core/hle/service/am/applet_ae.h2
-rw-r--r--src/core/hle/service/am/applet_oe.h2
-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/aoc/aoc_u.cpp19
-rw-r--r--src/core/hle/service/aoc/aoc_u.h5
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp136
-rw-r--r--src/core/hle/service/bcat/backend/backend.h147
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp503
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.h58
-rw-r--r--src/core/hle/service/bcat/bcat.cpp8
-rw-r--r--src/core/hle/service/bcat/bcat.h3
-rw-r--r--src/core/hle/service/bcat/module.cpp557
-rw-r--r--src/core/hle/service/bcat/module.h24
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp8
-rw-r--r--src/core/hle/service/btdrv/btdrv.h6
-rw-r--r--src/core/hle/service/btm/btm.cpp14
-rw-r--r--src/core/hle/service/btm/btm.h6
-rw-r--r--src/core/hle/service/fatal/fatal.cpp29
-rw-r--r--src/core/hle/service/fatal/fatal.h9
-rw-r--r--src/core/hle/service/fatal/fatal_p.cpp4
-rw-r--r--src/core/hle/service/fatal/fatal_p.h2
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp3
-rw-r--r--src/core/hle/service/fatal/fatal_u.h2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp9
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp31
-rw-r--r--src/core/hle/service/friend/friend.h9
-rw-r--r--src/core/hle/service/friend/interface.cpp4
-rw-r--r--src/core/hle/service/friend/interface.h2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h8
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h3
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h3
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h3
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h8
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h3
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h3
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h3
-rw-r--r--src/core/hle/service/hid/hid.cpp25
-rw-r--r--src/core/hle/service/hid/hid.h10
-rw-r--r--src/core/hle/service/hid/irs.cpp6
-rw-r--r--src/core/hle/service/hid/irs.h3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp11
-rw-r--r--src/core/hle/service/ldr/ldr.h2
-rw-r--r--src/core/hle/service/nfp/nfp.cpp19
-rw-r--r--src/core/hle/service/nfp/nfp.h5
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp4
-rw-r--r--src/core/hle/service/nfp/nfp_user.h2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp43
-rw-r--r--src/core/hle/service/nifm/nifm.h6
-rw-r--r--src/core/hle/service/nim/nim.cpp13
-rw-r--r--src/core/hle/service/nim/nim.h6
-rw-r--r--src/core/hle/service/ns/ns.cpp5
-rw-r--r--src/core/hle/service/ns/ns.h3
-rw-r--r--src/core/hle/service/ns/pl_u.cpp10
-rw-r--r--src/core/hle/service/ns/pl_u.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h5
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp75
-rw-r--r--src/core/hle/service/nvdrv/interface.h3
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h6
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp7
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h5
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp38
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h5
-rw-r--r--src/core/hle/service/prepo/prepo.cpp14
-rw-r--r--src/core/hle/service/prepo/prepo.h6
-rw-r--r--src/core/hle/service/service.cpp28
-rw-r--r--src/core/hle/service/time/interface.cpp4
-rw-r--r--src/core/hle/service/time/interface.h2
-rw-r--r--src/core/hle/service/time/time.cpp25
-rw-r--r--src/core/hle/service/time/time.h4
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp4
-rw-r--r--src/core/hle/service/vi/display/vi_display.h2
-rw-r--r--src/core/loader/nso.cpp1
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h4
115 files changed, 2152 insertions, 355 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a6b56c9c6..3416854db 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
@@ -499,6 +510,15 @@ create_target_directory_groups(core)
499 510
500target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 511target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
501target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives) 512target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt json-headers mbedtls opus unicorn open_source_archives)
513
514if (YUZU_ENABLE_BOXCAT)
515 get_directory_property(OPENSSL_LIBS
516 DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl
517 DEFINITION OPENSSL_LIBS)
518 target_compile_definitions(core PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT -DYUZU_ENABLE_BOXCAT)
519 target_link_libraries(core PRIVATE httplib json-headers ${OPENSSL_LIBS} zip)
520endif()
521
502if (ENABLE_WEB_SERVICE) 522if (ENABLE_WEB_SERVICE)
503 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) 523 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
504 target_link_libraries(core PRIVATE web_service) 524 target_link_libraries(core PRIVATE web_service)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 76bb2bae9..75a7ffb97 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -163,6 +163,7 @@ struct System::Impl {
163 gpu_core = VideoCore::CreateGPU(system); 163 gpu_core = VideoCore::CreateGPU(system);
164 164
165 is_powered_on = true; 165 is_powered_on = true;
166 exit_lock = false;
166 167
167 LOG_DEBUG(Core, "Initialized OK"); 168 LOG_DEBUG(Core, "Initialized OK");
168 169
@@ -249,6 +250,7 @@ struct System::Impl {
249 perf_stats->GetMeanFrametime()); 250 perf_stats->GetMeanFrametime());
250 251
251 is_powered_on = false; 252 is_powered_on = false;
253 exit_lock = false;
252 254
253 // Shutdown emulation session 255 // Shutdown emulation session
254 renderer.reset(); 256 renderer.reset();
@@ -333,9 +335,11 @@ struct System::Impl {
333 std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; 335 std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager;
334 CpuCoreManager cpu_core_manager; 336 CpuCoreManager cpu_core_manager;
335 bool is_powered_on = false; 337 bool is_powered_on = false;
338 bool exit_lock = false;
336 339
337 std::unique_ptr<Memory::CheatEngine> cheat_engine; 340 std::unique_ptr<Memory::CheatEngine> cheat_engine;
338 std::unique_ptr<Tools::Freezer> memory_freezer; 341 std::unique_ptr<Tools::Freezer> memory_freezer;
342 std::array<u8, 0x20> build_id{};
339 343
340 /// Frontend applets 344 /// Frontend applets
341 Service::AM::Applets::AppletManager applet_manager; 345 Service::AM::Applets::AppletManager applet_manager;
@@ -629,6 +633,22 @@ const Service::APM::Controller& System::GetAPMController() const {
629 return impl->apm_controller; 633 return impl->apm_controller;
630} 634}
631 635
636void System::SetExitLock(bool locked) {
637 impl->exit_lock = locked;
638}
639
640bool System::GetExitLock() const {
641 return impl->exit_lock;
642}
643
644void System::SetCurrentProcessBuildID(std::array<u8, 32> id) {
645 impl->build_id = id;
646}
647
648const std::array<u8, 32>& System::GetCurrentProcessBuildID() const {
649 return impl->build_id;
650}
651
632System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 652System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
633 return impl->Init(*this, emu_window); 653 return impl->Init(*this, emu_window);
634} 654}
diff --git a/src/core/core.h b/src/core/core.h
index d2a3c82d8..f49b7fbf9 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -326,6 +326,14 @@ public:
326 326
327 const Service::APM::Controller& GetAPMController() const; 327 const Service::APM::Controller& GetAPMController() const;
328 328
329 void SetExitLock(bool locked);
330
331 bool GetExitLock() const;
332
333 void SetCurrentProcessBuildID(std::array<u8, 0x20> id);
334
335 const std::array<u8, 0x20>& GetCurrentProcessBuildID() const;
336
329private: 337private:
330 System(); 338 System();
331 339
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/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/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index a7c55e116..0c0f7ed6e 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -70,7 +70,7 @@ public:
70 70
71protected: 71protected:
72 void Get(Kernel::HLERequestContext& ctx) { 72 void Get(Kernel::HLERequestContext& ctx) {
73 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 73 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
74 ProfileBase profile_base{}; 74 ProfileBase profile_base{};
75 ProfileData data{}; 75 ProfileData data{};
76 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 76 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
@@ -89,7 +89,7 @@ protected:
89 } 89 }
90 90
91 void GetBase(Kernel::HLERequestContext& ctx) { 91 void GetBase(Kernel::HLERequestContext& ctx) {
92 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 92 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
93 ProfileBase profile_base{}; 93 ProfileBase profile_base{};
94 if (profile_manager.GetProfileBase(user_id, profile_base)) { 94 if (profile_manager.GetProfileBase(user_id, profile_base)) {
95 IPC::ResponseBuilder rb{ctx, 16}; 95 IPC::ResponseBuilder rb{ctx, 16};
@@ -263,7 +263,7 @@ private:
263}; 263};
264 264
265void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { 265void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
266 LOG_INFO(Service_ACC, "called"); 266 LOG_DEBUG(Service_ACC, "called");
267 IPC::ResponseBuilder rb{ctx, 3}; 267 IPC::ResponseBuilder rb{ctx, 3};
268 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
269 rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount())); 269 rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
@@ -272,7 +272,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
272void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { 272void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
273 IPC::RequestParser rp{ctx}; 273 IPC::RequestParser rp{ctx};
274 Common::UUID user_id = rp.PopRaw<Common::UUID>(); 274 Common::UUID user_id = rp.PopRaw<Common::UUID>();
275 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 275 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
276 276
277 IPC::ResponseBuilder rb{ctx, 3}; 277 IPC::ResponseBuilder rb{ctx, 3};
278 rb.Push(RESULT_SUCCESS); 278 rb.Push(RESULT_SUCCESS);
@@ -280,21 +280,21 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
280} 280}
281 281
282void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { 282void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
283 LOG_INFO(Service_ACC, "called"); 283 LOG_DEBUG(Service_ACC, "called");
284 ctx.WriteBuffer(profile_manager->GetAllUsers()); 284 ctx.WriteBuffer(profile_manager->GetAllUsers());
285 IPC::ResponseBuilder rb{ctx, 2}; 285 IPC::ResponseBuilder rb{ctx, 2};
286 rb.Push(RESULT_SUCCESS); 286 rb.Push(RESULT_SUCCESS);
287} 287}
288 288
289void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) { 289void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
290 LOG_INFO(Service_ACC, "called"); 290 LOG_DEBUG(Service_ACC, "called");
291 ctx.WriteBuffer(profile_manager->GetOpenUsers()); 291 ctx.WriteBuffer(profile_manager->GetOpenUsers());
292 IPC::ResponseBuilder rb{ctx, 2}; 292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(RESULT_SUCCESS); 293 rb.Push(RESULT_SUCCESS);
294} 294}
295 295
296void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { 296void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
297 LOG_INFO(Service_ACC, "called"); 297 LOG_DEBUG(Service_ACC, "called");
298 IPC::ResponseBuilder rb{ctx, 6}; 298 IPC::ResponseBuilder rb{ctx, 6};
299 rb.Push(RESULT_SUCCESS); 299 rb.Push(RESULT_SUCCESS);
300 rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser()); 300 rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 6c594dcaf..34409e0c3 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_} {
@@ -232,12 +238,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
232 238
233IDebugFunctions::~IDebugFunctions() = default; 239IDebugFunctions::~IDebugFunctions() = default;
234 240
235ISelfController::ISelfController(Core::System& system_, 241ISelfController::ISelfController(Core::System& system,
236 std::shared_ptr<NVFlinger::NVFlinger> nvflinger_) 242 std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
237 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) { 243 : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) {
238 // clang-format off 244 // clang-format off
239 static const FunctionInfo functions[] = { 245 static const FunctionInfo functions[] = {
240 {0, nullptr, "Exit"}, 246 {0, &ISelfController::Exit, "Exit"},
241 {1, &ISelfController::LockExit, "LockExit"}, 247 {1, &ISelfController::LockExit, "LockExit"},
242 {2, &ISelfController::UnlockExit, "UnlockExit"}, 248 {2, &ISelfController::UnlockExit, "UnlockExit"},
243 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, 249 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
@@ -282,7 +288,7 @@ ISelfController::ISelfController(Core::System& system_,
282 288
283 RegisterHandlers(functions); 289 RegisterHandlers(functions);
284 290
285 auto& kernel = system_.Kernel(); 291 auto& kernel = system.Kernel();
286 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 292 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
287 "ISelfController:LaunchableEvent"); 293 "ISelfController:LaunchableEvent");
288 294
@@ -298,15 +304,28 @@ ISelfController::ISelfController(Core::System& system_,
298 304
299ISelfController::~ISelfController() = default; 305ISelfController::~ISelfController() = default;
300 306
307void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
308 LOG_DEBUG(Service_AM, "called");
309
310 system.Shutdown();
311
312 IPC::ResponseBuilder rb{ctx, 2};
313 rb.Push(RESULT_SUCCESS);
314}
315
301void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { 316void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
302 LOG_WARNING(Service_AM, "(STUBBED) called"); 317 LOG_DEBUG(Service_AM, "called");
318
319 system.SetExitLock(true);
303 320
304 IPC::ResponseBuilder rb{ctx, 2}; 321 IPC::ResponseBuilder rb{ctx, 2};
305 rb.Push(RESULT_SUCCESS); 322 rb.Push(RESULT_SUCCESS);
306} 323}
307 324
308void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { 325void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
309 LOG_WARNING(Service_AM, "(STUBBED) called"); 326 LOG_DEBUG(Service_AM, "called");
327
328 system.SetExitLock(false);
310 329
311 IPC::ResponseBuilder rb{ctx, 2}; 330 IPC::ResponseBuilder rb{ctx, 2};
312 rb.Push(RESULT_SUCCESS); 331 rb.Push(RESULT_SUCCESS);
@@ -550,6 +569,10 @@ void AppletMessageQueue::OperationModeChanged() {
550 on_operation_mode_changed.writable->Signal(); 569 on_operation_mode_changed.writable->Signal();
551} 570}
552 571
572void AppletMessageQueue::RequestExit() {
573 PushMessage(AppletMessage::ExitRequested);
574}
575
553ICommonStateGetter::ICommonStateGetter(Core::System& system, 576ICommonStateGetter::ICommonStateGetter(Core::System& system,
554 std::shared_ptr<AppletMessageQueue> msg_queue) 577 std::shared_ptr<AppletMessageQueue> msg_queue)
555 : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { 578 : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {
@@ -1066,7 +1089,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1066 1089
1067 RegisterHandlers(functions); 1090 RegisterHandlers(functions);
1068 1091
1069 auto& kernel = Core::System::GetInstance().Kernel(); 1092 auto& kernel = system.Kernel();
1070 gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( 1093 gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair(
1071 kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); 1094 kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
1072} 1095}
@@ -1111,26 +1134,55 @@ void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx
1111} 1134}
1112 1135
1113void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 1136void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1114 LOG_DEBUG(Service_AM, "called"); 1137 IPC::RequestParser rp{ctx};
1138 const auto kind = rp.PopEnum<LaunchParameterKind>();
1115 1139
1116 LaunchParameters params{}; 1140 LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind));
1117 1141
1118 params.magic = POP_LAUNCH_PARAMETER_MAGIC; 1142 if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) {
1119 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 = Core::System::GetInstance().GetCurrentProcessBuildID();
1146 u64 build_id{};
1147 std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
1120 1148
1121 Account::ProfileManager profile_manager{}; 1149 const auto data =
1122 const auto uuid = profile_manager.GetUser(Settings::values.current_user); 1150 backend->GetLaunchParameter({Core::CurrentProcess()->GetTitleID(), build_id});
1123 ASSERT(uuid);
1124 params.current_user = uuid->uuid;
1125 1151
1126 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{};
1127 1162
1128 rb.Push(RESULT_SUCCESS); 1163 params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC;
1164 params.is_account_selected = 1;
1165
1166 Account::ProfileManager profile_manager{};
1167 const auto uuid = profile_manager.GetUser(Settings::values.current_user);
1168 ASSERT(uuid);
1169 params.current_user = uuid->uuid;
1129 1170
1130 std::vector<u8> buffer(sizeof(LaunchParameters)); 1171 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1131 std::memcpy(buffer.data(), &params, buffer.size()); 1172
1173 rb.Push(RESULT_SUCCESS);
1174
1175 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
1176 std::memcpy(buffer.data(), &params, buffer.size());
1132 1177
1133 rb.PushIpcInterface<AM::IStorage>(buffer); 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);
1134} 1186}
1135 1187
1136void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( 1188void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 28f870302..9169eb2bd 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -45,6 +45,7 @@ class AppletMessageQueue {
45public: 45public:
46 enum class AppletMessage : u32 { 46 enum class AppletMessage : u32 {
47 NoMessage = 0, 47 NoMessage = 0,
48 ExitRequested = 4,
48 FocusStateChanged = 15, 49 FocusStateChanged = 15,
49 OperationModeChanged = 30, 50 OperationModeChanged = 30,
50 PerformanceModeChanged = 31, 51 PerformanceModeChanged = 31,
@@ -59,6 +60,7 @@ public:
59 AppletMessage PopMessage(); 60 AppletMessage PopMessage();
60 std::size_t GetMessageCount() const; 61 std::size_t GetMessageCount() const;
61 void OperationModeChanged(); 62 void OperationModeChanged();
63 void RequestExit();
62 64
63private: 65private:
64 std::queue<AppletMessage> messages; 66 std::queue<AppletMessage> messages;
@@ -123,6 +125,7 @@ public:
123 ~ISelfController() override; 125 ~ISelfController() override;
124 126
125private: 127private:
128 void Exit(Kernel::HLERequestContext& ctx);
126 void LockExit(Kernel::HLERequestContext& ctx); 129 void LockExit(Kernel::HLERequestContext& ctx);
127 void UnlockExit(Kernel::HLERequestContext& ctx); 130 void UnlockExit(Kernel::HLERequestContext& ctx);
128 void EnterFatalSection(Kernel::HLERequestContext& ctx); 131 void EnterFatalSection(Kernel::HLERequestContext& ctx);
@@ -151,6 +154,8 @@ private:
151 u32 idle_time_detection_extension = 0; 154 u32 idle_time_detection_extension = 0;
152 u64 num_fatal_sections_entered = 0; 155 u64 num_fatal_sections_entered = 0;
153 bool is_auto_sleep_disabled = false; 156 bool is_auto_sleep_disabled = false;
157
158 Core::System& system;
154}; 159};
155 160
156class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 161class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
@@ -250,6 +255,8 @@ private:
250 void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); 255 void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
251 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); 256 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
252 257
258 bool launch_popped_application_specific = false;
259 bool launch_popped_account_preselect = false;
253 Kernel::EventPair gpu_error_detected_event; 260 Kernel::EventPair gpu_error_detected_event;
254 Core::System& system; 261 Core::System& system;
255}; 262};
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 0e0d10858..2e3e45915 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -19,6 +19,8 @@ class NVFlinger;
19 19
20namespace AM { 20namespace AM {
21 21
22class AppletMessageQueue;
23
22class AppletAE final : public ServiceFramework<AppletAE> { 24class AppletAE final : public ServiceFramework<AppletAE> {
23public: 25public:
24 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 26 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 99a65e7b5..758da792d 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -19,6 +19,8 @@ class NVFlinger;
19 19
20namespace AM { 20namespace AM {
21 21
22class AppletMessageQueue;
23
22class AppletOE final : public ServiceFramework<AppletOE> { 24class AppletOE final : public ServiceFramework<AppletOE> {
23public: 25public:
24 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 26 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
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/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index d3e97776b..e9cf1e840 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -29,9 +29,9 @@ static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
29 return (title_id & DLC_BASE_TITLE_ID_MASK) == base; 29 return (title_id & DLC_BASE_TITLE_ID_MASK) == base;
30} 30}
31 31
32static std::vector<u64> AccumulateAOCTitleIDs() { 32static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
33 std::vector<u64> add_on_content; 33 std::vector<u64> add_on_content;
34 const auto& rcu = Core::System::GetInstance().GetContentProvider(); 34 const auto& rcu = system.GetContentProvider();
35 const auto list = 35 const auto list =
36 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 36 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
37 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), 37 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
@@ -47,7 +47,8 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
47 return add_on_content; 47 return add_on_content;
48} 48}
49 49
50AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) { 50AOC_U::AOC_U(Core::System& system)
51 : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) {
51 // clang-format off 52 // clang-format off
52 static const FunctionInfo functions[] = { 53 static const FunctionInfo functions[] = {
53 {0, nullptr, "CountAddOnContentByApplicationId"}, 54 {0, nullptr, "CountAddOnContentByApplicationId"},
@@ -65,7 +66,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
65 66
66 RegisterHandlers(functions); 67 RegisterHandlers(functions);
67 68
68 auto& kernel = Core::System::GetInstance().Kernel(); 69 auto& kernel = system.Kernel();
69 aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 70 aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
70 "GetAddOnContentListChanged:Event"); 71 "GetAddOnContentListChanged:Event");
71} 72}
@@ -86,7 +87,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
86 IPC::ResponseBuilder rb{ctx, 3}; 87 IPC::ResponseBuilder rb{ctx, 3};
87 rb.Push(RESULT_SUCCESS); 88 rb.Push(RESULT_SUCCESS);
88 89
89 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 90 const auto current = system.CurrentProcess()->GetTitleID();
90 91
91 const auto& disabled = Settings::values.disabled_addons[current]; 92 const auto& disabled = Settings::values.disabled_addons[current];
92 if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { 93 if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -113,7 +114,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
113 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, 114 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
114 process_id); 115 process_id);
115 116
116 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 117 const auto current = system.CurrentProcess()->GetTitleID();
117 118
118 std::vector<u32> out; 119 std::vector<u32> out;
119 const auto& disabled = Settings::values.disabled_addons[current]; 120 const auto& disabled = Settings::values.disabled_addons[current];
@@ -159,7 +160,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
159 IPC::ResponseBuilder rb{ctx, 4}; 160 IPC::ResponseBuilder rb{ctx, 4};
160 rb.Push(RESULT_SUCCESS); 161 rb.Push(RESULT_SUCCESS);
161 162
162 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 163 const auto title_id = system.CurrentProcess()->GetTitleID();
163 FileSys::PatchManager pm{title_id}; 164 FileSys::PatchManager pm{title_id};
164 165
165 const auto res = pm.GetControlMetadata(); 166 const auto res = pm.GetControlMetadata();
@@ -196,8 +197,8 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
196 rb.PushCopyObjects(aoc_change_event.readable); 197 rb.PushCopyObjects(aoc_change_event.readable);
197} 198}
198 199
199void InstallInterfaces(SM::ServiceManager& service_manager) { 200void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
200 std::make_shared<AOC_U>()->InstallAsService(service_manager); 201 std::make_shared<AOC_U>(system)->InstallAsService(service_manager);
201} 202}
202 203
203} // namespace Service::AOC 204} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 5effea730..848b2f416 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -14,7 +14,7 @@ namespace Service::AOC {
14 14
15class AOC_U final : public ServiceFramework<AOC_U> { 15class AOC_U final : public ServiceFramework<AOC_U> {
16public: 16public:
17 AOC_U(); 17 explicit AOC_U(Core::System& system);
18 ~AOC_U() override; 18 ~AOC_U() override;
19 19
20private: 20private:
@@ -26,9 +26,10 @@ private:
26 26
27 std::vector<u64> add_on_content; 27 std::vector<u64> add_on_content;
28 Kernel::EventPair aoc_change_event; 28 Kernel::EventPair aoc_change_event;
29 Core::System& system;
29}; 30};
30 31
31/// Registers all AOC services with the specified service manager. 32/// Registers all AOC services with the specified service manager.
32void InstallInterfaces(SM::ServiceManager& service_manager); 33void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
33 34
34} // namespace Service::AOC 35} // namespace Service::AOC
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..9b677debe
--- /dev/null
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -0,0 +1,136 @@
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 event_name) : impl{} {
14 auto& kernel{Core::System::GetInstance().Kernel()};
15 event = Kernel::WritableEvent::CreateEventPair(
16 kernel, Kernel::ResetType::Automatic, "ProgressServiceBackend:UpdateEvent:" + event_name);
17}
18
19Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() {
20 return event.readable;
21}
22
23DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
24 return impl;
25}
26
27void ProgressServiceBackend::SetNeedHLELock(bool need) {
28 need_hle_lock = need;
29}
30
31void ProgressServiceBackend::SetTotalSize(u64 size) {
32 impl.total_bytes = size;
33 SignalUpdate();
34}
35
36void ProgressServiceBackend::StartConnecting() {
37 impl.status = DeliveryCacheProgressImpl::Status::Connecting;
38 SignalUpdate();
39}
40
41void ProgressServiceBackend::StartProcessingDataList() {
42 impl.status = DeliveryCacheProgressImpl::Status::ProcessingDataList;
43 SignalUpdate();
44}
45
46void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name,
47 std::string_view file_name, u64 file_size) {
48 impl.status = DeliveryCacheProgressImpl::Status::Downloading;
49 impl.current_downloaded_bytes = 0;
50 impl.current_total_bytes = file_size;
51 std::memcpy(impl.current_directory.data(), dir_name.data(),
52 std::min<u64>(dir_name.size(), 0x31ull));
53 std::memcpy(impl.current_file.data(), file_name.data(),
54 std::min<u64>(file_name.size(), 0x31ull));
55 SignalUpdate();
56}
57
58void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) {
59 impl.current_downloaded_bytes = downloaded;
60 SignalUpdate();
61}
62
63void ProgressServiceBackend::FinishDownloadingFile() {
64 impl.total_downloaded_bytes += impl.current_total_bytes;
65 SignalUpdate();
66}
67
68void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) {
69 impl.status = DeliveryCacheProgressImpl::Status::Committing;
70 impl.current_file.fill(0);
71 impl.current_downloaded_bytes = 0;
72 impl.current_total_bytes = 0;
73 std::memcpy(impl.current_directory.data(), dir_name.data(),
74 std::min<u64>(dir_name.size(), 0x31ull));
75 SignalUpdate();
76}
77
78void ProgressServiceBackend::FinishDownload(ResultCode result) {
79 impl.total_downloaded_bytes = impl.total_bytes;
80 impl.status = DeliveryCacheProgressImpl::Status::Done;
81 impl.result = result;
82 SignalUpdate();
83}
84
85void ProgressServiceBackend::SignalUpdate() const {
86 if (need_hle_lock) {
87 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
88 event.writable->Signal();
89 } else {
90 event.writable->Signal();
91 }
92}
93
94Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}
95
96Backend::~Backend() = default;
97
98NullBackend::NullBackend(const DirectoryGetter& getter) : Backend(std::move(getter)) {}
99
100NullBackend::~NullBackend() = default;
101
102bool NullBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
103 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
104 title.build_id);
105
106 progress.FinishDownload(RESULT_SUCCESS);
107 return true;
108}
109
110bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
111 ProgressServiceBackend& progress) {
112 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id,
113 title.build_id, name);
114
115 progress.FinishDownload(RESULT_SUCCESS);
116 return true;
117}
118
119bool NullBackend::Clear(u64 title_id) {
120 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}");
121
122 return true;
123}
124
125void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
126 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id,
127 Common::HexToString(passphrase));
128}
129
130std::optional<std::vector<u8>> NullBackend::GetLaunchParameter(TitleIDVersion title) {
131 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
132 title.build_id);
133 return std::nullopt;
134}
135
136} // 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..3f5d8b5dd
--- /dev/null
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -0,0 +1,147 @@
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 "common/common_types.h"
10#include "core/file_sys/vfs_types.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
13#include "core/hle/result.h"
14
15namespace Service::BCAT {
16
17struct DeliveryCacheProgressImpl;
18
19using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>;
20using Passphrase = std::array<u8, 0x20>;
21
22struct TitleIDVersion {
23 u64 title_id;
24 u64 build_id;
25};
26
27using DirectoryName = std::array<char, 0x20>;
28using FileName = std::array<char, 0x20>;
29
30struct DeliveryCacheProgressImpl {
31 enum class Status : s32 {
32 None = 0x0,
33 Queued = 0x1,
34 Connecting = 0x2,
35 ProcessingDataList = 0x3,
36 Downloading = 0x4,
37 Committing = 0x5,
38 Done = 0x9,
39 };
40
41 Status status;
42 ResultCode result = RESULT_SUCCESS;
43 DirectoryName current_directory;
44 FileName current_file;
45 s64 current_downloaded_bytes; ///< Bytes downloaded on current file.
46 s64 current_total_bytes; ///< Bytes total on current file.
47 s64 total_downloaded_bytes; ///< Bytes downloaded on overall download.
48 s64 total_bytes; ///< Bytes total on overall download.
49 INSERT_PADDING_BYTES(
50 0x198); ///< Appears to be unused in official code, possibly reserved for future use.
51};
52static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200,
53 "DeliveryCacheProgressImpl has incorrect size.");
54
55// A class to manage the signalling to the game about BCAT download progress.
56// Some of this class is implemented in module.cpp to avoid exposing the implementation structure.
57class ProgressServiceBackend {
58 friend class IBcatService;
59
60public:
61 // Clients should call this with true if any of the functions are going to be called from a
62 // non-HLE thread and this class need to lock the hle mutex. (default is false)
63 void SetNeedHLELock(bool need);
64
65 // Sets the number of bytes total in the entire download.
66 void SetTotalSize(u64 size);
67
68 // Notifies the application that the backend has started connecting to the server.
69 void StartConnecting();
70 // Notifies the application that the backend has begun accumulating and processing metadata.
71 void StartProcessingDataList();
72
73 // Notifies the application that a file is starting to be downloaded.
74 void StartDownloadingFile(std::string_view dir_name, std::string_view file_name, u64 file_size);
75 // Updates the progress of the current file to the size passed.
76 void UpdateFileProgress(u64 downloaded);
77 // Notifies the application that the current file has completed download.
78 void FinishDownloadingFile();
79
80 // Notifies the application that all files in this directory have completed and are being
81 // finalized.
82 void CommitDirectory(std::string_view dir_name);
83
84 // Notifies the application that the operation completed with result code result.
85 void FinishDownload(ResultCode result);
86
87private:
88 explicit ProgressServiceBackend(std::string event_name);
89
90 Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent();
91 DeliveryCacheProgressImpl& GetImpl();
92
93 void SignalUpdate() const;
94
95 DeliveryCacheProgressImpl impl;
96 Kernel::EventPair event;
97 bool need_hle_lock = false;
98};
99
100// A class representing an abstract backend for BCAT functionality.
101class Backend {
102public:
103 explicit Backend(DirectoryGetter getter);
104 virtual ~Backend();
105
106 // Called when the backend is needed to synchronize the data for the game with title ID and
107 // version in title. A ProgressServiceBackend object is provided to alert the application of
108 // status.
109 virtual bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) = 0;
110 // Very similar to Synchronize, but only for the directory provided. Backends should not alter
111 // the data for any other directories.
112 virtual bool SynchronizeDirectory(TitleIDVersion title, std::string name,
113 ProgressServiceBackend& progress) = 0;
114
115 // Removes all cached data associated with title id provided.
116 virtual bool Clear(u64 title_id) = 0;
117
118 // Sets the BCAT Passphrase to be used with the associated title ID.
119 virtual void SetPassphrase(u64 title_id, const Passphrase& passphrase) = 0;
120
121 // Gets the launch parameter used by AM associated with the title ID and version provided.
122 virtual std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) = 0;
123
124protected:
125 DirectoryGetter dir_getter;
126};
127
128// A backend of BCAT that provides no operation.
129class NullBackend : public Backend {
130public:
131 explicit NullBackend(const DirectoryGetter& getter);
132 ~NullBackend() override;
133
134 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
135 bool SynchronizeDirectory(TitleIDVersion title, std::string name,
136 ProgressServiceBackend& progress) override;
137
138 bool Clear(u64 title_id) override;
139
140 void SetPassphrase(u64 title_id, const Passphrase& passphrase) override;
141
142 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
143};
144
145std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter);
146
147} // 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..e6ee0810b
--- /dev/null
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -0,0 +1,503 @@
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;
91constexpr 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& e) {
499 return StatusResult::ParseError;
500 }
501}
502
503} // 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..c2f946424 100644
--- a/src/core/hle/service/bcat/bcat.cpp
+++ b/src/core/hle/service/bcat/bcat.cpp
@@ -6,11 +6,15 @@
6 6
7namespace Service::BCAT { 7namespace Service::BCAT {
8 8
9BCAT::BCAT(std::shared_ptr<Module> module, const char* name) 9BCAT::BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc, const char* name)
10 : Module::Interface(std::move(module), name) { 10 : Module::Interface(std::move(module), fsc, name) {
11 // clang-format off
11 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
12 {0, &BCAT::CreateBcatService, "CreateBcatService"}, 13 {0, &BCAT::CreateBcatService, "CreateBcatService"},
14 {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"},
15 {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"},
13 }; 16 };
17 // clang-format on
14 RegisterHandlers(functions); 18 RegisterHandlers(functions);
15} 19}
16 20
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h
index 802bd689a..813073658 100644
--- a/src/core/hle/service/bcat/bcat.h
+++ b/src/core/hle/service/bcat/bcat.h
@@ -10,7 +10,8 @@ namespace Service::BCAT {
10 10
11class BCAT final : public Module::Interface { 11class BCAT final : public Module::Interface {
12public: 12public:
13 explicit BCAT(std::shared_ptr<Module> module, const char* name); 13 explicit BCAT(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc,
14 const char* name);
14 ~BCAT() override; 15 ~BCAT() override;
15}; 16};
16 17
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index b7bd738fc..b3fed56c7 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -2,34 +2,254 @@
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() {
39 const auto& id = Core::System::GetInstance().GetCurrentProcessBuildID();
40 u64 out{};
41 std::memcpy(&out, id.data(), sizeof(u64));
42 return out;
43}
44
45// The digest is only used to determine if a file is unique compared to others of the same name.
46// Since the algorithm isn't ever checked in game, MD5 is safe.
47BCATDigest DigestFile(const FileSys::VirtualFile& file) {
48 BCATDigest out{};
49 const auto bytes = file->ReadAllBytes();
50 mbedtls_md5(bytes.data(), bytes.size(), out.data());
51 return out;
52}
53
54// For a name to be valid it must be non-empty, must have a null terminating character as the final
55// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if
56// file.
57bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x20> name,
58 char match_char) {
59 const auto null_chars = std::count(name.begin(), name.end(), 0);
60 const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) {
61 return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0';
62 });
63 if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') {
64 LOG_ERROR(Service_BCAT, "Name passed was invalid!");
65 IPC::ResponseBuilder rb{ctx, 2};
66 rb.Push(ERROR_INVALID_ARGUMENT);
67 return false;
68 }
69
70 return true;
71}
72
73bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) {
74 return VerifyNameValidInternal(ctx, name, '-');
75}
76
77bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) {
78 return VerifyNameValidInternal(ctx, name, '.');
79}
80
81} // Anonymous namespace
82
83struct DeliveryCacheDirectoryEntry {
84 FileName name;
85 u64 size;
86 BCATDigest digest;
87};
88
89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
90public:
91 IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event,
92 const DeliveryCacheProgressImpl& impl)
93 : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) {
94 // clang-format off
95 static const FunctionInfo functions[] = {
96 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"},
97 {1, &IDeliveryCacheProgressService::GetImpl, "GetImpl"},
98 };
99 // clang-format on
100
101 RegisterHandlers(functions);
102 }
103
104private:
105 void GetEvent(Kernel::HLERequestContext& ctx) {
106 LOG_DEBUG(Service_BCAT, "called");
107
108 IPC::ResponseBuilder rb{ctx, 2, 1};
109 rb.Push(RESULT_SUCCESS);
110 rb.PushCopyObjects(event);
111 }
112
113 void GetImpl(Kernel::HLERequestContext& ctx) {
114 LOG_DEBUG(Service_BCAT, "called");
115
116 ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl));
117
118 IPC::ResponseBuilder rb{ctx, 2};
119 rb.Push(RESULT_SUCCESS);
120 }
121
122 Kernel::SharedPtr<Kernel::ReadableEvent> event;
123 const DeliveryCacheProgressImpl& impl;
124};
125
12class IBcatService final : public ServiceFramework<IBcatService> { 126class IBcatService final : public ServiceFramework<IBcatService> {
13public: 127public:
14 IBcatService() : ServiceFramework("IBcatService") { 128 IBcatService(Backend& backend) : ServiceFramework("IBcatService"), 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({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()},
167 progress.at(static_cast<std::size_t>(SyncType::Normal)));
168
169 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
170 rb.Push(RESULT_SUCCESS);
171 rb.PushIpcInterface(CreateProgressService(SyncType::Normal));
172 }
173
174 void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) {
175 IPC::RequestParser rp{ctx};
176 const auto name_raw = rp.PopRaw<DirectoryName>();
177 const auto name =
178 Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
179
180 LOG_DEBUG(Service_BCAT, "called, name={}", name);
181
182 backend.SynchronizeDirectory({Core::CurrentProcess()->GetTitleID(), GetCurrentBuildID()},
183 name,
184 progress.at(static_cast<std::size_t>(SyncType::Directory)));
185
186 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
187 rb.Push(RESULT_SUCCESS);
188 rb.PushIpcInterface(CreateProgressService(SyncType::Directory));
189 }
190
191 void SetPassphrase(Kernel::HLERequestContext& ctx) {
192 IPC::RequestParser rp{ctx};
193 const auto title_id = rp.PopRaw<u64>();
194
195 const auto passphrase_raw = ctx.ReadBuffer();
196
197 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
198 Common::HexToString(passphrase_raw));
199
200 if (title_id == 0) {
201 LOG_ERROR(Service_BCAT, "Invalid title ID!");
202 IPC::ResponseBuilder rb{ctx, 2};
203 rb.Push(ERROR_INVALID_ARGUMENT);
204 }
205
206 if (passphrase_raw.size() > 0x40) {
207 LOG_ERROR(Service_BCAT, "Passphrase too large!");
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(ERROR_INVALID_ARGUMENT);
210 return;
211 }
212
213 Passphrase passphrase{};
214 std::memcpy(passphrase.data(), passphrase_raw.data(),
215 std::min(passphrase.size(), passphrase_raw.size()));
216
217 backend.SetPassphrase(title_id, passphrase);
218
219 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(RESULT_SUCCESS);
221 }
222
223 void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) {
224 IPC::RequestParser rp{ctx};
225 const auto title_id = rp.PopRaw<u64>();
226
227 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
228
229 if (title_id == 0) {
230 LOG_ERROR(Service_BCAT, "Invalid title ID!");
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(ERROR_INVALID_ARGUMENT);
233 return;
234 }
235
236 if (!backend.Clear(title_id)) {
237 LOG_ERROR(Service_BCAT, "Could not clear the directory successfully!");
238 IPC::ResponseBuilder rb{ctx, 2};
239 rb.Push(ERROR_FAILED_CLEAR_CACHE);
240 return;
241 }
242
243 IPC::ResponseBuilder rb{ctx, 2};
244 rb.Push(RESULT_SUCCESS);
245 }
246
247 Backend& backend;
248
249 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress{
250 ProgressServiceBackend{"Normal"},
251 ProgressServiceBackend{"Directory"},
252 };
33}; 253};
34 254
35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 255void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
@@ -37,20 +257,331 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
37 257
38 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 258 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
39 rb.Push(RESULT_SUCCESS); 259 rb.Push(RESULT_SUCCESS);
40 rb.PushIpcInterface<IBcatService>(); 260 rb.PushIpcInterface<IBcatService>(*backend);
261}
262
263class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
264public:
265 IDeliveryCacheFileService(FileSys::VirtualDir root_)
266 : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) {
267 // clang-format off
268 static const FunctionInfo functions[] = {
269 {0, &IDeliveryCacheFileService::Open, "Open"},
270 {1, &IDeliveryCacheFileService::Read, "Read"},
271 {2, &IDeliveryCacheFileService::GetSize, "GetSize"},
272 {3, &IDeliveryCacheFileService::GetDigest, "GetDigest"},
273 };
274 // clang-format on
275
276 RegisterHandlers(functions);
277 }
278
279private:
280 void Open(Kernel::HLERequestContext& ctx) {
281 IPC::RequestParser rp{ctx};
282 const auto dir_name_raw = rp.PopRaw<DirectoryName>();
283 const auto file_name_raw = rp.PopRaw<FileName>();
284
285 const auto dir_name =
286 Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
287 const auto file_name =
288 Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size());
289
290 LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name);
291
292 if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw))
293 return;
294
295 if (current_file != nullptr) {
296 LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!");
297 IPC::ResponseBuilder rb{ctx, 2};
298 rb.Push(ERROR_ENTITY_ALREADY_OPEN);
299 return;
300 }
301
302 const auto dir = root->GetSubdirectory(dir_name);
303
304 if (dir == nullptr) {
305 LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name);
306 IPC::ResponseBuilder rb{ctx, 2};
307 rb.Push(ERROR_FAILED_OPEN_ENTITY);
308 return;
309 }
310
311 current_file = dir->GetFile(file_name);
312
313 if (current_file == nullptr) {
314 LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_name);
315 IPC::ResponseBuilder rb{ctx, 2};
316 rb.Push(ERROR_FAILED_OPEN_ENTITY);
317 return;
318 }
319
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(RESULT_SUCCESS);
322 }
323
324 void Read(Kernel::HLERequestContext& ctx) {
325 IPC::RequestParser rp{ctx};
326 const auto offset{rp.PopRaw<u64>()};
327
328 auto size = ctx.GetWriteBufferSize();
329
330 LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size);
331
332 if (current_file == nullptr) {
333 LOG_ERROR(Service_BCAT, "There is no file currently open!");
334 IPC::ResponseBuilder rb{ctx, 2};
335 rb.Push(ERROR_NO_OPEN_ENTITY);
336 }
337
338 size = std::min<u64>(current_file->GetSize() - offset, size);
339 const auto buffer = current_file->ReadBytes(size, offset);
340 ctx.WriteBuffer(buffer);
341
342 IPC::ResponseBuilder rb{ctx, 4};
343 rb.Push(RESULT_SUCCESS);
344 rb.Push<u64>(buffer.size());
345 }
346
347 void GetSize(Kernel::HLERequestContext& ctx) {
348 LOG_DEBUG(Service_BCAT, "called");
349
350 if (current_file == nullptr) {
351 LOG_ERROR(Service_BCAT, "There is no file currently open!");
352 IPC::ResponseBuilder rb{ctx, 2};
353 rb.Push(ERROR_NO_OPEN_ENTITY);
354 }
355
356 IPC::ResponseBuilder rb{ctx, 4};
357 rb.Push(RESULT_SUCCESS);
358 rb.Push<u64>(current_file->GetSize());
359 }
360
361 void GetDigest(Kernel::HLERequestContext& ctx) {
362 LOG_DEBUG(Service_BCAT, "called");
363
364 if (current_file == nullptr) {
365 LOG_ERROR(Service_BCAT, "There is no file currently open!");
366 IPC::ResponseBuilder rb{ctx, 2};
367 rb.Push(ERROR_NO_OPEN_ENTITY);
368 }
369
370 IPC::ResponseBuilder rb{ctx, 6};
371 rb.Push(RESULT_SUCCESS);
372 rb.PushRaw(DigestFile(current_file));
373 }
374
375 FileSys::VirtualDir root;
376 FileSys::VirtualFile current_file;
377};
378
379class IDeliveryCacheDirectoryService final
380 : public ServiceFramework<IDeliveryCacheDirectoryService> {
381public:
382 IDeliveryCacheDirectoryService(FileSys::VirtualDir root_)
383 : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) {
384 // clang-format off
385 static const FunctionInfo functions[] = {
386 {0, &IDeliveryCacheDirectoryService::Open, "Open"},
387 {1, &IDeliveryCacheDirectoryService::Read, "Read"},
388 {2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"},
389 };
390 // clang-format on
391
392 RegisterHandlers(functions);
393 }
394
395private:
396 void Open(Kernel::HLERequestContext& ctx) {
397 IPC::RequestParser rp{ctx};
398 const auto name_raw = rp.PopRaw<DirectoryName>();
399 const auto name =
400 Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());
401
402 LOG_DEBUG(Service_BCAT, "called, name={}", name);
403
404 if (!VerifyNameValidDir(ctx, name_raw))
405 return;
406
407 if (current_dir != nullptr) {
408 LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!");
409 IPC::ResponseBuilder rb{ctx, 2};
410 rb.Push(ERROR_ENTITY_ALREADY_OPEN);
411 return;
412 }
413
414 current_dir = root->GetSubdirectory(name);
415
416 if (current_dir == nullptr) {
417 LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name);
418 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(ERROR_FAILED_OPEN_ENTITY);
420 return;
421 }
422
423 IPC::ResponseBuilder rb{ctx, 2};
424 rb.Push(RESULT_SUCCESS);
425 }
426
427 void Read(Kernel::HLERequestContext& ctx) {
428 auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry);
429
430 LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size);
431
432 if (current_dir == nullptr) {
433 LOG_ERROR(Service_BCAT, "There is no open directory!");
434 IPC::ResponseBuilder rb{ctx, 2};
435 rb.Push(ERROR_NO_OPEN_ENTITY);
436 return;
437 }
438
439 const auto files = current_dir->GetFiles();
440 write_size = std::min<u64>(write_size, files.size());
441 std::vector<DeliveryCacheDirectoryEntry> entries(write_size);
442 std::transform(
443 files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) {
444 FileName name{};
445 std::memcpy(name.data(), file->GetName().data(),
446 std::min(file->GetName().size(), name.size()));
447 return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)};
448 });
449
450 ctx.WriteBuffer(entries);
451
452 IPC::ResponseBuilder rb{ctx, 3};
453 rb.Push(RESULT_SUCCESS);
454 rb.Push<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry));
455 }
456
457 void GetCount(Kernel::HLERequestContext& ctx) {
458 LOG_DEBUG(Service_BCAT, "called");
459
460 if (current_dir == nullptr) {
461 LOG_ERROR(Service_BCAT, "There is no open directory!");
462 IPC::ResponseBuilder rb{ctx, 2};
463 rb.Push(ERROR_NO_OPEN_ENTITY);
464 return;
465 }
466
467 const auto files = current_dir->GetFiles();
468
469 IPC::ResponseBuilder rb{ctx, 3};
470 rb.Push(RESULT_SUCCESS);
471 rb.Push<u32>(files.size());
472 }
473
474 FileSys::VirtualDir root;
475 FileSys::VirtualDir current_dir;
476};
477
478class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
479public:
480 IDeliveryCacheStorageService(FileSys::VirtualDir root_)
481 : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) {
482 // clang-format off
483 static const FunctionInfo functions[] = {
484 {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"},
485 {1, &IDeliveryCacheStorageService::CreateDirectoryService, "CreateDirectoryService"},
486 {10, &IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory, "EnumerateDeliveryCacheDirectory"},
487 };
488 // clang-format on
489
490 RegisterHandlers(functions);
491
492 for (const auto& subdir : root->GetSubdirectories()) {
493 DirectoryName name{};
494 std::memcpy(name.data(), subdir->GetName().data(),
495 std::min(sizeof(DirectoryName) - 1, subdir->GetName().size()));
496 entries.push_back(name);
497 }
498 }
499
500private:
501 void CreateFileService(Kernel::HLERequestContext& ctx) {
502 LOG_DEBUG(Service_BCAT, "called");
503
504 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
505 rb.Push(RESULT_SUCCESS);
506 rb.PushIpcInterface<IDeliveryCacheFileService>(root);
507 }
508
509 void CreateDirectoryService(Kernel::HLERequestContext& ctx) {
510 LOG_DEBUG(Service_BCAT, "called");
511
512 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
513 rb.Push(RESULT_SUCCESS);
514 rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root);
515 }
516
517 void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) {
518 auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName);
519
520 LOG_DEBUG(Service_BCAT, "called, size={:016X}", size);
521
522 size = std::min<u64>(size, entries.size() - next_read_index);
523 ctx.WriteBuffer(entries.data() + next_read_index, size * sizeof(DirectoryName));
524 next_read_index += size;
525
526 IPC::ResponseBuilder rb{ctx, 3};
527 rb.Push(RESULT_SUCCESS);
528 rb.Push<u32>(size);
529 }
530
531 FileSys::VirtualDir root;
532 std::vector<DirectoryName> entries;
533 u64 next_read_index = 0;
534};
535
536void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) {
537 LOG_DEBUG(Service_BCAT, "called");
538
539 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
540 rb.Push(RESULT_SUCCESS);
541 rb.PushIpcInterface<IDeliveryCacheStorageService>(
542 fsc.GetBCATDirectory(Core::CurrentProcess()->GetTitleID()));
543}
544
545void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
546 Kernel::HLERequestContext& ctx) {
547 IPC::RequestParser rp{ctx};
548 const auto title_id = rp.PopRaw<u64>();
549
550 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
551
552 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
553 rb.Push(RESULT_SUCCESS);
554 rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id));
555}
556
557std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) {
558 const auto backend = Settings::values.bcat_backend;
559
560#ifdef YUZU_ENABLE_BOXCAT
561 if (backend == "boxcat")
562 return std::make_unique<Boxcat>(std::move(getter));
563#endif
564
565 return std::make_unique<NullBackend>(std::move(getter));
41} 566}
42 567
43Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 568Module::Interface::Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc,
44 : ServiceFramework(name), module(std::move(module)) {} 569 const char* name)
570 : ServiceFramework(name), module(std::move(module)), fsc(fsc),
571 backend(CreateBackendFromSettings([&fsc](u64 tid) { return fsc.GetBCATDirectory(tid); })) {}
45 572
46Module::Interface::~Interface() = default; 573Module::Interface::~Interface() = default;
47 574
48void InstallInterfaces(SM::ServiceManager& service_manager) { 575void InstallInterfaces(Core::System& system) {
49 auto module = std::make_shared<Module>(); 576 auto module = std::make_shared<Module>();
50 std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); 577 std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:a")
51 std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager); 578 ->InstallAsService(system.ServiceManager());
52 std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager); 579 std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:m")
53 std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager); 580 ->InstallAsService(system.ServiceManager());
581 std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:u")
582 ->InstallAsService(system.ServiceManager());
583 std::make_shared<BCAT>(module, system.GetFileSystemController(), "bcat:s")
584 ->InstallAsService(system.ServiceManager());
54} 585}
55 586
56} // namespace Service::BCAT 587} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h
index f0d63cab0..27469926a 100644
--- a/src/core/hle/service/bcat/module.h
+++ b/src/core/hle/service/bcat/module.h
@@ -6,23 +6,39 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Service::BCAT { 9namespace Service {
10
11namespace FileSystem {
12class FileSystemController;
13} // namespace FileSystem
14
15namespace BCAT {
16
17class Backend;
10 18
11class Module final { 19class Module final {
12public: 20public:
13 class Interface : public ServiceFramework<Interface> { 21 class Interface : public ServiceFramework<Interface> {
14 public: 22 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 23 explicit Interface(std::shared_ptr<Module> module, FileSystem::FileSystemController& fsc,
24 const char* name);
16 ~Interface() override; 25 ~Interface() override;
17 26
18 void CreateBcatService(Kernel::HLERequestContext& ctx); 27 void CreateBcatService(Kernel::HLERequestContext& ctx);
28 void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx);
29 void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx);
19 30
20 protected: 31 protected:
32 FileSystem::FileSystemController& fsc;
33
21 std::shared_ptr<Module> module; 34 std::shared_ptr<Module> module;
35 std::unique_ptr<Backend> backend;
22 }; 36 };
23}; 37};
24 38
25/// Registers all BCAT services with the specified service manager. 39/// Registers all BCAT services with the specified service manager.
26void InstallInterfaces(SM::ServiceManager& service_manager); 40void InstallInterfaces(Core::System& system);
41
42} // namespace BCAT
27 43
28} // namespace Service::BCAT 44} // namespace Service
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 3c7ca2c44..afce581e5 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -16,7 +16,7 @@ namespace Service::BtDrv {
16 16
17class Bt final : public ServiceFramework<Bt> { 17class Bt final : public ServiceFramework<Bt> {
18public: 18public:
19 explicit Bt() : ServiceFramework{"bt"} { 19 explicit Bt(Core::System& system) : ServiceFramework{"bt"} {
20 // clang-format off 20 // clang-format off
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
22 {0, nullptr, "LeClientReadCharacteristic"}, 22 {0, nullptr, "LeClientReadCharacteristic"},
@@ -33,7 +33,7 @@ public:
33 // clang-format on 33 // clang-format on
34 RegisterHandlers(functions); 34 RegisterHandlers(functions);
35 35
36 auto& kernel = Core::System::GetInstance().Kernel(); 36 auto& kernel = system.Kernel();
37 register_event = Kernel::WritableEvent::CreateEventPair( 37 register_event = Kernel::WritableEvent::CreateEventPair(
38 kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent"); 38 kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent");
39 } 39 }
@@ -163,9 +163,9 @@ public:
163 } 163 }
164}; 164};
165 165
166void InstallInterfaces(SM::ServiceManager& sm) { 166void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
167 std::make_shared<BtDrv>()->InstallAsService(sm); 167 std::make_shared<BtDrv>()->InstallAsService(sm);
168 std::make_shared<Bt>()->InstallAsService(sm); 168 std::make_shared<Bt>(system)->InstallAsService(sm);
169} 169}
170 170
171} // namespace Service::BtDrv 171} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h
index 164e56f43..191410dbc 100644
--- a/src/core/hle/service/btdrv/btdrv.h
+++ b/src/core/hle/service/btdrv/btdrv.h
@@ -8,9 +8,13 @@ namespace Service::SM {
8class ServiceManager; 8class ServiceManager;
9} 9}
10 10
11namespace Core {
12class System;
13}
14
11namespace Service::BtDrv { 15namespace Service::BtDrv {
12 16
13/// Registers all BtDrv services with the specified service manager. 17/// Registers all BtDrv services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm); 18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
15 19
16} // namespace Service::BtDrv 20} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index b439ee7ec..920fc6ff7 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -17,7 +17,7 @@ namespace Service::BTM {
17 17
18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
19public: 19public:
20 explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} { 20 explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} {
21 // clang-format off 21 // clang-format off
22 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, 23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -56,7 +56,7 @@ public:
56 // clang-format on 56 // clang-format on
57 RegisterHandlers(functions); 57 RegisterHandlers(functions);
58 58
59 auto& kernel = Core::System::GetInstance().Kernel(); 59 auto& kernel = system.Kernel();
60 scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, 60 scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
61 "IBtmUserCore:ScanEvent"); 61 "IBtmUserCore:ScanEvent");
62 connection_event = Kernel::WritableEvent::CreateEventPair( 62 connection_event = Kernel::WritableEvent::CreateEventPair(
@@ -108,7 +108,7 @@ private:
108 108
109class BTM_USR final : public ServiceFramework<BTM_USR> { 109class BTM_USR final : public ServiceFramework<BTM_USR> {
110public: 110public:
111 explicit BTM_USR() : ServiceFramework{"btm:u"} { 111 explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) {
112 // clang-format off 112 // clang-format off
113 static const FunctionInfo functions[] = { 113 static const FunctionInfo functions[] = {
114 {0, &BTM_USR::GetCore, "GetCore"}, 114 {0, &BTM_USR::GetCore, "GetCore"},
@@ -123,8 +123,10 @@ private:
123 123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
126 rb.PushIpcInterface<IBtmUserCore>(); 126 rb.PushIpcInterface<IBtmUserCore>(system);
127 } 127 }
128
129 Core::System& system;
128}; 130};
129 131
130class BTM final : public ServiceFramework<BTM> { 132class BTM final : public ServiceFramework<BTM> {
@@ -268,11 +270,11 @@ private:
268 } 270 }
269}; 271};
270 272
271void InstallInterfaces(SM::ServiceManager& sm) { 273void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
272 std::make_shared<BTM>()->InstallAsService(sm); 274 std::make_shared<BTM>()->InstallAsService(sm);
273 std::make_shared<BTM_DBG>()->InstallAsService(sm); 275 std::make_shared<BTM_DBG>()->InstallAsService(sm);
274 std::make_shared<BTM_SYS>()->InstallAsService(sm); 276 std::make_shared<BTM_SYS>()->InstallAsService(sm);
275 std::make_shared<BTM_USR>()->InstallAsService(sm); 277 std::make_shared<BTM_USR>(system)->InstallAsService(sm);
276} 278}
277 279
278} // namespace Service::BTM 280} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
index e6425a7e3..c6b878043 100644
--- a/src/core/hle/service/btm/btm.h
+++ b/src/core/hle/service/btm/btm.h
@@ -8,8 +8,12 @@ namespace Service::SM {
8class ServiceManager; 8class ServiceManager;
9} 9}
10 10
11namespace Core {
12class System;
13};
14
11namespace Service::BTM { 15namespace Service::BTM {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::BTM 19} // namespace Service::BTM
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 01fa06ad3..b2ebf6240 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -20,8 +20,8 @@
20 20
21namespace Service::Fatal { 21namespace Service::Fatal {
22 22
23Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 23Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
24 : ServiceFramework(name), module(std::move(module)) {} 24 : ServiceFramework(name), module(std::move(module)), system(system) {}
25 25
26Module::Interface::~Interface() = default; 26Module::Interface::~Interface() = default;
27 27
@@ -64,7 +64,8 @@ enum class FatalType : u32 {
64 ErrorScreen = 2, 64 ErrorScreen = 2,
65}; 65};
66 66
67static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { 67static void GenerateErrorReport(Core::System& system, ResultCode error_code,
68 const FatalInfo& info) {
68 const auto title_id = Core::CurrentProcess()->GetTitleID(); 69 const auto title_id = Core::CurrentProcess()->GetTitleID();
69 std::string crash_report = fmt::format( 70 std::string crash_report = fmt::format(
70 "Yuzu {}-{} crash report\n" 71 "Yuzu {}-{} crash report\n"
@@ -101,18 +102,19 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
101 102
102 LOG_ERROR(Service_Fatal, "{}", crash_report); 103 LOG_ERROR(Service_Fatal, "{}", crash_report);
103 104
104 Core::System::GetInstance().GetReporter().SaveCrashReport( 105 system.GetReporter().SaveCrashReport(
105 title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc, 106 title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc,
106 info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace, 107 info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace,
107 info.backtrace_size, info.ArchAsString(), info.unk10); 108 info.backtrace_size, info.ArchAsString(), info.unk10);
108} 109}
109 110
110static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) { 111static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type,
112 const FatalInfo& info) {
111 LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", 113 LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}",
112 static_cast<u32>(fatal_type), error_code.raw); 114 static_cast<u32>(fatal_type), error_code.raw);
113 switch (fatal_type) { 115 switch (fatal_type) {
114 case FatalType::ErrorReportAndScreen: 116 case FatalType::ErrorReportAndScreen:
115 GenerateErrorReport(error_code, info); 117 GenerateErrorReport(system, error_code, info);
116 [[fallthrough]]; 118 [[fallthrough]];
117 case FatalType::ErrorScreen: 119 case FatalType::ErrorScreen:
118 // Since we have no fatal:u error screen. We should just kill execution instead 120 // Since we have no fatal:u error screen. We should just kill execution instead
@@ -120,7 +122,7 @@ static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const F
120 break; 122 break;
121 // Should not throw a fatal screen but should generate an error report 123 // Should not throw a fatal screen but should generate an error report
122 case FatalType::ErrorReport: 124 case FatalType::ErrorReport:
123 GenerateErrorReport(error_code, info); 125 GenerateErrorReport(system, error_code, info);
124 break; 126 break;
125 } 127 }
126} 128}
@@ -130,7 +132,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
130 IPC::RequestParser rp{ctx}; 132 IPC::RequestParser rp{ctx};
131 const auto error_code = rp.Pop<ResultCode>(); 133 const auto error_code = rp.Pop<ResultCode>();
132 134
133 ThrowFatalError(error_code, FatalType::ErrorScreen, {}); 135 ThrowFatalError(system, error_code, FatalType::ErrorScreen, {});
134 IPC::ResponseBuilder rb{ctx, 2}; 136 IPC::ResponseBuilder rb{ctx, 2};
135 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
136} 138}
@@ -141,7 +143,8 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
141 const auto error_code = rp.Pop<ResultCode>(); 143 const auto error_code = rp.Pop<ResultCode>();
142 const auto fatal_type = rp.PopEnum<FatalType>(); 144 const auto fatal_type = rp.PopEnum<FatalType>();
143 145
144 ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy 146 ThrowFatalError(system, error_code, fatal_type,
147 {}); // No info is passed with ThrowFatalWithPolicy
145 IPC::ResponseBuilder rb{ctx, 2}; 148 IPC::ResponseBuilder rb{ctx, 2};
146 rb.Push(RESULT_SUCCESS); 149 rb.Push(RESULT_SUCCESS);
147} 150}
@@ -157,15 +160,15 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx)
157 ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!"); 160 ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
158 std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo)); 161 std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
159 162
160 ThrowFatalError(error_code, fatal_type, info); 163 ThrowFatalError(system, error_code, fatal_type, info);
161 IPC::ResponseBuilder rb{ctx, 2}; 164 IPC::ResponseBuilder rb{ctx, 2};
162 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
163} 166}
164 167
165void InstallInterfaces(SM::ServiceManager& service_manager) { 168void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
166 auto module = std::make_shared<Module>(); 169 auto module = std::make_shared<Module>();
167 std::make_shared<Fatal_P>(module)->InstallAsService(service_manager); 170 std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
168 std::make_shared<Fatal_U>(module)->InstallAsService(service_manager); 171 std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
169} 172}
170 173
171} // namespace Service::Fatal 174} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index 09371ff7f..bd9339dfc 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -6,13 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Fatal { 13namespace Service::Fatal {
10 14
11class Module final { 15class Module final {
12public: 16public:
13 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
14 public: 18 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
16 ~Interface() override; 20 ~Interface() override;
17 21
18 void ThrowFatal(Kernel::HLERequestContext& ctx); 22 void ThrowFatal(Kernel::HLERequestContext& ctx);
@@ -21,9 +25,10 @@ public:
21 25
22 protected: 26 protected:
23 std::shared_ptr<Module> module; 27 std::shared_ptr<Module> module;
28 Core::System& system;
24 }; 29 };
25}; 30};
26 31
27void InstallInterfaces(SM::ServiceManager& service_manager); 32void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
28 33
29} // namespace Service::Fatal 34} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp
index 9e5f872ff..066ccf6b0 100644
--- a/src/core/hle/service/fatal/fatal_p.cpp
+++ b/src/core/hle/service/fatal/fatal_p.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Fatal { 7namespace Service::Fatal {
8 8
9Fatal_P::Fatal_P(std::shared_ptr<Module> module) 9Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system)
10 : Module::Interface(std::move(module), "fatal:p") {} 10 : Module::Interface(std::move(module), system, "fatal:p") {}
11 11
12Fatal_P::~Fatal_P() = default; 12Fatal_P::~Fatal_P() = default;
13 13
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h
index 6e9c5979f..c6d953cb5 100644
--- a/src/core/hle/service/fatal/fatal_p.h
+++ b/src/core/hle/service/fatal/fatal_p.h
@@ -10,7 +10,7 @@ namespace Service::Fatal {
10 10
11class Fatal_P final : public Module::Interface { 11class Fatal_P final : public Module::Interface {
12public: 12public:
13 explicit Fatal_P(std::shared_ptr<Module> module); 13 explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system);
14 ~Fatal_P() override; 14 ~Fatal_P() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index 1572a2051..8d72ed485 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -6,7 +6,8 @@
6 6
7namespace Service::Fatal { 7namespace Service::Fatal {
8 8
9Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") { 9Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system)
10 : Module::Interface(std::move(module), system, "fatal:u") {
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, 12 {0, &Fatal_U::ThrowFatal, "ThrowFatal"},
12 {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, 13 {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h
index 72cb6d076..34c5c7f95 100644
--- a/src/core/hle/service/fatal/fatal_u.h
+++ b/src/core/hle/service/fatal/fatal_u.h
@@ -10,7 +10,7 @@ namespace Service::Fatal {
10 10
11class Fatal_U final : public Module::Interface { 11class Fatal_U final : public Module::Interface {
12public: 12public:
13 explicit Fatal_U(std::shared_ptr<Module> module); 13 explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system);
14 ~Fatal_U() override; 14 ~Fatal_U() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 14cd0e322..7fa4e820b 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -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;
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 3e0c03ec0..e6b49d8a2 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -110,6 +110,8 @@ public:
110 FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; 110 FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
111 FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; 111 FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
112 112
113 FileSys::VirtualDir GetBCATDirectory(u64 title_id) const;
114
113 // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function 115 // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
114 // above is called. 116 // above is called.
115 void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); 117 void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index d1ec12ef9..42b4ee861 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -149,7 +149,8 @@ private:
149 149
150class INotificationService final : public ServiceFramework<INotificationService> { 150class INotificationService final : public ServiceFramework<INotificationService> {
151public: 151public:
152 INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) { 152 INotificationService(Common::UUID uuid, Core::System& system)
153 : ServiceFramework("INotificationService"), uuid(uuid) {
153 // clang-format off 154 // clang-format off
154 static const FunctionInfo functions[] = { 155 static const FunctionInfo functions[] = {
155 {0, &INotificationService::GetEvent, "GetEvent"}, 156 {0, &INotificationService::GetEvent, "GetEvent"},
@@ -159,6 +160,9 @@ public:
159 // clang-format on 160 // clang-format on
160 161
161 RegisterHandlers(functions); 162 RegisterHandlers(functions);
163
164 notification_event = Kernel::WritableEvent::CreateEventPair(
165 system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
162 } 166 }
163 167
164private: 168private:
@@ -167,13 +171,6 @@ private:
167 171
168 IPC::ResponseBuilder rb{ctx, 2, 1}; 172 IPC::ResponseBuilder rb{ctx, 2, 1};
169 rb.Push(RESULT_SUCCESS); 173 rb.Push(RESULT_SUCCESS);
170
171 if (!is_event_created) {
172 auto& kernel = Core::System::GetInstance().Kernel();
173 notification_event = Kernel::WritableEvent::CreateEventPair(
174 kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
175 is_event_created = true;
176 }
177 rb.PushCopyObjects(notification_event.readable); 174 rb.PushCopyObjects(notification_event.readable);
178 } 175 }
179 176
@@ -261,21 +258,21 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
261 258
262 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 259 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
263 rb.Push(RESULT_SUCCESS); 260 rb.Push(RESULT_SUCCESS);
264 rb.PushIpcInterface<INotificationService>(uuid); 261 rb.PushIpcInterface<INotificationService>(uuid, system);
265} 262}
266 263
267Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 264Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
268 : ServiceFramework(name), module(std::move(module)) {} 265 : ServiceFramework(name), module(std::move(module)), system(system) {}
269 266
270Module::Interface::~Interface() = default; 267Module::Interface::~Interface() = default;
271 268
272void InstallInterfaces(SM::ServiceManager& service_manager) { 269void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
273 auto module = std::make_shared<Module>(); 270 auto module = std::make_shared<Module>();
274 std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); 271 std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
275 std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager); 272 std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
276 std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager); 273 std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
277 std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager); 274 std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
278 std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager); 275 std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
279} 276}
280 277
281} // namespace Service::Friend 278} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index 38d05fa8e..24f3fc969 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -6,13 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Friend { 13namespace Service::Friend {
10 14
11class Module final { 15class Module final {
12public: 16public:
13 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
14 public: 18 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
16 ~Interface() override; 20 ~Interface() override;
17 21
18 void CreateFriendService(Kernel::HLERequestContext& ctx); 22 void CreateFriendService(Kernel::HLERequestContext& ctx);
@@ -20,10 +24,11 @@ public:
20 24
21 protected: 25 protected:
22 std::shared_ptr<Module> module; 26 std::shared_ptr<Module> module;
27 Core::System& system;
23 }; 28 };
24}; 29};
25 30
26/// Registers all Friend services with the specified service manager. 31/// Registers all Friend services with the specified service manager.
27void InstallInterfaces(SM::ServiceManager& service_manager); 32void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
28 33
29} // namespace Service::Friend 34} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp
index 5b384f733..58155f652 100644
--- a/src/core/hle/service/friend/interface.cpp
+++ b/src/core/hle/service/friend/interface.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Friend { 7namespace Service::Friend {
8 8
9Friend::Friend(std::shared_ptr<Module> module, const char* name) 9Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name)
10 : Interface(std::move(module), name) { 10 : Interface(std::move(module), system, name) {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &Friend::CreateFriendService, "CreateFriendService"}, 12 {0, &Friend::CreateFriendService, "CreateFriendService"},
13 {1, &Friend::CreateNotificationService, "CreateNotificationService"}, 13 {1, &Friend::CreateNotificationService, "CreateNotificationService"},
diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h
index 1963def39..465a35770 100644
--- a/src/core/hle/service/friend/interface.h
+++ b/src/core/hle/service/friend/interface.h
@@ -10,7 +10,7 @@ namespace Service::Friend {
10 10
11class Friend final : public Module::Interface { 11class Friend final : public Module::Interface {
12public: 12public:
13 explicit Friend(std::shared_ptr<Module> module, const char* name); 13 explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name);
14 ~Friend() override; 14 ~Friend() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
index 0993a7815..8091db9d7 100644
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::HID { 7namespace Service::HID {
8 8
9ControllerBase::ControllerBase() = default; 9ControllerBase::ControllerBase(Core::System& system) : system(system) {}
10ControllerBase::~ControllerBase() = default; 10ControllerBase::~ControllerBase() = default;
11 11
12void ControllerBase::ActivateController() { 12void ControllerBase::ActivateController() {
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 5e5097a03..8bc69c372 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -11,10 +11,14 @@ namespace Core::Timing {
11class CoreTiming; 11class CoreTiming;
12} 12}
13 13
14namespace Core {
15class System;
16}
17
14namespace Service::HID { 18namespace Service::HID {
15class ControllerBase { 19class ControllerBase {
16public: 20public:
17 ControllerBase(); 21 explicit ControllerBase(Core::System& system);
18 virtual ~ControllerBase(); 22 virtual ~ControllerBase();
19 23
20 // Called when the controller is initialized 24 // Called when the controller is initialized
@@ -46,5 +50,7 @@ protected:
46 s64_le entry_count; 50 s64_le entry_count;
47 }; 51 };
48 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); 52 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
53
54 Core::System& system;
49}; 55};
50} // namespace Service::HID 56} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index c5c2e032a..8e8263f5b 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -14,7 +14,8 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 14constexpr 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() = default; 17Controller_DebugPad::Controller_DebugPad(Core::System& system)
18 : ControllerBase(system), system(system) {}
18Controller_DebugPad::~Controller_DebugPad() = default; 19Controller_DebugPad::~Controller_DebugPad() = default;
19 20
20void Controller_DebugPad::OnInit() {} 21void 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 e584b92ec..6c4de817e 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -16,7 +16,7 @@
16namespace Service::HID { 16namespace Service::HID {
17class Controller_DebugPad final : public ControllerBase { 17class Controller_DebugPad final : public ControllerBase {
18public: 18public:
19 Controller_DebugPad(); 19 explicit Controller_DebugPad(Core::System& system);
20 ~Controller_DebugPad() override; 20 ~Controller_DebugPad() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
@@ -89,5 +89,6 @@ 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;
92}; 93};
93} // namespace Service::HID 94} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index a179252e3..80da0a0d3 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -10,7 +10,8 @@
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() = default; 13Controller_Gesture::Controller_Gesture(Core::System& system)
14 : ControllerBase(system), system(system) {}
14Controller_Gesture::~Controller_Gesture() = default; 15Controller_Gesture::~Controller_Gesture() = default;
15 16
16void Controller_Gesture::OnInit() {} 17void Controller_Gesture::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index f305fe90f..396897527 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -12,7 +12,7 @@
12namespace Service::HID { 12namespace Service::HID {
13class Controller_Gesture final : public ControllerBase { 13class Controller_Gesture final : public ControllerBase {
14public: 14public:
15 Controller_Gesture(); 15 explicit Controller_Gesture(Core::System& system);
16 ~Controller_Gesture() override; 16 ~Controller_Gesture() override;
17 17
18 // Called when the controller is initialized 18 // Called when the controller is initialized
@@ -59,5 +59,6 @@ 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;
62}; 63};
63} // namespace Service::HID 64} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 92d7bfb52..e587b2e15 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -12,7 +12,8 @@ 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() = default; 15Controller_Keyboard::Controller_Keyboard(Core::System& system)
16 : ControllerBase(system), system(system) {}
16Controller_Keyboard::~Controller_Keyboard() = default; 17Controller_Keyboard::~Controller_Keyboard() = default;
17 18
18void Controller_Keyboard::OnInit() {} 19void Controller_Keyboard::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 73cd2c7bb..ef586f7eb 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -15,7 +15,7 @@
15namespace Service::HID { 15namespace Service::HID {
16class Controller_Keyboard final : public ControllerBase { 16class Controller_Keyboard final : public ControllerBase {
17public: 17public:
18 Controller_Keyboard(); 18 explicit Controller_Keyboard(Core::System& system);
19 ~Controller_Keyboard() override; 19 ~Controller_Keyboard() override;
20 20
21 // Called when the controller is initialized 21 // Called when the controller is initialized
@@ -53,5 +53,6 @@ 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;
56}; 57};
57} // namespace Service::HID 58} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 11ab096d9..88f2ca4c1 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() = default; 14Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(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 9d46eecbe..df2da6ae3 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -14,7 +14,7 @@
14namespace Service::HID { 14namespace Service::HID {
15class Controller_Mouse final : public ControllerBase { 15class Controller_Mouse final : public ControllerBase {
16public: 16public:
17 Controller_Mouse(); 17 explicit Controller_Mouse(Core::System& system);
18 ~Controller_Mouse() override; 18 ~Controller_Mouse() override;
19 19
20 // Called when the controller is initialized 20 // Called when the controller is initialized
@@ -53,5 +53,6 @@ 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;
56}; 57};
57} // namespace Service::HID 58} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index e47fe8188..a9cd119c4 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -93,7 +93,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
93 }; 93 };
94} 94}
95 95
96Controller_NPad::Controller_NPad() = default; 96Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
97Controller_NPad::~Controller_NPad() = default; 97Controller_NPad::~Controller_NPad() = default;
98 98
99void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { 99void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
@@ -165,12 +165,15 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
165 controller.battery_level[0] = BATTERY_FULL; 165 controller.battery_level[0] = BATTERY_FULL;
166 controller.battery_level[1] = BATTERY_FULL; 166 controller.battery_level[1] = BATTERY_FULL;
167 controller.battery_level[2] = BATTERY_FULL; 167 controller.battery_level[2] = BATTERY_FULL;
168 styleset_changed_events[controller_idx].writable->Signal();
168} 169}
169 170
170void Controller_NPad::OnInit() { 171void Controller_NPad::OnInit() {
171 auto& kernel = Core::System::GetInstance().Kernel(); 172 auto& kernel = system.Kernel();
172 styleset_changed_event = Kernel::WritableEvent::CreateEventPair( 173 for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
173 kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged"); 174 styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
175 kernel, Kernel::ResetType::Manual, fmt::format("npad:NpadStyleSetChanged_{}", i));
176 }
174 177
175 if (!IsControllerActivated()) { 178 if (!IsControllerActivated()) {
176 return; 179 return;
@@ -431,7 +434,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
431 supported_npad_id_types.clear(); 434 supported_npad_id_types.clear();
432 supported_npad_id_types.resize(length / sizeof(u32)); 435 supported_npad_id_types.resize(length / sizeof(u32));
433 std::memcpy(supported_npad_id_types.data(), data, length); 436 std::memcpy(supported_npad_id_types.data(), data, length);
434 bool had_controller_update = false;
435 for (std::size_t i = 0; i < connected_controllers.size(); i++) { 437 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
436 auto& controller = connected_controllers[i]; 438 auto& controller = connected_controllers[i];
437 if (!controller.is_connected) { 439 if (!controller.is_connected) {
@@ -450,10 +452,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
450 controller.type = requested_controller; 452 controller.type = requested_controller;
451 InitNewlyAddedControler(i); 453 InitNewlyAddedControler(i);
452 } 454 }
453 had_controller_update = true;
454 }
455 if (had_controller_update) {
456 styleset_changed_event.writable->Signal();
457 } 455 }
458 } 456 }
459} 457}
@@ -468,7 +466,6 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
468} 466}
469 467
470void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { 468void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
471 styleset_changed_event.writable->Signal();
472 hold_type = joy_hold_type; 469 hold_type = joy_hold_type;
473} 470}
474 471
@@ -479,7 +476,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
479void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 476void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
480 const std::size_t npad_index = NPadIdToIndex(npad_id); 477 const std::size_t npad_index = NPadIdToIndex(npad_id);
481 ASSERT(npad_index < shared_memory_entries.size()); 478 ASSERT(npad_index < shared_memory_entries.size());
482 shared_memory_entries[npad_index].pad_assignment = assignment_mode; 479 if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
480 shared_memory_entries[npad_index].pad_assignment = assignment_mode;
481 }
483} 482}
484 483
485void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 484void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
@@ -498,11 +497,12 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
498 last_processed_vibration = vibrations.back(); 497 last_processed_vibration = vibrations.back();
499} 498}
500 499
501Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const { 500Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
501 u32 npad_id) const {
502 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should 502 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
503 // be signalled at least once, and signaled after a new controller is connected? 503 // be signalled at least once, and signaled after a new controller is connected?
504 styleset_changed_event.writable->Signal(); 504 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
505 return styleset_changed_event.readable; 505 return styleset_event.readable;
506} 506}
507 507
508Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 508Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index f28b36806..1bc3d55d6 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -20,7 +20,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
20 20
21class Controller_NPad final : public ControllerBase { 21class Controller_NPad final : public ControllerBase {
22public: 22public:
23 Controller_NPad(); 23 explicit Controller_NPad(Core::System& system);
24 ~Controller_NPad() override; 24 ~Controller_NPad() override;
25 25
26 // Called when the controller is initialized 26 // Called when the controller is initialized
@@ -109,7 +109,7 @@ public:
109 void VibrateController(const std::vector<u32>& controller_ids, 109 void VibrateController(const std::vector<u32>& controller_ids,
110 const std::vector<Vibration>& vibrations); 110 const std::vector<Vibration>& vibrations);
111 111
112 Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const; 112 Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
113 Vibration GetLastVibration() const; 113 Vibration GetLastVibration() const;
114 114
115 void AddNewController(NPadControllerType controller); 115 void AddNewController(NPadControllerType controller);
@@ -315,7 +315,8 @@ private:
315 sticks; 315 sticks;
316 std::vector<u32> supported_npad_id_types{}; 316 std::vector<u32> supported_npad_id_types{};
317 NpadHoldType hold_type{NpadHoldType::Vertical}; 317 NpadHoldType hold_type{NpadHoldType::Vertical};
318 Kernel::EventPair styleset_changed_event; 318 // Each controller should have their own styleset changed event
319 std::array<Kernel::EventPair, 10> styleset_changed_events;
319 Vibration last_processed_vibration{}; 320 Vibration last_processed_vibration{};
320 std::array<ControllerHolder, 10> connected_controllers{}; 321 std::array<ControllerHolder, 10> connected_controllers{};
321 bool can_controllers_vibrate{true}; 322 bool can_controllers_vibrate{true};
@@ -327,5 +328,6 @@ private:
327 std::array<ControllerPad, 10> npad_pad_states{}; 328 std::array<ControllerPad, 10> npad_pad_states{};
328 bool IsControllerSupported(NPadControllerType controller); 329 bool IsControllerSupported(NPadControllerType controller);
329 bool is_in_lr_assignment_mode{false}; 330 bool is_in_lr_assignment_mode{false};
331 Core::System& system;
330}; 332};
331} // namespace Service::HID 333} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index 946948f5e..9b829341e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -9,7 +9,8 @@
9 9
10namespace Service::HID { 10namespace Service::HID {
11 11
12Controller_Stubbed::Controller_Stubbed() = default; 12Controller_Stubbed::Controller_Stubbed(Core::System& system)
13 : ControllerBase(system), system(system) {}
13Controller_Stubbed::~Controller_Stubbed() = default; 14Controller_Stubbed::~Controller_Stubbed() = default;
14 15
15void Controller_Stubbed::OnInit() {} 16void Controller_Stubbed::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 24469f03e..37d7d8538 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -10,7 +10,7 @@
10namespace Service::HID { 10namespace Service::HID {
11class Controller_Stubbed final : public ControllerBase { 11class Controller_Stubbed final : public ControllerBase {
12public: 12public:
13 Controller_Stubbed(); 13 explicit Controller_Stubbed(Core::System& system);
14 ~Controller_Stubbed() override; 14 ~Controller_Stubbed() override;
15 15
16 // Called when the controller is initialized 16 // Called when the controller is initialized
@@ -30,5 +30,6 @@ 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;
33}; 34};
34} // namespace Service::HID 35} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 1a8445a43..25912fd69 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -13,7 +13,8 @@
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() = default; 16Controller_Touchscreen::Controller_Touchscreen(Core::System& system)
17 : ControllerBase(system), system(system) {}
17Controller_Touchscreen::~Controller_Touchscreen() = default; 18Controller_Touchscreen::~Controller_Touchscreen() = default;
18 19
19void Controller_Touchscreen::OnInit() {} 20void Controller_Touchscreen::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 76fc340e9..3429c84db 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -14,7 +14,7 @@
14namespace Service::HID { 14namespace Service::HID {
15class Controller_Touchscreen final : public ControllerBase { 15class Controller_Touchscreen final : public ControllerBase {
16public: 16public:
17 Controller_Touchscreen(); 17 explicit Controller_Touchscreen(Core::System& system);
18 ~Controller_Touchscreen() override; 18 ~Controller_Touchscreen() override;
19 19
20 // Called when the controller is initialized 20 // Called when the controller is initialized
@@ -69,5 +69,6 @@ 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;
72}; 73};
73} // namespace Service::HID 74} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index 1a9da9576..1bce044b4 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() = default; 13Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(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 2864e6617..c445ebec0 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -12,7 +12,7 @@
12namespace Service::HID { 12namespace Service::HID {
13class Controller_XPad final : public ControllerBase { 13class Controller_XPad final : public ControllerBase {
14public: 14public:
15 Controller_XPad(); 15 explicit Controller_XPad(Core::System& system);
16 ~Controller_XPad() override; 16 ~Controller_XPad() override;
17 17
18 // Called when the controller is initialized 18 // Called when the controller is initialized
@@ -56,5 +56,6 @@ 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;
59}; 60};
60} // namespace Service::HID 61} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index f8b1ca816..8d76ba746 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -42,13 +42,14 @@ constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_C
42constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100); 42constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
43constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 43constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
44 44
45IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { 45IAppletResource::IAppletResource(Core::System& system)
46 : ServiceFramework("IAppletResource"), system(system) {
46 static const FunctionInfo functions[] = { 47 static const FunctionInfo functions[] = {
47 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 48 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
48 }; 49 };
49 RegisterHandlers(functions); 50 RegisterHandlers(functions);
50 51
51 auto& kernel = Core::System::GetInstance().Kernel(); 52 auto& kernel = system.Kernel();
52 shared_mem = Kernel::SharedMemory::Create( 53 shared_mem = Kernel::SharedMemory::Create(
53 kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, 54 kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
54 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); 55 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
@@ -74,7 +75,7 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
74 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); 75 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
75 76
76 // Register update callbacks 77 // Register update callbacks
77 auto& core_timing = Core::System::GetInstance().CoreTiming(); 78 auto& core_timing = system.CoreTiming();
78 pad_update_event = 79 pad_update_event =
79 core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { 80 core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
80 UpdateControllers(userdata, cycles_late); 81 UpdateControllers(userdata, cycles_late);
@@ -96,7 +97,7 @@ void IAppletResource::DeactivateController(HidController controller) {
96} 97}
97 98
98IAppletResource ::~IAppletResource() { 99IAppletResource ::~IAppletResource() {
99 Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0); 100 system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
100} 101}
101 102
102void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 103void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -108,7 +109,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
108} 109}
109 110
110void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { 111void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) {
111 auto& core_timing = Core::System::GetInstance().CoreTiming(); 112 auto& core_timing = system.CoreTiming();
112 113
113 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 114 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
114 for (const auto& controller : controllers) { 115 for (const auto& controller : controllers) {
@@ -141,13 +142,13 @@ private:
141 142
142std::shared_ptr<IAppletResource> Hid::GetAppletResource() { 143std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
143 if (applet_resource == nullptr) { 144 if (applet_resource == nullptr) {
144 applet_resource = std::make_shared<IAppletResource>(); 145 applet_resource = std::make_shared<IAppletResource>(system);
145 } 146 }
146 147
147 return applet_resource; 148 return applet_resource;
148} 149}
149 150
150Hid::Hid() : ServiceFramework("hid") { 151Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
151 // clang-format off 152 // clang-format off
152 static const FunctionInfo functions[] = { 153 static const FunctionInfo functions[] = {
153 {0, &Hid::CreateAppletResource, "CreateAppletResource"}, 154 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -286,7 +287,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
286 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 287 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
287 288
288 if (applet_resource == nullptr) { 289 if (applet_resource == nullptr) {
289 applet_resource = std::make_shared<IAppletResource>(); 290 applet_resource = std::make_shared<IAppletResource>(system);
290 } 291 }
291 292
292 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 293 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -479,7 +480,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
479 IPC::ResponseBuilder rb{ctx, 2, 1}; 480 IPC::ResponseBuilder rb{ctx, 2, 1};
480 rb.Push(RESULT_SUCCESS); 481 rb.Push(RESULT_SUCCESS);
481 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 482 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
482 .GetStyleSetChangedEvent()); 483 .GetStyleSetChangedEvent(npad_id));
483} 484}
484 485
485void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { 486void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
@@ -1053,14 +1054,14 @@ void ReloadInputDevices() {
1053 Settings::values.is_device_reload_pending.store(true); 1054 Settings::values.is_device_reload_pending.store(true);
1054} 1055}
1055 1056
1056void InstallInterfaces(SM::ServiceManager& service_manager) { 1057void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
1057 std::make_shared<Hid>()->InstallAsService(service_manager); 1058 std::make_shared<Hid>(system)->InstallAsService(service_manager);
1058 std::make_shared<HidBus>()->InstallAsService(service_manager); 1059 std::make_shared<HidBus>()->InstallAsService(service_manager);
1059 std::make_shared<HidDbg>()->InstallAsService(service_manager); 1060 std::make_shared<HidDbg>()->InstallAsService(service_manager);
1060 std::make_shared<HidSys>()->InstallAsService(service_manager); 1061 std::make_shared<HidSys>()->InstallAsService(service_manager);
1061 std::make_shared<HidTmp>()->InstallAsService(service_manager); 1062 std::make_shared<HidTmp>()->InstallAsService(service_manager);
1062 1063
1063 std::make_shared<IRS>()->InstallAsService(service_manager); 1064 std::make_shared<IRS>(system)->InstallAsService(service_manager);
1064 std::make_shared<IRS_SYS>()->InstallAsService(service_manager); 1065 std::make_shared<IRS_SYS>()->InstallAsService(service_manager);
1065 1066
1066 std::make_shared<XCD_SYS>()->InstallAsService(service_manager); 1067 std::make_shared<XCD_SYS>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 2fd6d9fc7..35b663679 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -42,7 +42,7 @@ enum class HidController : std::size_t {
42 42
43class IAppletResource final : public ServiceFramework<IAppletResource> { 43class IAppletResource final : public ServiceFramework<IAppletResource> {
44public: 44public:
45 IAppletResource(); 45 explicit IAppletResource(Core::System& system);
46 ~IAppletResource() override; 46 ~IAppletResource() override;
47 47
48 void ActivateController(HidController controller); 48 void ActivateController(HidController controller);
@@ -61,7 +61,7 @@ public:
61private: 61private:
62 template <typename T> 62 template <typename T>
63 void MakeController(HidController controller) { 63 void MakeController(HidController controller) {
64 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); 64 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
65 } 65 }
66 66
67 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 67 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
@@ -70,6 +70,7 @@ private:
70 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; 70 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
71 71
72 Core::Timing::EventType* pad_update_event; 72 Core::Timing::EventType* pad_update_event;
73 Core::System& system;
73 74
74 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> 75 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
75 controllers{}; 76 controllers{};
@@ -77,7 +78,7 @@ private:
77 78
78class Hid final : public ServiceFramework<Hid> { 79class Hid final : public ServiceFramework<Hid> {
79public: 80public:
80 Hid(); 81 explicit Hid(Core::System& system);
81 ~Hid() override; 82 ~Hid() override;
82 83
83 std::shared_ptr<IAppletResource> GetAppletResource(); 84 std::shared_ptr<IAppletResource> GetAppletResource();
@@ -126,12 +127,13 @@ private:
126 void SwapNpadAssignment(Kernel::HLERequestContext& ctx); 127 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
127 128
128 std::shared_ptr<IAppletResource> applet_resource; 129 std::shared_ptr<IAppletResource> applet_resource;
130 Core::System& system;
129}; 131};
130 132
131/// Reload input devices. Used when input configuration changed 133/// Reload input devices. Used when input configuration changed
132void ReloadInputDevices(); 134void ReloadInputDevices();
133 135
134/// Registers all HID services with the specified service manager. 136/// Registers all HID services with the specified service manager.
135void InstallInterfaces(SM::ServiceManager& service_manager); 137void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
136 138
137} // namespace Service::HID 139} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 2c4625c99..5e79e2c1a 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -11,7 +11,7 @@
11 11
12namespace Service::HID { 12namespace Service::HID {
13 13
14IRS::IRS() : ServiceFramework{"irs"} { 14IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) {
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, 17 {302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
@@ -37,7 +37,7 @@ IRS::IRS() : ServiceFramework{"irs"} {
37 37
38 RegisterHandlers(functions); 38 RegisterHandlers(functions);
39 39
40 auto& kernel = Core::System::GetInstance().Kernel(); 40 auto& kernel = system.Kernel();
41 shared_mem = Kernel::SharedMemory::Create( 41 shared_mem = Kernel::SharedMemory::Create(
42 kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite, 42 kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
43 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory"); 43 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
98 98
99 IPC::ResponseBuilder rb{ctx, 5}; 99 IPC::ResponseBuilder rb{ctx, 5};
100 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
101 rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks()); 101 rb.PushRaw<u64>(system.CoreTiming().GetTicks());
102 rb.PushRaw<u32>(0); 102 rb.PushRaw<u32>(0);
103} 103}
104 104
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 12de6bfb3..eb4e898dd 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -15,7 +15,7 @@ namespace Service::HID {
15 15
16class IRS final : public ServiceFramework<IRS> { 16class IRS final : public ServiceFramework<IRS> {
17public: 17public:
18 explicit IRS(); 18 explicit IRS(Core::System& system);
19 ~IRS() override; 19 ~IRS() override;
20 20
21private: 21private:
@@ -39,6 +39,7 @@ private:
39 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); 39 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
40 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; 40 Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
41 const u32 device_handle{0xABCD}; 41 const u32 device_handle{0xABCD};
42 Core::System& system;
42}; 43};
43 44
44class IRS_SYS final : public ServiceFramework<IRS_SYS> { 45class IRS_SYS final : public ServiceFramework<IRS_SYS> {
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 8ddad8682..3164ca26e 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -78,7 +78,7 @@ public:
78 78
79class RelocatableObject final : public ServiceFramework<RelocatableObject> { 79class RelocatableObject final : public ServiceFramework<RelocatableObject> {
80public: 80public:
81 explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { 81 explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) {
82 // clang-format off 82 // clang-format off
83 static const FunctionInfo functions[] = { 83 static const FunctionInfo functions[] = {
84 {0, &RelocatableObject::LoadNro, "LoadNro"}, 84 {0, &RelocatableObject::LoadNro, "LoadNro"},
@@ -364,7 +364,7 @@ public:
364 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, 364 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
365 Kernel::VMAPermission::ReadWrite); 365 Kernel::VMAPermission::ReadWrite);
366 366
367 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 367 system.InvalidateCpuInstructionCaches();
368 368
369 nro.insert_or_assign(*map_address, 369 nro.insert_or_assign(*map_address,
370 NROInfo{hash, nro_address, nro_size, bss_address, bss_size}); 370 NROInfo{hash, nro_address, nro_size, bss_address, bss_size});
@@ -430,7 +430,7 @@ public:
430 .IsSuccess()); 430 .IsSuccess());
431 } 431 }
432 432
433 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 433 system.InvalidateCpuInstructionCaches();
434 434
435 nro.erase(iter); 435 nro.erase(iter);
436 IPC::ResponseBuilder rb{ctx, 2}; 436 IPC::ResponseBuilder rb{ctx, 2};
@@ -516,13 +516,14 @@ private:
516 Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && 516 Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
517 Common::Is4KBAligned(header.rw_size); 517 Common::Is4KBAligned(header.rw_size);
518 } 518 }
519 Core::System& system;
519}; 520};
520 521
521void InstallInterfaces(SM::ServiceManager& sm) { 522void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
522 std::make_shared<DebugMonitor>()->InstallAsService(sm); 523 std::make_shared<DebugMonitor>()->InstallAsService(sm);
523 std::make_shared<ProcessManager>()->InstallAsService(sm); 524 std::make_shared<ProcessManager>()->InstallAsService(sm);
524 std::make_shared<Shell>()->InstallAsService(sm); 525 std::make_shared<Shell>()->InstallAsService(sm);
525 std::make_shared<RelocatableObject>()->InstallAsService(sm); 526 std::make_shared<RelocatableObject>(system)->InstallAsService(sm);
526} 527}
527 528
528} // namespace Service::LDR 529} // namespace Service::LDR
diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h
index 412410c4f..7ac8c0b65 100644
--- a/src/core/hle/service/ldr/ldr.h
+++ b/src/core/hle/service/ldr/ldr.h
@@ -11,6 +11,6 @@ class ServiceManager;
11namespace Service::LDR { 11namespace Service::LDR {
12 12
13/// Registers all LDR services with the specified service manager. 13/// Registers all LDR services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm); 14void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
15 15
16} // namespace Service::LDR 16} // namespace Service::LDR
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index a5cb06f8a..a42c22d44 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -23,9 +23,9 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
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
26Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 26Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
27 : ServiceFramework(name), module(std::move(module)) { 27 : ServiceFramework(name), module(std::move(module)), system(system) {
28 auto& kernel = Core::System::GetInstance().Kernel(); 28 auto& kernel = system.Kernel();
29 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, 29 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
30 "IUser:NFCTagDetected"); 30 "IUser:NFCTagDetected");
31} 31}
@@ -34,8 +34,8 @@ Module::Interface::~Interface() = default;
34 34
35class IUser final : public ServiceFramework<IUser> { 35class IUser final : public ServiceFramework<IUser> {
36public: 36public:
37 IUser(Module::Interface& nfp_interface) 37 IUser(Module::Interface& nfp_interface, Core::System& system)
38 : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { 38 : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) {
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"},
@@ -65,7 +65,7 @@ public:
65 }; 65 };
66 RegisterHandlers(functions); 66 RegisterHandlers(functions);
67 67
68 auto& kernel = Core::System::GetInstance().Kernel(); 68 auto& kernel = system.Kernel();
69 deactivate_event = Kernel::WritableEvent::CreateEventPair( 69 deactivate_event = Kernel::WritableEvent::CreateEventPair(
70 kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent"); 70 kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent");
71 availability_change_event = Kernel::WritableEvent::CreateEventPair( 71 availability_change_event = Kernel::WritableEvent::CreateEventPair(
@@ -324,6 +324,7 @@ private:
324 Kernel::EventPair deactivate_event; 324 Kernel::EventPair deactivate_event;
325 Kernel::EventPair availability_change_event; 325 Kernel::EventPair availability_change_event;
326 const Module::Interface& nfp_interface; 326 const Module::Interface& nfp_interface;
327 Core::System& system;
327}; 328};
328 329
329void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 330void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -331,7 +332,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
331 332
332 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 333 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
333 rb.Push(RESULT_SUCCESS); 334 rb.Push(RESULT_SUCCESS);
334 rb.PushIpcInterface<IUser>(*this); 335 rb.PushIpcInterface<IUser>(*this, system);
335} 336}
336 337
337bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { 338bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
@@ -353,9 +354,9 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const
353 return amiibo; 354 return amiibo;
354} 355}
355 356
356void InstallInterfaces(SM::ServiceManager& service_manager) { 357void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
357 auto module = std::make_shared<Module>(); 358 auto module = std::make_shared<Module>();
358 std::make_shared<NFP_User>(module)->InstallAsService(service_manager); 359 std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
359} 360}
360 361
361} // namespace Service::NFP 362} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index a1817e991..9718ef745 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -16,7 +16,7 @@ class Module final {
16public: 16public:
17 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
18 public: 18 public:
19 explicit Interface(std::shared_ptr<Module> module, const char* name); 19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
20 ~Interface() override; 20 ~Interface() override;
21 21
22 struct ModelInfo { 22 struct ModelInfo {
@@ -43,9 +43,10 @@ public:
43 43
44 protected: 44 protected:
45 std::shared_ptr<Module> module; 45 std::shared_ptr<Module> module;
46 Core::System& system;
46 }; 47 };
47}; 48};
48 49
49void InstallInterfaces(SM::ServiceManager& service_manager); 50void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
50 51
51} // namespace Service::NFP 52} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 784a87c1b..298184f17 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::NFP { 7namespace Service::NFP {
8 8
9NFP_User::NFP_User(std::shared_ptr<Module> module) 9NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system)
10 : Module::Interface(std::move(module), "nfp:user") { 10 : Module::Interface(std::move(module), system, "nfp:user") {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, 12 {0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
13 }; 13 };
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 65d9aaf48..1686ebf20 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -10,7 +10,7 @@ namespace Service::NFP {
10 10
11class NFP_User final : public Module::Interface { 11class NFP_User final : public Module::Interface {
12public: 12public:
13 explicit NFP_User(std::shared_ptr<Module> module); 13 explicit NFP_User(std::shared_ptr<Module> module, Core::System& system);
14 ~NFP_User() override; 14 ~NFP_User() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 76b12b482..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") {
@@ -31,7 +38,7 @@ public:
31 38
32class IRequest final : public ServiceFramework<IRequest> { 39class IRequest final : public ServiceFramework<IRequest> {
33public: 40public:
34 explicit IRequest() : ServiceFramework("IRequest") { 41 explicit IRequest(Core::System& system) : ServiceFramework("IRequest") {
35 static const FunctionInfo functions[] = { 42 static const FunctionInfo functions[] = {
36 {0, &IRequest::GetRequestState, "GetRequestState"}, 43 {0, &IRequest::GetRequestState, "GetRequestState"},
37 {1, &IRequest::GetResult, "GetResult"}, 44 {1, &IRequest::GetResult, "GetResult"},
@@ -61,7 +68,7 @@ public:
61 }; 68 };
62 RegisterHandlers(functions); 69 RegisterHandlers(functions);
63 70
64 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& kernel = system.Kernel();
65 event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, 72 event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
66 "IRequest:Event1"); 73 "IRequest:Event1");
67 event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic, 74 event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
@@ -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) {
@@ -130,7 +137,7 @@ public:
130 137
131class IGeneralService final : public ServiceFramework<IGeneralService> { 138class IGeneralService final : public ServiceFramework<IGeneralService> {
132public: 139public:
133 IGeneralService(); 140 IGeneralService(Core::System& system);
134 141
135private: 142private:
136 void GetClientId(Kernel::HLERequestContext& ctx) { 143 void GetClientId(Kernel::HLERequestContext& ctx) {
@@ -155,7 +162,7 @@ private:
155 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 162 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
156 163
157 rb.Push(RESULT_SUCCESS); 164 rb.Push(RESULT_SUCCESS);
158 rb.PushIpcInterface<IRequest>(); 165 rb.PushIpcInterface<IRequest>(system);
159 } 166 }
160 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 167 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
161 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 168 LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -189,18 +196,20 @@ 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 }
208 Core::System& system;
201}; 209};
202 210
203IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { 211IGeneralService::IGeneralService(Core::System& system)
212 : ServiceFramework("IGeneralService"), system(system) {
204 static const FunctionInfo functions[] = { 213 static const FunctionInfo functions[] = {
205 {1, &IGeneralService::GetClientId, "GetClientId"}, 214 {1, &IGeneralService::GetClientId, "GetClientId"},
206 {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, 215 {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
@@ -245,7 +254,8 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
245 254
246class NetworkInterface final : public ServiceFramework<NetworkInterface> { 255class NetworkInterface final : public ServiceFramework<NetworkInterface> {
247public: 256public:
248 explicit NetworkInterface(const char* name) : ServiceFramework{name} { 257 explicit NetworkInterface(const char* name, Core::System& system)
258 : ServiceFramework{name}, system(system) {
249 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
250 {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, 260 {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
251 {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, 261 {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
@@ -258,7 +268,7 @@ public:
258 268
259 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 269 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
260 rb.Push(RESULT_SUCCESS); 270 rb.Push(RESULT_SUCCESS);
261 rb.PushIpcInterface<IGeneralService>(); 271 rb.PushIpcInterface<IGeneralService>(system);
262 } 272 }
263 273
264 void CreateGeneralService(Kernel::HLERequestContext& ctx) { 274 void CreateGeneralService(Kernel::HLERequestContext& ctx) {
@@ -266,14 +276,17 @@ public:
266 276
267 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 277 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
268 rb.Push(RESULT_SUCCESS); 278 rb.Push(RESULT_SUCCESS);
269 rb.PushIpcInterface<IGeneralService>(); 279 rb.PushIpcInterface<IGeneralService>(system);
270 } 280 }
281
282private:
283 Core::System& system;
271}; 284};
272 285
273void InstallInterfaces(SM::ServiceManager& service_manager) { 286void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
274 std::make_shared<NetworkInterface>("nifm:a")->InstallAsService(service_manager); 287 std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
275 std::make_shared<NetworkInterface>("nifm:s")->InstallAsService(service_manager); 288 std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
276 std::make_shared<NetworkInterface>("nifm:u")->InstallAsService(service_manager); 289 std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
277} 290}
278 291
279} // namespace Service::NIFM 292} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 4616b3b48..6857e18f9 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -8,9 +8,13 @@ namespace Service::SM {
8class ServiceManager; 8class ServiceManager;
9} 9}
10 10
11namespace Core {
12class System;
13}
14
11namespace Service::NIFM { 15namespace Service::NIFM {
12 16
13/// Registers all NIFM services with the specified service manager. 17/// Registers all NIFM services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
15 19
16} // namespace Service::NIFM 20} // namespace Service::NIFM
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index f319a3ca1..75d414952 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -126,7 +126,7 @@ public:
126class IEnsureNetworkClockAvailabilityService final 126class IEnsureNetworkClockAvailabilityService final
127 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { 127 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
128public: 128public:
129 IEnsureNetworkClockAvailabilityService() 129 explicit IEnsureNetworkClockAvailabilityService(Core::System& system)
130 : ServiceFramework("IEnsureNetworkClockAvailabilityService") { 130 : ServiceFramework("IEnsureNetworkClockAvailabilityService") {
131 static const FunctionInfo functions[] = { 131 static const FunctionInfo functions[] = {
132 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, 132 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
@@ -139,7 +139,7 @@ public:
139 }; 139 };
140 RegisterHandlers(functions); 140 RegisterHandlers(functions);
141 141
142 auto& kernel = Core::System::GetInstance().Kernel(); 142 auto& kernel = system.Kernel();
143 finished_event = Kernel::WritableEvent::CreateEventPair( 143 finished_event = Kernel::WritableEvent::CreateEventPair(
144 kernel, Kernel::ResetType::Automatic, 144 kernel, Kernel::ResetType::Automatic,
145 "IEnsureNetworkClockAvailabilityService:FinishEvent"); 145 "IEnsureNetworkClockAvailabilityService:FinishEvent");
@@ -200,7 +200,7 @@ private:
200 200
201class NTC final : public ServiceFramework<NTC> { 201class NTC final : public ServiceFramework<NTC> {
202public: 202public:
203 explicit NTC() : ServiceFramework{"ntc"} { 203 explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) {
204 // clang-format off 204 // clang-format off
205 static const FunctionInfo functions[] = { 205 static const FunctionInfo functions[] = {
206 {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, 206 {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
@@ -218,7 +218,7 @@ private:
218 218
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
221 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); 221 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system);
222 } 222 }
223 223
224 // TODO(ogniK): Do we need these? 224 // TODO(ogniK): Do we need these?
@@ -235,13 +235,14 @@ private:
235 IPC::ResponseBuilder rb{ctx, 2}; 235 IPC::ResponseBuilder rb{ctx, 2};
236 rb.Push(RESULT_SUCCESS); 236 rb.Push(RESULT_SUCCESS);
237 } 237 }
238 Core::System& system;
238}; 239};
239 240
240void InstallInterfaces(SM::ServiceManager& sm) { 241void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
241 std::make_shared<NIM>()->InstallAsService(sm); 242 std::make_shared<NIM>()->InstallAsService(sm);
242 std::make_shared<NIM_ECA>()->InstallAsService(sm); 243 std::make_shared<NIM_ECA>()->InstallAsService(sm);
243 std::make_shared<NIM_SHP>()->InstallAsService(sm); 244 std::make_shared<NIM_SHP>()->InstallAsService(sm);
244 std::make_shared<NTC>()->InstallAsService(sm); 245 std::make_shared<NTC>(system)->InstallAsService(sm);
245} 246}
246 247
247} // namespace Service::NIM 248} // namespace Service::NIM
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
index 2a2a92df0..dbe25dc01 100644
--- a/src/core/hle/service/nim/nim.h
+++ b/src/core/hle/service/nim/nim.h
@@ -8,8 +8,12 @@ namespace Service::SM {
8class ServiceManager; 8class ServiceManager;
9} 9}
10 10
11namespace Core {
12class System;
13}
14
11namespace Service::NIM { 15namespace Service::NIM {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::NIM 19} // namespace Service::NIM
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 13121c4f1..15c156ce1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -617,7 +617,8 @@ public:
617 } 617 }
618}; 618};
619 619
620void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) { 620void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
621
621 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); 622 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
622 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); 623 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
623 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); 624 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
@@ -628,7 +629,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSyst
628 std::make_shared<NS_SU>()->InstallAsService(service_manager); 629 std::make_shared<NS_SU>()->InstallAsService(service_manager);
629 std::make_shared<NS_VM>()->InstallAsService(service_manager); 630 std::make_shared<NS_VM>()->InstallAsService(service_manager);
630 631
631 std::make_shared<PL_U>(fsc)->InstallAsService(service_manager); 632 std::make_shared<PL_U>(system)->InstallAsService(service_manager);
632} 633}
633 634
634} // namespace Service::NS 635} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index d067e7a9a..13a64ad88 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -97,8 +97,7 @@ private:
97}; 97};
98 98
99/// Registers all NS services with the specified service manager. 99/// Registers all NS services with the specified service manager.
100void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc); 100void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
101 101
102} // namespace NS 102} // namespace NS
103
104} // namespace Service 103} // namespace Service
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 9d49f36e8..7dcdb4a07 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -150,8 +150,9 @@ struct PL_U::Impl {
150 std::vector<FontRegion> shared_font_regions; 150 std::vector<FontRegion> shared_font_regions;
151}; 151};
152 152
153PL_U::PL_U(FileSystem::FileSystemController& fsc) 153PL_U::PL_U(Core::System& system)
154 : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { 154 : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) {
155
155 static const FunctionInfo functions[] = { 156 static const FunctionInfo functions[] = {
156 {0, &PL_U::RequestLoad, "RequestLoad"}, 157 {0, &PL_U::RequestLoad, "RequestLoad"},
157 {1, &PL_U::GetLoadState, "GetLoadState"}, 158 {1, &PL_U::GetLoadState, "GetLoadState"},
@@ -161,6 +162,9 @@ PL_U::PL_U(FileSystem::FileSystemController& fsc)
161 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, 162 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
162 }; 163 };
163 RegisterHandlers(functions); 164 RegisterHandlers(functions);
165
166 auto& fsc = system.GetFileSystemController();
167
164 // Attempt to load shared font data from disk 168 // Attempt to load shared font data from disk
165 const auto* nand = fsc.GetSystemNANDContents(); 169 const auto* nand = fsc.GetSystemNANDContents();
166 std::size_t offset = 0; 170 std::size_t offset = 0;
@@ -325,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
325 Kernel::MemoryState::Shared); 329 Kernel::MemoryState::Shared);
326 330
327 // Create shared font memory object 331 // Create shared font memory object
328 auto& kernel = Core::System::GetInstance().Kernel(); 332 auto& kernel = system.Kernel();
329 impl->shared_font_mem = Kernel::SharedMemory::Create( 333 impl->shared_font_mem = Kernel::SharedMemory::Create(
330 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, 334 kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
331 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, 335 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index 35ca424d2..1063f4204 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -17,7 +17,7 @@ namespace NS {
17 17
18class PL_U final : public ServiceFramework<PL_U> { 18class PL_U final : public ServiceFramework<PL_U> {
19public: 19public:
20 PL_U(FileSystem::FileSystemController& fsc); 20 explicit PL_U(Core::System& system);
21 ~PL_U() override; 21 ~PL_U() override;
22 22
23private: 23private:
@@ -30,6 +30,7 @@ private:
30 30
31 struct Impl; 31 struct Impl;
32 std::unique_ptr<Impl> impl; 32 std::unique_ptr<Impl> impl;
33 Core::System& system;
33}; 34};
34 35
35} // namespace NS 36} // namespace NS
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 5b8248433..1b52511a5 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/hle/service/nvdrv/nvdata.h" 11#include "core/hle/service/nvdrv/nvdata.h"
12#include "core/hle/service/service.h"
12 13
13namespace Core { 14namespace Core {
14class System; 15class System;
@@ -38,8 +39,9 @@ public:
38 * @param output A buffer where the output data will be written to. 39 * @param output A buffer where the output data will be written to.
39 * @returns The result code of the ioctl. 40 * @returns The result code of the ioctl.
40 */ 41 */
41 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 42 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
42 IoctlCtrl& ctrl) = 0; 43 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
44 IoctlVersion version) = 0;
43 45
44protected: 46protected:
45 Core::System& system; 47 Core::System& system;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 926a1285d..f764388bc 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -17,8 +17,9 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
17 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 17 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
18nvdisp_disp0 ::~nvdisp_disp0() = default; 18nvdisp_disp0 ::~nvdisp_disp0() = default;
19 19
20u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 20u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
21 IoctlCtrl& ctrl) { 21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
22 IoctlVersion version) {
22 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 23 UNIMPLEMENTED_MSG("Unimplemented ioctl");
23 return 0; 24 return 0;
24} 25}
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index e79e490ff..6fcdeee84 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -20,8 +20,9 @@ public:
20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0() override; 21 ~nvdisp_disp0() override;
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 23 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
24 IoctlCtrl& ctrl) override; 24 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
25 IoctlVersion version) override;
25 26
26 /// Performs a screen flip, drawing the buffer pointed to by the handle. 27 /// Performs a screen flip, drawing the buffer pointed to by the handle.
27 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 28 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 24ab3f2e9..6bc053f27 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -26,8 +26,9 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_
26 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 26 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
27nvhost_as_gpu::~nvhost_as_gpu() = default; 27nvhost_as_gpu::~nvhost_as_gpu() = default;
28 28
29u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 29u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
30 IoctlCtrl& ctrl) { 30 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
31 IoctlVersion version) {
31 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 32 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
32 command.raw, input.size(), output.size()); 33 command.raw, input.size(), output.size());
33 34
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 30ca5f4c3..169fb8f0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -20,8 +20,9 @@ public:
20 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
21 ~nvhost_as_gpu() override; 21 ~nvhost_as_gpu() override;
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 23 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
24 IoctlCtrl& ctrl) override; 24 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
25 IoctlVersion version) override;
25 26
26private: 27private:
27 enum class IoctlCommand : u32_le { 28 enum class IoctlCommand : u32_le {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 9a66a5f88..ff6b1abae 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -19,8 +19,9 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface)
19 : nvdevice(system), events_interface{events_interface} {} 19 : nvdevice(system), events_interface{events_interface} {}
20nvhost_ctrl::~nvhost_ctrl() = default; 20nvhost_ctrl::~nvhost_ctrl() = default;
21 21
22u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 22u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
23 IoctlCtrl& ctrl) { 23 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
24 IoctlVersion version) {
24 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 25 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
25 command.raw, input.size(), output.size()); 26 command.raw, input.size(), output.size());
26 27
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 14e6e7e57..9898623de 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -17,8 +17,9 @@ public:
17 explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); 17 explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface);
18 ~nvhost_ctrl() override; 18 ~nvhost_ctrl() override;
19 19
20 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 20 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
21 IoctlCtrl& ctrl) override; 21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
22 IoctlVersion version) override;
22 23
23private: 24private:
24 enum class IoctlCommand : u32_le { 25 enum class IoctlCommand : u32_le {
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 988effd90..389ace76f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -15,14 +15,15 @@ namespace Service::Nvidia::Devices {
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; 16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
17 17
18u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 18u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input,
19 IoctlCtrl& ctrl) { 19 const std::vector<u8>& input2, std::vector<u8>& output,
20 std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) {
20 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
21 command.raw, input.size(), output.size()); 22 command.raw, input.size(), output.size());
22 23
23 switch (static_cast<IoctlCommand>(command.raw)) { 24 switch (static_cast<IoctlCommand>(command.raw)) {
24 case IoctlCommand::IocGetCharacteristicsCommand: 25 case IoctlCommand::IocGetCharacteristicsCommand:
25 return GetCharacteristics(input, output); 26 return GetCharacteristics(input, output, output2, version);
26 case IoctlCommand::IocGetTPCMasksCommand: 27 case IoctlCommand::IocGetTPCMasksCommand:
27 return GetTPCMasks(input, output); 28 return GetTPCMasks(input, output);
28 case IoctlCommand::IocGetActiveSlotMaskCommand: 29 case IoctlCommand::IocGetActiveSlotMaskCommand:
@@ -44,7 +45,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
44 return 0; 45 return 0;
45} 46}
46 47
47u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) { 48u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
49 std::vector<u8>& output2, IoctlVersion version) {
48 LOG_DEBUG(Service_NVDRV, "called"); 50 LOG_DEBUG(Service_NVDRV, "called");
49 IoctlCharacteristics params{}; 51 IoctlCharacteristics params{};
50 std::memcpy(&params, input.data(), input.size()); 52 std::memcpy(&params, input.data(), input.size());
@@ -85,7 +87,13 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
85 params.gc.gr_compbit_store_base_hw = 0x0; 87 params.gc.gr_compbit_store_base_hw = 0x0;
86 params.gpu_characteristics_buf_size = 0xA0; 88 params.gpu_characteristics_buf_size = 0xA0;
87 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 89 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
88 std::memcpy(output.data(), &params, output.size()); 90
91 if (version == IoctlVersion::Version3) {
92 std::memcpy(output.data(), input.data(), output.size());
93 std::memcpy(output2.data(), &params.gc, output2.size());
94 } else {
95 std::memcpy(output.data(), &params, output.size());
96 }
89 return 0; 97 return 0;
90} 98}
91 99
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 2b035ae3f..642b0a2cb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -16,8 +16,9 @@ public:
16 explicit nvhost_ctrl_gpu(Core::System& system); 16 explicit nvhost_ctrl_gpu(Core::System& system);
17 ~nvhost_ctrl_gpu() override; 17 ~nvhost_ctrl_gpu() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
20 IoctlCtrl& ctrl) override; 20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
21 IoctlVersion version) override;
21 22
22private: 23private:
23 enum class IoctlCommand : u32_le { 24 enum class IoctlCommand : u32_le {
@@ -162,7 +163,8 @@ private:
162 }; 163 };
163 static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); 164 static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
164 165
165 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); 166 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
167 std::vector<u8>& output2, IoctlVersion version);
166 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); 168 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
167 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 169 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
168 u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); 170 u32 ZCullGetCtxSize(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 b4ee2a255..2b8d1bef6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -17,8 +17,9 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
17 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 17 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
18nvhost_gpu::~nvhost_gpu() = default; 18nvhost_gpu::~nvhost_gpu() = default;
19 19
20u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 20u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
21 IoctlCtrl& ctrl) { 21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
22 IoctlVersion version) {
22 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 23 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
23 command.raw, input.size(), output.size()); 24 command.raw, input.size(), output.size());
24 25
@@ -50,7 +51,7 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
50 return SubmitGPFIFO(input, output); 51 return SubmitGPFIFO(input, output);
51 } 52 }
52 if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { 53 if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
53 return KickoffPB(input, output); 54 return KickoffPB(input, output, input2, version);
54 } 55 }
55 } 56 }
56 57
@@ -173,7 +174,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
173 return 0; 174 return 0;
174} 175}
175 176
176u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) { 177u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
178 const std::vector<u8>& input2, IoctlVersion version) {
177 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 179 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
178 UNIMPLEMENTED(); 180 UNIMPLEMENTED();
179 } 181 }
@@ -183,9 +185,13 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
183 params.num_entries, params.flags.raw); 185 params.num_entries, params.flags.raw);
184 186
185 Tegra::CommandList entries(params.num_entries); 187 Tegra::CommandList entries(params.num_entries);
186 Memory::ReadBlock(params.address, entries.data(), 188 if (version == IoctlVersion::Version2) {
187 params.num_entries * sizeof(Tegra::CommandListHeader)); 189 std::memcpy(entries.data(), input2.data(),
188 190 params.num_entries * sizeof(Tegra::CommandListHeader));
191 } else {
192 Memory::ReadBlock(params.address, entries.data(),
193 params.num_entries * sizeof(Tegra::CommandListHeader));
194 }
189 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); 195 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
190 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); 196 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
191 197
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index d2e8fbae9..d056dd046 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -24,8 +24,9 @@ public:
24 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 24 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
25 ~nvhost_gpu() override; 25 ~nvhost_gpu() override;
26 26
27 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 27 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
28 IoctlCtrl& ctrl) override; 28 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
29 IoctlVersion version) override;
29 30
30private: 31private:
31 enum class IoctlCommand : u32_le { 32 enum class IoctlCommand : u32_le {
@@ -183,7 +184,8 @@ private:
183 u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); 184 u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
184 u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); 185 u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
185 u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); 186 u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
186 u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output); 187 u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
188 const std::vector<u8>& input2, IoctlVersion version);
187 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 189 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
188 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); 190 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
189 191
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index f572ad30f..bdae8b887 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices {
13nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} 13nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {}
14nvhost_nvdec::~nvhost_nvdec() = default; 14nvhost_nvdec::~nvhost_nvdec() = default;
15 15
16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
17 IoctlCtrl& ctrl) { 17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
18 IoctlVersion version) {
18 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
19 command.raw, input.size(), output.size()); 20 command.raw, input.size(), output.size());
20 21
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 2710f0511..cbdac8069 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -16,8 +16,9 @@ public:
16 explicit nvhost_nvdec(Core::System& system); 16 explicit nvhost_nvdec(Core::System& system);
17 ~nvhost_nvdec() override; 17 ~nvhost_nvdec() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
20 IoctlCtrl& ctrl) override; 20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
21 IoctlVersion version) override;
21 22
22private: 23private:
23 enum class IoctlCommand : u32_le { 24 enum class IoctlCommand : u32_le {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 38282956f..96e7b7dab 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices {
13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} 13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
14nvhost_nvjpg::~nvhost_nvjpg() = default; 14nvhost_nvjpg::~nvhost_nvjpg() = default;
15 15
16u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 16u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
17 IoctlCtrl& ctrl) { 17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
18 IoctlVersion version) {
18 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
19 command.raw, input.size(), output.size()); 20 command.raw, input.size(), output.size());
20 21
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 379766693..98dcac52f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -16,8 +16,9 @@ public:
16 explicit nvhost_nvjpg(Core::System& system); 16 explicit nvhost_nvjpg(Core::System& system);
17 ~nvhost_nvjpg() override; 17 ~nvhost_nvjpg() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
20 IoctlCtrl& ctrl) override; 20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
21 IoctlVersion version) override;
21 22
22private: 23private:
23 enum class IoctlCommand : u32_le { 24 enum class IoctlCommand : u32_le {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 70e8091db..c695b8863 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -13,8 +13,9 @@ namespace Service::Nvidia::Devices {
13nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} 13nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
14nvhost_vic::~nvhost_vic() = default; 14nvhost_vic::~nvhost_vic() = default;
15 15
16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
17 IoctlCtrl& ctrl) { 17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
18 IoctlVersion version) {
18 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
19 command.raw, input.size(), output.size()); 20 command.raw, input.size(), output.size());
20 21
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index 7d111977e..bec32bea1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -16,8 +16,9 @@ public:
16 explicit nvhost_vic(Core::System& system); 16 explicit nvhost_vic(Core::System& system);
17 ~nvhost_vic() override; 17 ~nvhost_vic() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
20 IoctlCtrl& ctrl) override; 20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
21 IoctlVersion version) override;
21 22
22private: 23private:
23 enum class IoctlCommand : u32_le { 24 enum class IoctlCommand : u32_le {
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 223b496b7..8c742316c 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -28,8 +28,9 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
28 return object->addr; 28 return object->addr;
29} 29}
30 30
31u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 31u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
32 IoctlCtrl& ctrl) { 32 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
33 IoctlVersion version) {
33 switch (static_cast<IoctlCommand>(command.raw)) { 34 switch (static_cast<IoctlCommand>(command.raw)) {
34 case IoctlCommand::Create: 35 case IoctlCommand::Create:
35 return IocCreate(input, output); 36 return IocCreate(input, output);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index bf4a101c2..73c2e8809 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -22,8 +22,9 @@ public:
22 /// Returns the allocated address of an nvmap object given its handle. 22 /// Returns the allocated address of an nvmap object given its handle.
23 VAddr GetObjectAddress(u32 handle) const; 23 VAddr GetObjectAddress(u32 handle) const;
24 24
25 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, 25 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
26 IoctlCtrl& ctrl) override; 26 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
27 IoctlVersion version) override;
27 28
28 /// Represents an nvmap object. 29 /// Represents an nvmap object.
29 struct Object { 30 struct Object {
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index d5be64ed2..5e0c23602 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -33,42 +33,77 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {
33 rb.Push<u32>(0); 33 rb.Push<u32>(0);
34} 34}
35 35
36void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { 36void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
37 LOG_DEBUG(Service_NVDRV, "called");
38
39 IPC::RequestParser rp{ctx}; 37 IPC::RequestParser rp{ctx};
40 u32 fd = rp.Pop<u32>(); 38 u32 fd = rp.Pop<u32>();
41 u32 command = rp.Pop<u32>(); 39 u32 command = rp.Pop<u32>();
42 40
43 std::vector<u8> output(ctx.GetWriteBufferSize()); 41 /// Ioctl 3 has 2 outputs, first in the input params, second is the result
42 std::vector<u8> output(ctx.GetWriteBufferSize(0));
43 std::vector<u8> output2;
44 if (version == IoctlVersion::Version3) {
45 output2.resize((ctx.GetWriteBufferSize(1)));
46 }
47
48 /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer.
49 /// KickOfPB uses this
50 auto input = ctx.ReadBuffer(0);
51
52 std::vector<u8> input2;
53 if (version == IoctlVersion::Version2) {
54 input2 = ctx.ReadBuffer(1);
55 }
44 56
45 IoctlCtrl ctrl{}; 57 IoctlCtrl ctrl{};
46 58
47 u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output, ctrl); 59 u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
48 60
49 if (ctrl.must_delay) { 61 if (ctrl.must_delay) {
50 ctrl.fresh_call = false; 62 ctrl.fresh_call = false;
51 ctx.SleepClientThread( 63 ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout,
52 "NVServices::DelayedResponse", ctrl.timeout, 64 [=](Kernel::SharedPtr<Kernel::Thread> thread,
53 [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, 65 Kernel::HLERequestContext& ctx,
54 Kernel::ThreadWakeupReason reason) { 66 Kernel::ThreadWakeupReason reason) {
55 IoctlCtrl ctrl2{ctrl}; 67 IoctlCtrl ctrl2{ctrl};
56 std::vector<u8> output2 = output; 68 std::vector<u8> tmp_output = output;
57 u32 result = nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output2, ctrl2); 69 std::vector<u8> tmp_output2 = output2;
58 ctx.WriteBuffer(output2); 70 u32 result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
59 IPC::ResponseBuilder rb{ctx, 3}; 71 tmp_output2, ctrl2, version);
60 rb.Push(RESULT_SUCCESS); 72 ctx.WriteBuffer(tmp_output, 0);
61 rb.Push(result); 73 if (version == IoctlVersion::Version3) {
62 }, 74 ctx.WriteBuffer(tmp_output2, 1);
63 nvdrv->GetEventWriteable(ctrl.event_id)); 75 }
76 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS);
78 rb.Push(result);
79 },
80 nvdrv->GetEventWriteable(ctrl.event_id));
64 } else { 81 } else {
65 ctx.WriteBuffer(output); 82 ctx.WriteBuffer(output);
83 if (version == IoctlVersion::Version3) {
84 ctx.WriteBuffer(output2, 1);
85 }
66 } 86 }
67 IPC::ResponseBuilder rb{ctx, 3}; 87 IPC::ResponseBuilder rb{ctx, 3};
68 rb.Push(RESULT_SUCCESS); 88 rb.Push(RESULT_SUCCESS);
69 rb.Push(result); 89 rb.Push(result);
70} 90}
71 91
92void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
93 LOG_DEBUG(Service_NVDRV, "called");
94 IoctlBase(ctx, IoctlVersion::Version1);
95}
96
97void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
98 LOG_DEBUG(Service_NVDRV, "called");
99 IoctlBase(ctx, IoctlVersion::Version2);
100}
101
102void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
103 LOG_DEBUG(Service_NVDRV, "called");
104 IoctlBase(ctx, IoctlVersion::Version3);
105}
106
72void NVDRV::Close(Kernel::HLERequestContext& ctx) { 107void NVDRV::Close(Kernel::HLERequestContext& ctx) {
73 LOG_DEBUG(Service_NVDRV, "called"); 108 LOG_DEBUG(Service_NVDRV, "called");
74 109
@@ -154,8 +189,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
154 {8, &NVDRV::SetClientPID, "SetClientPID"}, 189 {8, &NVDRV::SetClientPID, "SetClientPID"},
155 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, 190 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
156 {10, nullptr, "InitializeDevtools"}, 191 {10, nullptr, "InitializeDevtools"},
157 {11, &NVDRV::Ioctl, "Ioctl2"}, 192 {11, &NVDRV::Ioctl2, "Ioctl2"},
158 {12, nullptr, "Ioctl3"}, 193 {12, &NVDRV::Ioctl3, "Ioctl3"},
159 {13, &NVDRV::FinishInitialize, "FinishInitialize"}, 194 {13, &NVDRV::FinishInitialize, "FinishInitialize"},
160 }; 195 };
161 RegisterHandlers(functions); 196 RegisterHandlers(functions);
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 10a0ecd52..9269ce00c 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -24,6 +24,8 @@ public:
24private: 24private:
25 void Open(Kernel::HLERequestContext& ctx); 25 void Open(Kernel::HLERequestContext& ctx);
26 void Ioctl(Kernel::HLERequestContext& ctx); 26 void Ioctl(Kernel::HLERequestContext& ctx);
27 void Ioctl2(Kernel::HLERequestContext& ctx);
28 void Ioctl3(Kernel::HLERequestContext& ctx);
27 void Close(Kernel::HLERequestContext& ctx); 29 void Close(Kernel::HLERequestContext& ctx);
28 void Initialize(Kernel::HLERequestContext& ctx); 30 void Initialize(Kernel::HLERequestContext& ctx);
29 void QueryEvent(Kernel::HLERequestContext& ctx); 31 void QueryEvent(Kernel::HLERequestContext& ctx);
@@ -31,6 +33,7 @@ private:
31 void FinishInitialize(Kernel::HLERequestContext& ctx); 33 void FinishInitialize(Kernel::HLERequestContext& ctx);
32 void GetStatus(Kernel::HLERequestContext& ctx); 34 void GetStatus(Kernel::HLERequestContext& ctx);
33 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); 35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
36 void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
34 37
35 std::shared_ptr<Module> nvdrv; 38 std::shared_ptr<Module> nvdrv;
36 39
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index ac03cbc23..529b03471 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -34,6 +34,12 @@ enum class EventState {
34 Busy = 3, 34 Busy = 3,
35}; 35};
36 36
37enum class IoctlVersion : u32 {
38 Version1,
39 Version2,
40 Version3,
41};
42
37struct IoctlCtrl { 43struct IoctlCtrl {
38 // First call done to the servioce for services that call itself again after a call. 44 // First call done to the servioce for services that call itself again after a call.
39 bool fresh_call{true}; 45 bool fresh_call{true};
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 2011a226a..307a7e928 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -71,13 +71,14 @@ u32 Module::Open(const std::string& device_name) {
71 return fd; 71 return fd;
72} 72}
73 73
74u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, 74u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
75 IoctlCtrl& ctrl) { 75 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
76 IoctlVersion version) {
76 auto itr = open_files.find(fd); 77 auto itr = open_files.find(fd);
77 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 78 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
78 79
79 auto& device = itr->second; 80 auto& device = itr->second;
80 return device->ioctl({command}, input, output, ctrl); 81 return device->ioctl({command}, input, input2, output, output2, ctrl, version);
81} 82}
82 83
83ResultCode Module::Close(u32 fd) { 84ResultCode Module::Close(u32 fd) {
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a339ab672..f8bb28969 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -106,8 +106,9 @@ public:
106 /// Opens a device node and returns a file descriptor to it. 106 /// Opens a device node and returns a file descriptor to it.
107 u32 Open(const std::string& device_name); 107 u32 Open(const std::string& device_name);
108 /// Sends an ioctl command to the specified file descriptor. 108 /// Sends an ioctl command to the specified file descriptor.
109 u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output, 109 u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
110 IoctlCtrl& ctrl); 110 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
111 IoctlVersion version);
111 /// Closes a device file descriptor and returns operation success. 112 /// Closes a device file descriptor and returns operation success.
112 ResultCode Close(u32 fd); 113 ResultCode Close(u32 fd);
113 114
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index f9db79370..2e4d707b9 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -29,26 +29,28 @@ namespace Service::NVFlinger {
29constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); 29constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
30constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); 30constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
31 31
32NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { 32NVFlinger::NVFlinger(Core::System& system) : system(system) {
33 displays.emplace_back(0, "Default"); 33 displays.emplace_back(0, "Default", system);
34 displays.emplace_back(1, "External"); 34 displays.emplace_back(1, "External", system);
35 displays.emplace_back(2, "Edid"); 35 displays.emplace_back(2, "Edid", system);
36 displays.emplace_back(3, "Internal"); 36 displays.emplace_back(3, "Internal", system);
37 displays.emplace_back(4, "Null"); 37 displays.emplace_back(4, "Null", system);
38 38
39 // Schedule the screen composition events 39 // Schedule the screen composition events
40 composition_event = core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, 40 composition_event = system.CoreTiming().RegisterEvent(
41 s64 cycles_late) { 41 "ScreenComposition", [this](u64 userdata, s64 cycles_late) {
42 Compose(); 42 Compose();
43 const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); 43 const auto ticks =
44 this->core_timing.ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late), composition_event); 44 Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks();
45 }); 45 this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late),
46 46 composition_event);
47 core_timing.ScheduleEvent(frame_ticks, composition_event); 47 });
48
49 system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
48} 50}
49 51
50NVFlinger::~NVFlinger() { 52NVFlinger::~NVFlinger() {
51 core_timing.UnscheduleEvent(composition_event, 0); 53 system.CoreTiming().UnscheduleEvent(composition_event, 0);
52} 54}
53 55
54void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 56void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -185,11 +187,9 @@ void NVFlinger::Compose() {
185 MicroProfileFlip(); 187 MicroProfileFlip();
186 188
187 if (!buffer) { 189 if (!buffer) {
188 auto& system_instance = Core::System::GetInstance();
189
190 // There was no queued buffer to draw, render previous frame 190 // There was no queued buffer to draw, render previous frame
191 system_instance.GetPerfStats().EndGameFrame(); 191 system.GetPerfStats().EndGameFrame();
192 system_instance.GPU().SwapBuffers({}); 192 system.GPU().SwapBuffers({});
193 continue; 193 continue;
194 } 194 }
195 195
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 988be8726..5d7e3bfb8 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -38,7 +38,7 @@ class BufferQueue;
38 38
39class NVFlinger final { 39class NVFlinger final {
40public: 40public:
41 explicit NVFlinger(Core::Timing::CoreTiming& core_timing); 41 explicit NVFlinger(Core::System& system);
42 ~NVFlinger(); 42 ~NVFlinger();
43 43
44 /// Sets the NVDrv module instance to use to send buffers to the GPU. 44 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -105,8 +105,7 @@ private:
105 /// Event that handles screen composition. 105 /// Event that handles screen composition.
106 Core::Timing::EventType* composition_event; 106 Core::Timing::EventType* composition_event;
107 107
108 /// Core timing instance for registering/unregistering the composition event. 108 Core::System& system;
109 Core::Timing::CoreTiming& core_timing;
110}; 109};
111 110
112} // namespace Service::NVFlinger 111} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 0f79135ff..18d895263 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -15,7 +15,7 @@ namespace Service::PlayReport {
15 15
16class PlayReport final : public ServiceFramework<PlayReport> { 16class PlayReport final : public ServiceFramework<PlayReport> {
17public: 17public:
18 explicit PlayReport(Core::System& system, const char* name) 18 explicit PlayReport(const char* name, Core::System& system)
19 : ServiceFramework{name}, system(system) { 19 : ServiceFramework{name}, system(system) {
20 // clang-format off 20 // clang-format off
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
@@ -128,12 +128,12 @@ private:
128 Core::System& system; 128 Core::System& system;
129}; 129};
130 130
131void InstallInterfaces(Core::System& system) { 131void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
132 std::make_shared<PlayReport>(system, "prepo:a")->InstallAsService(system.ServiceManager()); 132 std::make_shared<PlayReport>("prepo:a", system)->InstallAsService(service_manager);
133 std::make_shared<PlayReport>(system, "prepo:a2")->InstallAsService(system.ServiceManager()); 133 std::make_shared<PlayReport>("prepo:a2", system)->InstallAsService(service_manager);
134 std::make_shared<PlayReport>(system, "prepo:m")->InstallAsService(system.ServiceManager()); 134 std::make_shared<PlayReport>("prepo:m", system)->InstallAsService(service_manager);
135 std::make_shared<PlayReport>(system, "prepo:s")->InstallAsService(system.ServiceManager()); 135 std::make_shared<PlayReport>("prepo:s", system)->InstallAsService(service_manager);
136 std::make_shared<PlayReport>(system, "prepo:u")->InstallAsService(system.ServiceManager()); 136 std::make_shared<PlayReport>("prepo:u", system)->InstallAsService(service_manager);
137} 137}
138 138
139} // namespace Service::PlayReport 139} // namespace Service::PlayReport
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index 0ebc3a938..a5682ee26 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -8,8 +8,12 @@ namespace Service::SM {
8class ServiceManager; 8class ServiceManager;
9} 9}
10 10
11namespace Core {
12class System;
13}
14
11namespace Service::PlayReport { 15namespace Service::PlayReport {
12 16
13void InstallInterfaces(Core::System& system); 17void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
14 18
15} // namespace Service::PlayReport 19} // namespace Service::PlayReport
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 906fdc415..f2c6fe9dc 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -198,50 +198,50 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
198void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { 198void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
200 // here and pass it into the respective InstallInterfaces functions. 200 // here and pass it into the respective InstallInterfaces functions.
201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
202 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); 202 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
203 203
204 SM::ServiceManager::InstallInterfaces(sm); 204 SM::ServiceManager::InstallInterfaces(sm);
205 205
206 Account::InstallInterfaces(system); 206 Account::InstallInterfaces(system);
207 AM::InstallInterfaces(*sm, nv_flinger, system); 207 AM::InstallInterfaces(*sm, nv_flinger, system);
208 AOC::InstallInterfaces(*sm); 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); 213 BtDrv::InstallInterfaces(*sm, system);
214 BTM::InstallInterfaces(*sm); 214 BTM::InstallInterfaces(*sm, system);
215 Capture::InstallInterfaces(*sm); 215 Capture::InstallInterfaces(*sm);
216 ERPT::InstallInterfaces(*sm); 216 ERPT::InstallInterfaces(*sm);
217 ES::InstallInterfaces(*sm); 217 ES::InstallInterfaces(*sm);
218 EUPLD::InstallInterfaces(*sm); 218 EUPLD::InstallInterfaces(*sm);
219 Fatal::InstallInterfaces(*sm); 219 Fatal::InstallInterfaces(*sm, system);
220 FGM::InstallInterfaces(*sm); 220 FGM::InstallInterfaces(*sm);
221 FileSystem::InstallInterfaces(system); 221 FileSystem::InstallInterfaces(system);
222 Friend::InstallInterfaces(*sm); 222 Friend::InstallInterfaces(*sm, system);
223 Glue::InstallInterfaces(system); 223 Glue::InstallInterfaces(system);
224 GRC::InstallInterfaces(*sm); 224 GRC::InstallInterfaces(*sm);
225 HID::InstallInterfaces(*sm); 225 HID::InstallInterfaces(*sm, system);
226 LBL::InstallInterfaces(*sm); 226 LBL::InstallInterfaces(*sm);
227 LDN::InstallInterfaces(*sm); 227 LDN::InstallInterfaces(*sm);
228 LDR::InstallInterfaces(*sm); 228 LDR::InstallInterfaces(*sm, system);
229 LM::InstallInterfaces(*sm); 229 LM::InstallInterfaces(*sm);
230 Migration::InstallInterfaces(*sm); 230 Migration::InstallInterfaces(*sm);
231 Mii::InstallInterfaces(*sm); 231 Mii::InstallInterfaces(*sm);
232 MM::InstallInterfaces(*sm); 232 MM::InstallInterfaces(*sm);
233 NCM::InstallInterfaces(*sm); 233 NCM::InstallInterfaces(*sm);
234 NFC::InstallInterfaces(*sm); 234 NFC::InstallInterfaces(*sm);
235 NFP::InstallInterfaces(*sm); 235 NFP::InstallInterfaces(*sm, system);
236 NIFM::InstallInterfaces(*sm); 236 NIFM::InstallInterfaces(*sm, system);
237 NIM::InstallInterfaces(*sm); 237 NIM::InstallInterfaces(*sm, system);
238 NPNS::InstallInterfaces(*sm); 238 NPNS::InstallInterfaces(*sm);
239 NS::InstallInterfaces(*sm, system.GetFileSystemController()); 239 NS::InstallInterfaces(*sm, system);
240 Nvidia::InstallInterfaces(*sm, *nv_flinger, system); 240 Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
241 PCIe::InstallInterfaces(*sm); 241 PCIe::InstallInterfaces(*sm);
242 PCTL::InstallInterfaces(*sm); 242 PCTL::InstallInterfaces(*sm);
243 PCV::InstallInterfaces(*sm); 243 PCV::InstallInterfaces(*sm);
244 PlayReport::InstallInterfaces(system); 244 PlayReport::InstallInterfaces(*sm, system);
245 PM::InstallInterfaces(system); 245 PM::InstallInterfaces(system);
246 PSC::InstallInterfaces(*sm); 246 PSC::InstallInterfaces(*sm);
247 PSM::InstallInterfaces(*sm); 247 PSM::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 1030185e0..9565e7de5 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -7,8 +7,8 @@
7namespace Service::Time { 7namespace Service::Time {
8 8
9Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, 9Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
10 const char* name) 10 Core::System& system, const char* name)
11 : Module::Interface(std::move(time), std::move(shared_memory), name) { 11 : Module::Interface(std::move(time), std::move(shared_memory), system, name) {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 14 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h
index bdf0883e2..5c63a07f4 100644
--- a/src/core/hle/service/time/interface.h
+++ b/src/core/hle/service/time/interface.h
@@ -13,7 +13,7 @@ class SharedMemory;
13class Time final : public Module::Interface { 13class Time final : public Module::Interface {
14public: 14public:
15 explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, 15 explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
16 const char* name); 16 Core::System& system, const char* name);
17 ~Time() override; 17 ~Time() override;
18}; 18};
19 19
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index ae6446204..1b9ab8401 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -126,8 +126,8 @@ private:
126 126
127class ISteadyClock final : public ServiceFramework<ISteadyClock> { 127class ISteadyClock final : public ServiceFramework<ISteadyClock> {
128public: 128public:
129 ISteadyClock(std::shared_ptr<SharedMemory> shared_memory) 129 ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system)
130 : ServiceFramework("ISteadyClock"), shared_memory(shared_memory) { 130 : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) {
131 static const FunctionInfo functions[] = { 131 static const FunctionInfo functions[] = {
132 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, 132 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
133 }; 133 };
@@ -150,12 +150,13 @@ private:
150 } 150 }
151 151
152 SteadyClockTimePoint GetCurrentTimePoint() const { 152 SteadyClockTimePoint GetCurrentTimePoint() const {
153 const auto& core_timing = Core::System::GetInstance().CoreTiming(); 153 const auto& core_timing = system.CoreTiming();
154 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); 154 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
155 return {static_cast<u64_le>(ms.count() / 1000), {}}; 155 return {static_cast<u64_le>(ms.count() / 1000), {}};
156 } 156 }
157 157
158 std::shared_ptr<SharedMemory> shared_memory; 158 std::shared_ptr<SharedMemory> shared_memory;
159 Core::System& system;
159}; 160};
160 161
161class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { 162class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@@ -290,7 +291,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
290 291
291 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 292 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
292 rb.Push(RESULT_SUCCESS); 293 rb.Push(RESULT_SUCCESS);
293 rb.PushIpcInterface<ISteadyClock>(shared_memory); 294 rb.PushIpcInterface<ISteadyClock>(shared_memory, system);
294} 295}
295 296
296void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 297void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
@@ -325,7 +326,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
325 return; 326 return;
326 } 327 }
327 328
328 const auto& core_timing = Core::System::GetInstance().CoreTiming(); 329 const auto& core_timing = system.CoreTiming();
329 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); 330 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
330 const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; 331 const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}};
331 332
@@ -407,8 +408,10 @@ void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
407} 408}
408 409
409Module::Interface::Interface(std::shared_ptr<Module> time, 410Module::Interface::Interface(std::shared_ptr<Module> time,
410 std::shared_ptr<SharedMemory> shared_memory, const char* name) 411 std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
411 : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {} 412 const char* name)
413 : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)),
414 system(system) {}
412 415
413Module::Interface::~Interface() = default; 416Module::Interface::~Interface() = default;
414 417
@@ -416,9 +419,11 @@ void InstallInterfaces(Core::System& system) {
416 auto time = std::make_shared<Module>(); 419 auto time = std::make_shared<Module>();
417 auto shared_mem = std::make_shared<SharedMemory>(system); 420 auto shared_mem = std::make_shared<SharedMemory>(system);
418 421
419 std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager()); 422 std::make_shared<Time>(time, shared_mem, system, "time:a")
420 std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager()); 423 ->InstallAsService(system.ServiceManager());
421 std::make_shared<Time>(std::move(time), shared_mem, "time:u") 424 std::make_shared<Time>(time, shared_mem, system, "time:s")
425 ->InstallAsService(system.ServiceManager());
426 std::make_shared<Time>(std::move(time), shared_mem, system, "time:u")
422 ->InstallAsService(system.ServiceManager()); 427 ->InstallAsService(system.ServiceManager());
423} 428}
424 429
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index e0708f856..c32d32860 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -80,7 +80,8 @@ public:
80 class Interface : public ServiceFramework<Interface> { 80 class Interface : public ServiceFramework<Interface> {
81 public: 81 public:
82 explicit Interface(std::shared_ptr<Module> time, 82 explicit Interface(std::shared_ptr<Module> time,
83 std::shared_ptr<SharedMemory> shared_memory, const char* name); 83 std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
84 const char* name);
84 ~Interface() override; 85 ~Interface() override;
85 86
86 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); 87 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -97,6 +98,7 @@ public:
97 protected: 98 protected:
98 std::shared_ptr<Module> time; 99 std::shared_ptr<Module> time;
99 std::shared_ptr<SharedMemory> shared_memory; 100 std::shared_ptr<SharedMemory> shared_memory;
101 Core::System& system;
100 }; 102 };
101}; 103};
102 104
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index a8d088305..006a6d9ff 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -15,8 +15,8 @@
15 15
16namespace Service::VI { 16namespace Service::VI {
17 17
18Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} { 18Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} {
19 auto& kernel = Core::System::GetInstance().Kernel(); 19 auto& kernel = system.Kernel();
20 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 20 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
21 fmt::format("Display VSync Event {}", id)); 21 fmt::format("Display VSync Event {}", id));
22} 22}
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 2acd46ff8..f56b5badc 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -26,7 +26,7 @@ public:
26 /// @param id The unique ID for this display. 26 /// @param id The unique ID for this display.
27 /// @param name The name for this display. 27 /// @param name The name for this display.
28 /// 28 ///
29 Display(u64 id, std::string name); 29 Display(u64 id, std::string name, Core::System& system);
30 ~Display(); 30 ~Display();
31 31
32 Display(const Display&) = delete; 32 Display(const Display&) = delete;
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/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;