summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/acc/acc.cpp264
-rw-r--r--src/core/hle/service/acc/acc.h30
-rw-r--r--src/core/hle/service/acc/acc_aa.cpp5
-rw-r--r--src/core/hle/service/acc/acc_aa.h4
-rw-r--r--src/core/hle/service/acc/acc_su.cpp7
-rw-r--r--src/core/hle/service/acc/acc_su.h4
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp9
-rw-r--r--src/core/hle/service/acc/acc_u0.h4
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp5
-rw-r--r--src/core/hle/service/acc/acc_u1.h4
-rw-r--r--src/core/hle/service/acc/errors.h14
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp11
-rw-r--r--src/core/hle/service/acc/profile_manager.h2
-rw-r--r--src/core/hle/service/am/am.cpp194
-rw-r--r--src/core/hle/service/am/am.h50
-rw-r--r--src/core/hle/service/am/applet_ae.cpp40
-rw-r--r--src/core/hle/service/am/applet_ae.h9
-rw-r--r--src/core/hle/service/am/applet_oe.cpp21
-rw-r--r--src/core/hle/service/am/applet_oe.h9
-rw-r--r--src/core/hle/service/am/applets/applets.cpp90
-rw-r--r--src/core/hle/service/am/applets/applets.h43
-rw-r--r--src/core/hle/service/am/applets/error.cpp22
-rw-r--r--src/core/hle/service/am/applets/error.h7
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp145
-rw-r--r--src/core/hle/service/am/applets/general_backend.h43
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp5
-rw-r--r--src/core/hle/service/am/applets/profile_select.h7
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp5
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h7
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp499
-rw-r--r--src/core/hle/service/am/applets/web_browser.h41
-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/apm/apm.cpp13
-rw-r--r--src/core/hle/service/apm/apm.h7
-rw-r--r--src/core/hle/service/apm/controller.cpp68
-rw-r--r--src/core/hle/service/apm/controller.h70
-rw-r--r--src/core/hle/service/apm/interface.cpp82
-rw-r--r--src/core/hle/service/apm/interface.h14
-rw-r--r--src/core/hle/service/arp/arp.cpp75
-rw-r--r--src/core/hle/service/arp/arp.h16
-rw-r--r--src/core/hle/service/audio/audio.cpp6
-rw-r--r--src/core/hle/service/audio/audio.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp59
-rw-r--r--src/core/hle/service/audio/audout_u.h12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp257
-rw-r--r--src/core/hle/service/audio/audren_u.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/es/es.cpp230
-rw-r--r--src/core/hle/service/fatal/fatal.cpp55
-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.cpp335
-rw-r--r--src/core/hle/service/filesystem/filesystem.h118
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp132
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h28
-rw-r--r--src/core/hle/service/friend/errors.h12
-rw-r--r--src/core/hle/service/friend/friend.cpp163
-rw-r--r--src/core/hle/service/friend/friend.h10
-rw-r--r--src/core/hle/service/friend/interface.cpp6
-rw-r--r--src/core/hle/service/friend/interface.h2
-rw-r--r--src/core/hle/service/glue/arp.cpp297
-rw-r--r--src/core/hle/service/glue/arp.h43
-rw-r--r--src/core/hle/service/glue/bgtc.cpp50
-rw-r--r--src/core/hle/service/glue/bgtc.h23
-rw-r--r--src/core/hle/service/glue/errors.h16
-rw-r--r--src/core/hle/service/glue/glue.cpp25
-rw-r--r--src/core/hle/service/glue/glue.h16
-rw-r--r--src/core/hle/service/glue/manager.cpp78
-rw-r--r--src/core/hle/service/glue/manager.h63
-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.cpp63
-rw-r--r--src/core/hle/service/hid/controllers/npad.h14
-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/errors.h13
-rw-r--r--src/core/hle/service/hid/hid.cpp100
-rw-r--r--src/core/hle/service/hid/hid.h15
-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.cpp45
-rw-r--r--src/core/hle/service/ldr/ldr.h2
-rw-r--r--src/core/hle/service/mii/mii.cpp16
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp4
-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.cpp30
-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.h13
-rw-r--r--src/core/hle/service/ns/pl_u.cpp23
-rw-r--r--src/core/hle/service/ns/pl_u.h15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp153
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp64
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h45
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h6
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp95
-rw-r--r--src/core/hle/service/nvdrv/interface.h7
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h54
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp60
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h89
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp23
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp39
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h9
-rw-r--r--src/core/hle/service/pm/pm.cpp124
-rw-r--r--src/core/hle/service/pm/pm.h6
-rw-r--r--src/core/hle/service/prepo/prepo.cpp112
-rw-r--r--src/core/hle/service/prepo/prepo.h6
-rw-r--r--src/core/hle/service/service.cpp53
-rw-r--r--src/core/hle/service/service.h11
-rw-r--r--src/core/hle/service/set/set.cpp10
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/time/interface.cpp11
-rw-r--r--src/core/hle/service/time/interface.h5
-rw-r--r--src/core/hle/service/time/time.cpp122
-rw-r--r--src/core/hle/service/time/time.h13
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp68
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h74
-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/hle/service/vi/vi.cpp48
160 files changed, 4900 insertions, 1129 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index cb66e344b..0c0f7ed6e 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -12,16 +12,28 @@
#include "common/swap.h"
#include "core/constants.h"
#include "core/core_timing.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/acc/acc_aa.h"
#include "core/hle/service/acc/acc_su.h"
#include "core/hle/service/acc/acc_u0.h"
#include "core/hle/service/acc/acc_u1.h"
+#include "core/hle/service/acc/errors.h"
#include "core/hle/service/acc/profile_manager.h"
+#include "core/hle/service/glue/arp.h"
+#include "core/hle/service/glue/manager.h"
+#include "core/hle/service/sm/sm.h"
+#include "core/loader/loader.h"
namespace Service::Account {
+constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
+constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
+
static std::string GetImagePath(Common::UUID uuid) {
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
"/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
@@ -32,22 +44,33 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
return static_cast<u32>(std::min(size, max_jpeg_image_size));
}
-class IProfile final : public ServiceFramework<IProfile> {
+class IProfileCommon : public ServiceFramework<IProfileCommon> {
public:
- explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager)
- : ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
+ explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id,
+ ProfileManager& profile_manager)
+ : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) {
static const FunctionInfo functions[] = {
- {0, &IProfile::Get, "Get"},
- {1, &IProfile::GetBase, "GetBase"},
- {10, &IProfile::GetImageSize, "GetImageSize"},
- {11, &IProfile::LoadImage, "LoadImage"},
+ {0, &IProfileCommon::Get, "Get"},
+ {1, &IProfileCommon::GetBase, "GetBase"},
+ {10, &IProfileCommon::GetImageSize, "GetImageSize"},
+ {11, &IProfileCommon::LoadImage, "LoadImage"},
};
+
RegisterHandlers(functions);
+
+ if (editor_commands) {
+ static const FunctionInfo editor_functions[] = {
+ {100, &IProfileCommon::Store, "Store"},
+ {101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
+ };
+
+ RegisterHandlers(editor_functions);
+ }
}
-private:
+protected:
void Get(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
ProfileBase profile_base{};
ProfileData data{};
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
@@ -66,7 +89,7 @@ private:
}
void GetBase(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
ProfileBase profile_base{};
if (profile_manager.GetProfileBase(user_id, profile_base)) {
IPC::ResponseBuilder rb{ctx, 16};
@@ -90,7 +113,7 @@ private:
LOG_WARNING(Service_ACC,
"Failed to load user provided image! Falling back to built-in backup...");
ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG);
- rb.Push<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size());
+ rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
return;
}
@@ -112,16 +135,97 @@ private:
if (!image.IsOpen()) {
LOG_WARNING(Service_ACC,
"Failed to load user provided image! Falling back to built-in backup...");
- rb.Push<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size());
+ rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
} else {
- rb.Push<u32>(SanitizeJPEGSize(image.GetSize()));
+ rb.Push(SanitizeJPEGSize(image.GetSize()));
+ }
+ }
+
+ void Store(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto base = rp.PopRaw<ProfileBase>();
+
+ const auto user_data = ctx.ReadBuffer();
+
+ LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
+ Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(base.username.data()), base.username.size()),
+ base.timestamp, base.user_uuid.Format());
+
+ if (user_data.size() < sizeof(ProfileData)) {
+ LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_BUFFER_SIZE);
+ return;
+ }
+
+ ProfileData data;
+ std::memcpy(&data, user_data.data(), sizeof(ProfileData));
+
+ if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
+ LOG_ERROR(Service_ACC, "Failed to update profile data and base!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_FAILED_SAVE_DATA);
+ return;
}
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
}
- const ProfileManager& profile_manager;
+ void StoreWithImage(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto base = rp.PopRaw<ProfileBase>();
+
+ const auto user_data = ctx.ReadBuffer();
+ const auto image_data = ctx.ReadBuffer(1);
+
+ LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
+ Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(base.username.data()), base.username.size()),
+ base.timestamp, base.user_uuid.Format());
+
+ if (user_data.size() < sizeof(ProfileData)) {
+ LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_BUFFER_SIZE);
+ return;
+ }
+
+ ProfileData data;
+ std::memcpy(&data, user_data.data(), sizeof(ProfileData));
+
+ FileUtil::IOFile image(GetImagePath(user_id), "wb");
+
+ if (!image.IsOpen() || !image.Resize(image_data.size()) ||
+ image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
+ !profile_manager.SetProfileBaseAndData(user_id, base, data)) {
+ LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_FAILED_SAVE_DATA);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ ProfileManager& profile_manager;
Common::UUID user_id; ///< The user id this profile refers to.
};
+class IProfile final : public IProfileCommon {
+public:
+ IProfile(Common::UUID user_id, ProfileManager& profile_manager)
+ : IProfileCommon("IProfile", false, user_id, profile_manager) {}
+};
+
+class IProfileEditor final : public IProfileCommon {
+public:
+ IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager)
+ : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {}
+};
+
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
public:
IManagerForApplication() : ServiceFramework("IManagerForApplication") {
@@ -159,7 +263,7 @@ private:
};
void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called");
+ LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
@@ -168,7 +272,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
- LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
+ LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
@@ -176,21 +280,21 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
}
void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called");
+ LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetAllUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called");
+ LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetOpenUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_ACC, "called");
+ LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
@@ -214,9 +318,71 @@ void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestCon
}
void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_ACC, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto pid = rp.Pop<u64>();
+
+ LOG_DEBUG(Service_ACC, "called, process_id={}", pid);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ rb.Push(InitializeApplicationInfoBase(pid));
+}
+
+void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ auto pid = rp.Pop<u64>();
+
+ LOG_WARNING(Service_ACC, "(Partial implementation) called, process_id={}", pid);
+
+ // TODO(ogniK): We require checking if the user actually owns the title and what not. As of
+ // currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called
+ // first then we do extra checks if the game is a digital copy.
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(InitializeApplicationInfoBase(pid));
+}
+
+ResultCode Module::Interface::InitializeApplicationInfoBase(u64 process_id) {
+ if (application_info) {
+ LOG_ERROR(Service_ACC, "Application already initialized");
+ return ERR_ACCOUNTINFO_ALREADY_INITIALIZED;
+ }
+
+ const auto& list = system.Kernel().GetProcessList();
+ const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
+ return process->GetProcessID() == process_id;
+ });
+
+ if (iter == list.end()) {
+ LOG_ERROR(Service_ACC, "Failed to find process ID");
+ application_info.application_type = ApplicationType::Unknown;
+
+ return ERR_ACCOUNTINFO_BAD_APPLICATION;
+ }
+
+ const auto launch_property = system.GetARPManager().GetLaunchProperty((*iter)->GetTitleID());
+
+ if (launch_property.Failed()) {
+ LOG_ERROR(Service_ACC, "Failed to get launch property");
+ return ERR_ACCOUNTINFO_BAD_APPLICATION;
+ }
+
+ switch (launch_property->base_game_storage_id) {
+ case FileSys::StorageId::GameCard:
+ application_info.application_type = ApplicationType::GameCard;
+ break;
+ case FileSys::StorageId::Host:
+ case FileSys::StorageId::NandUser:
+ case FileSys::StorageId::SdCard:
+ application_info.application_type = ApplicationType::Digital;
+ break;
+ default:
+ LOG_ERROR(Service_ACC, "Invalid game storage ID");
+ return ERR_ACCOUNTINFO_BAD_APPLICATION;
+ }
+
+ LOG_WARNING(Service_ACC, "ApplicationInfo init required");
+ // TODO(ogniK): Actual initalization here
+
+ return RESULT_SUCCESS;
}
void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
@@ -226,6 +392,42 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
rb.PushIpcInterface<IManagerForApplication>();
}
+void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
+ FileSys::NACP nacp;
+ const auto res = system.GetAppLoader().ReadControlData(nacp);
+
+ bool is_locked = false;
+
+ if (res != Loader::ResultStatus::Success) {
+ FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
+ auto nacp_unique = pm.GetControlMetadata().first;
+
+ if (nacp_unique != nullptr) {
+ is_locked = nacp_unique->GetUserAccountSwitchLock();
+ } else {
+ LOG_ERROR(Service_ACC, "nacp_unique is null!");
+ }
+ } else {
+ is_locked = nacp.GetUserAccountSwitchLock();
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(is_locked);
+}
+
+void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ Common::UUID user_id = rp.PopRaw<Common::UUID>();
+
+ LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format());
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager);
+}
+
void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
// A u8 is passed into this function which we can safely ignore. It's to determine if we have
@@ -251,19 +453,25 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
}
Module::Interface::Interface(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager, const char* name)
+ std::shared_ptr<ProfileManager> profile_manager, Core::System& system,
+ const char* name)
: ServiceFramework(name), module(std::move(module)),
- profile_manager(std::move(profile_manager)) {}
+ profile_manager(std::move(profile_manager)), system(system) {}
Module::Interface::~Interface() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(Core::System& system) {
auto module = std::make_shared<Module>();
auto profile_manager = std::make_shared<ProfileManager>();
- std::make_shared<ACC_AA>(module, profile_manager)->InstallAsService(service_manager);
- std::make_shared<ACC_SU>(module, profile_manager)->InstallAsService(service_manager);
- std::make_shared<ACC_U0>(module, profile_manager)->InstallAsService(service_manager);
- std::make_shared<ACC_U1>(module, profile_manager)->InstallAsService(service_manager);
+
+ std::make_shared<ACC_AA>(module, profile_manager, system)
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<ACC_SU>(module, profile_manager, system)
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<ACC_U0>(module, profile_manager, system)
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<ACC_U1>(module, profile_manager, system)
+ ->InstallAsService(system.ServiceManager());
}
} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index 89b2104fa..7a7dc9ec6 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -4,6 +4,7 @@
#pragma once
+#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
namespace Service::Account {
@@ -15,7 +16,8 @@ public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager, const char* name);
+ std::shared_ptr<ProfileManager> profile_manager, Core::System& system,
+ const char* name);
~Interface() override;
void GetUserCount(Kernel::HLERequestContext& ctx);
@@ -25,17 +27,41 @@ public:
void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
void GetProfile(Kernel::HLERequestContext& ctx);
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
+ void InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx);
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
+ void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
+ void GetProfileEditor(Kernel::HLERequestContext& ctx);
+
+ private:
+ ResultCode InitializeApplicationInfoBase(u64 process_id);
+
+ enum class ApplicationType : u32_le {
+ GameCard = 0,
+ Digital = 1,
+ Unknown = 3,
+ };
+
+ struct ApplicationInfo {
+ Service::Glue::ApplicationLaunchProperty launch_property;
+ ApplicationType application_type;
+
+ constexpr explicit operator bool() const {
+ return launch_property.title_id != 0x0;
+ }
+ };
+
+ ApplicationInfo application_info{};
protected:
std::shared_ptr<Module> module;
std::shared_ptr<ProfileManager> profile_manager;
+ Core::System& system;
};
};
/// Registers all ACC services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(Core::System& system);
} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp
index e84d9f7cf..3bac6bcd1 100644
--- a/src/core/hle/service/acc/acc_aa.cpp
+++ b/src/core/hle/service/acc/acc_aa.cpp
@@ -6,8 +6,9 @@
namespace Service::Account {
-ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
- : Module::Interface(std::move(module), std::move(profile_manager), "acc:aa") {
+ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system)
+ : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:aa") {
static const FunctionInfo functions[] = {
{0, nullptr, "EnsureCacheAsync"},
{1, nullptr, "LoadCache"},
diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h
index 9edb0421b..932c04890 100644
--- a/src/core/hle/service/acc/acc_aa.h
+++ b/src/core/hle/service/acc/acc_aa.h
@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_AA final : public Module::Interface {
public:
- explicit ACC_AA(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager);
+ explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system);
~ACC_AA() override;
};
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index d66233cad..0d1663657 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -6,8 +6,9 @@
namespace Service::Account {
-ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
- : Module::Interface(std::move(module), std::move(profile_manager), "acc:su") {
+ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system)
+ : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:su") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_SU::GetUserCount, "GetUserCount"},
@@ -40,7 +41,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{202, nullptr, "CancelUserRegistration"},
{203, nullptr, "DeleteUser"},
{204, nullptr, "SetUserPosition"},
- {205, nullptr, "GetProfileEditor"},
+ {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
{206, nullptr, "CompleteUserRegistrationForcibly"},
{210, nullptr, "CreateFloatingRegistrationRequest"},
{230, nullptr, "AuthenticateServiceAsync"},
diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h
index fcced063a..0a700d9bf 100644
--- a/src/core/hle/service/acc/acc_su.h
+++ b/src/core/hle/service/acc/acc_su.h
@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_SU final : public Module::Interface {
public:
- explicit ACC_SU(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager);
+ explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system);
~ACC_SU() override;
};
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 182f7c7e5..0ac19f4ff 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -6,8 +6,9 @@
namespace Service::Account {
-ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
- : Module::Interface(std::move(module), std::move(profile_manager), "acc:u0") {
+ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system)
+ : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u0") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_U0::GetUserCount, "GetUserCount"},
@@ -30,9 +31,9 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{120, nullptr, "CreateGuestLoginRequest"},
{130, nullptr, "LoadOpenContext"},
{131, nullptr, "ListOpenContextStoredUsers"},
- {140, nullptr, "InitializeApplicationInfo"},
+ {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"},
{141, nullptr, "ListQualifiedUsers"},
- {150, nullptr, "IsUserAccountSwitchLocked"},
+ {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"},
};
// clang-format on
diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h
index a1290e0bd..3bd9c3164 100644
--- a/src/core/hle/service/acc/acc_u0.h
+++ b/src/core/hle/service/acc/acc_u0.h
@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_U0 final : public Module::Interface {
public:
- explicit ACC_U0(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager);
+ explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system);
~ACC_U0() override;
};
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 2dd17d935..6520b3968 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -6,8 +6,9 @@
namespace Service::Account {
-ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager)
- : Module::Interface(std::move(module), std::move(profile_manager), "acc:u1") {
+ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system)
+ : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u1") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_U1::GetUserCount, "GetUserCount"},
diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h
index 9e79daee3..829f8a744 100644
--- a/src/core/hle/service/acc/acc_u1.h
+++ b/src/core/hle/service/acc/acc_u1.h
@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_U1 final : public Module::Interface {
public:
- explicit ACC_U1(std::shared_ptr<Module> module,
- std::shared_ptr<ProfileManager> profile_manager);
+ explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
+ Core::System& system);
~ACC_U1() override;
};
diff --git a/src/core/hle/service/acc/errors.h b/src/core/hle/service/acc/errors.h
new file mode 100644
index 000000000..1f0577239
--- /dev/null
+++ b/src/core/hle/service/acc/errors.h
@@ -0,0 +1,14 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::Account {
+
+constexpr ResultCode ERR_ACCOUNTINFO_BAD_APPLICATION{ErrorModule::Account, 22};
+constexpr ResultCode ERR_ACCOUNTINFO_ALREADY_INITIALIZED{ErrorModule::Account, 41};
+
+} // namespace Service::Account
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 49aa5908b..8f9986326 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -305,6 +305,17 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
return true;
}
+bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
+ const ProfileData& data_new) {
+ const auto index = GetUserIndex(uuid);
+ if (index.has_value() && SetProfileBase(uuid, profile_new)) {
+ profiles[*index].data = data_new;
+ return true;
+ }
+
+ return false;
+}
+
void ProfileManager::ParseUserSaveFile() {
FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat",
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index fd7abb541..5a6d28925 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -91,6 +91,8 @@ public:
bool RemoveUser(Common::UUID uuid);
bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
+ bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
+ const ProfileData& data_new);
private:
void ParseUserSaveFile();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 3f201c821..797c9a06f 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -29,7 +29,8 @@
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
#include "core/hle/service/am/tcap.h"
-#include "core/hle/service/apm/apm.h"
+#include "core/hle/service/apm/controller.h"
+#include "core/hle/service/apm/interface.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -55,7 +56,8 @@ struct LaunchParameters {
};
static_assert(sizeof(LaunchParameters) == 0x88);
-IWindowController::IWindowController() : ServiceFramework("IWindowController") {
+IWindowController::IWindowController(Core::System& system_)
+ : ServiceFramework("IWindowController"), system{system_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
@@ -74,7 +76,7 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
IWindowController::~IWindowController() = default;
void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
- const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID();
+ const u64 process_id = system.CurrentProcess()->GetProcessID();
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
@@ -230,11 +232,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
IDebugFunctions::~IDebugFunctions() = default;
-ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
+ISelfController::ISelfController(Core::System& system,
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
+ : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Exit"},
+ {0, &ISelfController::Exit, "Exit"},
{1, &ISelfController::LockExit, "LockExit"},
{2, &ISelfController::UnlockExit, "UnlockExit"},
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
@@ -265,13 +268,13 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{65, nullptr, "ReportUserIsActive"},
{66, nullptr, "GetCurrentIlluminance"},
{67, nullptr, "IsIlluminanceAvailable"},
- {68, nullptr, "SetAutoSleepDisabled"},
- {69, nullptr, "IsAutoSleepDisabled"},
+ {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
+ {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
{70, nullptr, "ReportMultimediaError"},
{71, nullptr, "GetCurrentIlluminanceEx"},
{80, nullptr, "SetWirelessPriorityMode"},
- {90, nullptr, "GetAccumulatedSuspendedTickValue"},
- {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
+ {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
+ {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, nullptr, "SetAlbumImageTakenNotificationEnabled"},
{1000, nullptr, "GetDebugStorageChannel"},
};
@@ -279,22 +282,44 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"ISelfController:LaunchableEvent");
+
+ // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
+ // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
+ // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
+ // suspended if the event has previously been created by a call to
+ // GetAccumulatedSuspendedTickChangedEvent.
+ accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent");
+ accumulated_suspended_tick_changed_event.writable->Signal();
}
ISelfController::~ISelfController() = default;
+void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ system.Shutdown();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
+
+ system.SetExitLock(true);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ LOG_DEBUG(Service_AM, "called");
+
+ system.SetExitLock(false);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -444,8 +469,54 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
rb.Push<u32>(idle_time_detection_extension);
}
-AppletMessageQueue::AppletMessageQueue() {
- auto& kernel = Core::System::GetInstance().Kernel();
+void ISelfController::SetAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ is_auto_sleep_disabled = rp.Pop<bool>();
+
+ // On the system itself, if the previous state of is_auto_sleep_disabled
+ // differed from the current value passed in, it'd signify the internal
+ // window manager to update (and also increment some statistics like update counts)
+ //
+ // It'd also indicate this change to an idle handling context.
+ //
+ // However, given we're emulating this behavior, most of this can be ignored
+ // and it's sufficient to simply set the member variable for querying via
+ // IsAutoSleepDisabled().
+
+ LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void ISelfController::IsAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(is_auto_sleep_disabled);
+}
+
+void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ // This command returns the total number of system ticks since ISelfController creation
+ // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
+ // can just always return 0 ticks.
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(0);
+}
+
+void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called.");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable);
+}
+
+AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"AMMessageQueue:OnMessageRecieved");
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
@@ -492,8 +563,13 @@ void AppletMessageQueue::OperationModeChanged() {
on_operation_mode_changed.writable->Signal();
}
-ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
- : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
+void AppletMessageQueue::RequestExit() {
+ PushMessage(AppletMessage::ExitRequested);
+}
+
+ICommonStateGetter::ICommonStateGetter(Core::System& system,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -526,7 +602,7 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
{64, nullptr, "SetTvPowerStateMatchingMode"},
{65, nullptr, "GetApplicationIdByContentActionName"},
- {66, nullptr, "SetCpuBoostMode"},
+ {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{80, nullptr, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
@@ -607,6 +683,16 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
}
}
+void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
+
+ const auto& sm = system.ServiceManager();
+ const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
+ ASSERT(apm_sys != nullptr);
+
+ apm_sys->SetCpuBoostMode(ctx);
+}
+
IStorage::IStorage(std::vector<u8> buffer)
: ServiceFramework("IStorage"), buffer(std::move(buffer)) {
// clang-format off
@@ -635,13 +721,11 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
- const bool use_docked_mode{Settings::values.use_docked_mode};
- LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
+ LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
- : APM::PerformanceMode::Handheld));
+ rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
}
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
@@ -871,7 +955,8 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
-ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
+ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
+ : ServiceFramework("ILibraryAppletCreator"), system{system_} {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
@@ -893,7 +978,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
static_cast<u32>(applet_id), applet_mode);
- const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
+ const auto& applet_manager{system.GetAppletManager()};
const auto applet = applet_manager.GetApplet(applet_id);
if (applet == nullptr) {
@@ -931,8 +1016,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
const auto handle{rp.Pop<Kernel::Handle>()};
const auto transfer_mem =
- Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(
- handle);
+ system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
@@ -950,7 +1034,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
}
-IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
+IApplicationFunctions::IApplicationFunctions(Core::System& system_)
+ : ServiceFramework("IApplicationFunctions"), system{system_} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -989,6 +1074,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{120, nullptr, "ExecuteProgram"},
{121, nullptr, "ClearUserChannel"},
{122, nullptr, "UnpopToUserChannel"},
+ {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
@@ -996,6 +1082,10 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
// clang-format on
RegisterHandlers(functions);
+
+ auto& kernel = system.Kernel();
+ gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Manual, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
}
IApplicationFunctions::~IApplicationFunctions() = default;
@@ -1070,13 +1160,21 @@ void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u128 uid = rp.PopRaw<u128>(); // What does this do?
- LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
+ u128 user_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
+
+ FileSys::SaveDataDescriptor descriptor{};
+ descriptor.title_id = Core::CurrentProcess()->GetTitleID();
+ descriptor.user_id = user_id;
+ descriptor.type = FileSys::SaveDataType::SaveData;
+ const auto res = system.GetFileSystemController().CreateSaveData(
+ FileSys::SaveDataSpaceId::NandUser, descriptor);
IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(RESULT_SUCCESS);
+ rb.Push(res.Code());
rb.Push<u64>(0);
-} // namespace Service::AM
+}
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
@@ -1107,7 +1205,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
- FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()};
+ FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
const auto res = pm.GetControlMetadata();
if (res.first != nullptr) {
@@ -1115,8 +1213,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
}
// Call IApplicationManagerInterface implementation.
- auto& service_manager = Core::System::GetInstance().ServiceManager();
- auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2");
+ auto& service_manager = system.ServiceManager();
+ auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
@@ -1188,8 +1286,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
"new_journal={:016X}",
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
- FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id,
- {new_normal_size, new_journal_size});
+ system.GetFileSystemController().WriteSaveDataSize(
+ type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -1208,8 +1306,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
user_id[1], user_id[0]);
- const auto size =
- FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id);
+ const auto size = system.GetFileSystemController().ReadSaveDataSize(
+ type, system.CurrentProcess()->GetTitleID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
@@ -1217,14 +1315,22 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
rb.Push(size.journal);
}
+void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(gpu_error_detected_event.readable);
+}
+
void InstallInterfaces(SM::ServiceManager& service_manager,
- std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
- auto message_queue = std::make_shared<AppletMessageQueue>();
- message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
- // game boot
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
+ auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
+ // Needed on game boot
+ message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
- std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
- std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
+ std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
+ std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
std::make_shared<IdleSys>()->InstallAsService(service_manager);
std::make_shared<OMM>()->InstallAsService(service_manager);
std::make_shared<SPSM>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 991b7d47c..a3baeb673 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -10,12 +10,15 @@
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
-namespace Service {
-namespace NVFlinger {
+namespace Kernel {
+class KernelCore;
+}
+
+namespace Service::NVFlinger {
class NVFlinger;
}
-namespace AM {
+namespace Service::AM {
enum SystemLanguage {
Japanese = 0,
@@ -42,12 +45,13 @@ class AppletMessageQueue {
public:
enum class AppletMessage : u32 {
NoMessage = 0,
+ ExitRequested = 4,
FocusStateChanged = 15,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
};
- AppletMessageQueue();
+ explicit AppletMessageQueue(Kernel::KernelCore& kernel);
~AppletMessageQueue();
const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
@@ -56,6 +60,7 @@ public:
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void OperationModeChanged();
+ void RequestExit();
private:
std::queue<AppletMessage> messages;
@@ -65,12 +70,14 @@ private:
class IWindowController final : public ServiceFramework<IWindowController> {
public:
- IWindowController();
+ explicit IWindowController(Core::System& system_);
~IWindowController() override;
private:
void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
+
+ Core::System& system;
};
class IAudioController final : public ServiceFramework<IAudioController> {
@@ -113,10 +120,12 @@ public:
class ISelfController final : public ServiceFramework<ISelfController> {
public:
- explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ explicit ISelfController(Core::System& system_,
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger_);
~ISelfController() override;
private:
+ void Exit(Kernel::HLERequestContext& ctx);
void LockExit(Kernel::HLERequestContext& ctx);
void UnlockExit(Kernel::HLERequestContext& ctx);
void EnterFatalSection(Kernel::HLERequestContext& ctx);
@@ -133,16 +142,26 @@ private:
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
+ void SetAutoSleepDisabled(Kernel::HLERequestContext& ctx);
+ void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
+ void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
+ void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
Kernel::EventPair launchable_event;
+ Kernel::EventPair accumulated_suspended_tick_changed_event;
+
u32 idle_time_detection_extension = 0;
u64 num_fatal_sections_entered = 0;
+ bool is_auto_sleep_disabled = false;
+
+ Core::System& system;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
- explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
+ explicit ICommonStateGetter(Core::System& system,
+ std::shared_ptr<AppletMessageQueue> msg_queue);
~ICommonStateGetter() override;
private:
@@ -164,7 +183,9 @@ private:
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
void GetBootMode(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
+ void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
+ Core::System& system;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
@@ -198,18 +219,20 @@ private:
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
- ILibraryAppletCreator();
+ explicit ILibraryAppletCreator(Core::System& system_);
~ILibraryAppletCreator() override;
private:
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
void CreateStorage(Kernel::HLERequestContext& ctx);
void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
+
+ Core::System& system;
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
- IApplicationFunctions();
+ explicit IApplicationFunctions(Core::System& system_);
~IApplicationFunctions() override;
private:
@@ -230,6 +253,10 @@ private:
void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
+ void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
+
+ Kernel::EventPair gpu_error_detected_event;
+ Core::System& system;
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -261,7 +288,6 @@ public:
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager,
- std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
-} // namespace AM
-} // namespace Service
+} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 488add8e7..e454b77d8 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -4,6 +4,7 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,9 +14,10 @@ namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue)
+ std::shared_ptr<AppletMessageQueue> msg_queue,
+ Core::System& system)
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
- msg_queue(std::move(msg_queue)) {
+ msg_queue(std::move(msg_queue)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -40,7 +42,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
+ rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -48,7 +50,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISelfController>(nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -56,7 +58,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IWindowController>();
+ rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -96,7 +98,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletCreator>();
+ rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -104,19 +106,20 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationFunctions>();
+ rb.PushIpcInterface<IApplicationFunctions>(system);
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
+ Core::System& system;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue)
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
- msg_queue(std::move(msg_queue)) {
+ msg_queue(std::move(msg_queue)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -143,7 +146,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
+ rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -151,7 +154,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISelfController>(nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -159,7 +162,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IWindowController>();
+ rb.PushIpcInterface<IWindowController>(system);
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -191,7 +194,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletCreator>();
+ rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
@@ -219,6 +222,7 @@ private:
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
+ Core::System& system;
};
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -226,7 +230,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
+ rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -234,7 +238,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
@@ -242,13 +246,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
}
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue)
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
- msg_queue(std::move(msg_queue)) {
+ msg_queue(std::move(msg_queue)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 902db2665..2e3e45915 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -9,16 +9,22 @@
#include "core/hle/service/service.h"
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+}
+
namespace NVFlinger {
class NVFlinger;
}
namespace AM {
+class AppletMessageQueue;
+
class AppletAE final : public ServiceFramework<AppletAE> {
public:
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue);
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
~AppletAE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -30,6 +36,7 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
+ Core::System& system;
};
} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index d3a0a1568..a2ffaa440 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -13,9 +13,9 @@ namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue)
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
- msg_queue(std::move(msg_queue)) {
+ msg_queue(std::move(msg_queue)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -63,7 +63,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IWindowController>();
+ rb.PushIpcInterface<IWindowController>(system);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -71,7 +71,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISelfController>(nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvflinger);
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
@@ -79,7 +79,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
+ rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
@@ -87,7 +87,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletCreator>();
+ rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -95,11 +95,12 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationFunctions>();
+ rb.PushIpcInterface<IApplicationFunctions>(system);
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
+ Core::System& system;
};
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
@@ -107,13 +108,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
+ rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
}
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue)
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
: ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
- msg_queue(std::move(msg_queue)) {
+ msg_queue(std::move(msg_queue)), system(system) {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index bbd0108ef..758da792d 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -9,16 +9,22 @@
#include "core/hle/service/service.h"
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+}
+
namespace NVFlinger {
class NVFlinger;
}
namespace AM {
+class AppletMessageQueue;
+
class AppletOE final : public ServiceFramework<AppletOE> {
public:
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
- std::shared_ptr<AppletMessageQueue> msg_queue);
+ std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
~AppletOE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -28,6 +34,7 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
+ Core::System& system;
};
} // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 14fa92318..d2e35362f 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -23,8 +23,7 @@
namespace Service::AM::Applets {
-AppletDataBroker::AppletDataBroker() {
- auto& kernel = Core::System::GetInstance().Kernel();
+AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
state_changed_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
@@ -35,12 +34,28 @@ AppletDataBroker::AppletDataBroker() {
AppletDataBroker::~AppletDataBroker() = default;
+AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
+ std::vector<std::vector<u8>> out_normal;
+
+ for (const auto& storage : in_channel) {
+ out_normal.push_back(storage->GetData());
+ }
+
+ std::vector<std::vector<u8>> out_interactive;
+
+ for (const auto& storage : in_interactive_channel) {
+ out_interactive.push_back(storage->GetData());
+ }
+
+ return {std::move(out_normal), std::move(out_interactive)};
+}
+
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
if (out_channel.empty())
return nullptr;
auto out = std::move(out_channel.front());
- out_channel.pop();
+ out_channel.pop_front();
return out;
}
@@ -49,7 +64,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
return nullptr;
auto out = std::move(in_channel.front());
- in_channel.pop();
+ in_channel.pop_front();
return out;
}
@@ -58,7 +73,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
return nullptr;
auto out = std::move(out_interactive_channel.front());
- out_interactive_channel.pop();
+ out_interactive_channel.pop_front();
return out;
}
@@ -67,25 +82,25 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
return nullptr;
auto out = std::move(in_interactive_channel.front());
- in_interactive_channel.pop();
+ in_interactive_channel.pop_front();
return out;
}
void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
- in_channel.push(std::make_unique<IStorage>(storage));
+ in_channel.push_back(std::make_unique<IStorage>(storage));
}
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
- out_channel.push(std::make_unique<IStorage>(storage));
+ out_channel.push_back(std::make_unique<IStorage>(storage));
pop_out_data_event.writable->Signal();
}
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
- in_interactive_channel.push(std::make_unique<IStorage>(storage));
+ in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
}
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
- out_interactive_channel.push(std::make_unique<IStorage>(storage));
+ out_interactive_channel.push_back(std::make_unique<IStorage>(storage));
pop_interactive_out_data_event.writable->Signal();
}
@@ -105,7 +120,7 @@ Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent(
return state_changed_event.readable;
}
-Applet::Applet() = default;
+Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {}
Applet::~Applet() = default;
@@ -123,12 +138,14 @@ void Applet::Initialize() {
AppletFrontendSet::AppletFrontendSet() = default;
-AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer,
- ProfileSelect profile_select,
- SoftwareKeyboard software_keyboard, WebBrowser web_browser)
- : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move(
- profile_select)},
- software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {}
+AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
+ PhotoViewer photo_viewer, ProfileSelect profile_select,
+ SoftwareKeyboard software_keyboard, WebBrowser web_browser,
+ ECommerceApplet e_commerce)
+ : parental_controls{std::move(parental_controls)}, error{std::move(error)},
+ photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
+ software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
+ e_commerce{std::move(e_commerce)} {}
AppletFrontendSet::~AppletFrontendSet() = default;
@@ -136,11 +153,13 @@ AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
-AppletManager::AppletManager() = default;
+AppletManager::AppletManager(Core::System& system_) : system{system_} {}
AppletManager::~AppletManager() = default;
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
+ if (set.parental_controls != nullptr)
+ frontend.parental_controls = std::move(set.parental_controls);
if (set.error != nullptr)
frontend.error = std::move(set.error);
if (set.photo_viewer != nullptr)
@@ -151,17 +170,21 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
frontend.software_keyboard = std::move(set.software_keyboard);
if (set.web_browser != nullptr)
frontend.web_browser = std::move(set.web_browser);
+ if (set.e_commerce != nullptr)
+ frontend.e_commerce = std::move(set.e_commerce);
}
void AppletManager::SetDefaultAppletFrontendSet() {
- frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
- frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
- frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
- frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
- frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
+ ClearAll();
+ SetDefaultAppletsIfMissing();
}
void AppletManager::SetDefaultAppletsIfMissing() {
+ if (frontend.parental_controls == nullptr) {
+ frontend.parental_controls =
+ std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
+ }
+
if (frontend.error == nullptr) {
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
}
@@ -182,6 +205,10 @@ void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.web_browser == nullptr) {
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
+
+ if (frontend.e_commerce == nullptr) {
+ frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
+ }
}
void AppletManager::ClearAll() {
@@ -190,21 +217,26 @@ void AppletManager::ClearAll() {
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
switch (id) {
+ case AppletId::Auth:
+ return std::make_shared<Auth>(system, *frontend.parental_controls);
case AppletId::Error:
- return std::make_shared<Error>(*frontend.error);
+ return std::make_shared<Error>(system, *frontend.error);
case AppletId::ProfileSelect:
- return std::make_shared<ProfileSelect>(*frontend.profile_select);
+ return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
case AppletId::SoftwareKeyboard:
- return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
+ return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
case AppletId::PhotoViewer:
- return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
+ return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
+ case AppletId::LibAppletShop:
+ return std::make_shared<WebBrowser>(system, *frontend.web_browser,
+ frontend.e_commerce.get());
case AppletId::LibAppletOff:
- return std::make_shared<WebBrowser>(*frontend.web_browser);
+ return std::make_shared<WebBrowser>(system, *frontend.web_browser);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id));
- return std::make_shared<StubApplet>();
+ return std::make_shared<StubApplet>(system, id);
}
}
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index b46e10a4a..764c3418c 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -12,14 +12,24 @@
union ResultCode;
+namespace Core {
+class System;
+}
+
namespace Core::Frontend {
+class ECommerceApplet;
class ErrorApplet;
+class ParentalControlsApplet;
class PhotoViewerApplet;
class ProfileSelectApplet;
class SoftwareKeyboardApplet;
class WebBrowserApplet;
} // namespace Core::Frontend
+namespace Kernel {
+class KernelCore;
+}
+
namespace Service::AM {
class IStorage;
@@ -51,9 +61,17 @@ enum class AppletId : u32 {
class AppletDataBroker final {
public:
- AppletDataBroker();
+ explicit AppletDataBroker(Kernel::KernelCore& kernel_);
~AppletDataBroker();
+ struct RawChannelData {
+ std::vector<std::vector<u8>> normal;
+ std::vector<std::vector<u8>> interactive;
+ };
+
+ // Retrieves but does not pop the data sent to applet.
+ RawChannelData PeekDataToAppletForDebug() const;
+
std::unique_ptr<IStorage> PopNormalDataToGame();
std::unique_ptr<IStorage> PopNormalDataToApplet();
@@ -76,16 +94,16 @@ private:
// Queues are named from applet's perspective
// PopNormalDataToApplet and PushNormalDataFromGame
- std::queue<std::unique_ptr<IStorage>> in_channel;
+ std::deque<std::unique_ptr<IStorage>> in_channel;
// PopNormalDataToGame and PushNormalDataFromApplet
- std::queue<std::unique_ptr<IStorage>> out_channel;
+ std::deque<std::unique_ptr<IStorage>> out_channel;
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
- std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
+ std::deque<std::unique_ptr<IStorage>> in_interactive_channel;
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
- std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
+ std::deque<std::unique_ptr<IStorage>> out_interactive_channel;
Kernel::EventPair state_changed_event;
@@ -98,7 +116,7 @@ private:
class Applet {
public:
- Applet();
+ explicit Applet(Kernel::KernelCore& kernel_);
virtual ~Applet();
virtual void Initialize();
@@ -137,15 +155,19 @@ protected:
};
struct AppletFrontendSet {
+ using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
+ using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
AppletFrontendSet();
- AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select,
- SoftwareKeyboard software_keyboard, WebBrowser web_browser);
+ AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
+ PhotoViewer photo_viewer, ProfileSelect profile_select,
+ SoftwareKeyboard software_keyboard, WebBrowser web_browser,
+ ECommerceApplet e_commerce);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -154,16 +176,18 @@ struct AppletFrontendSet {
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
+ ParentalControlsApplet parental_controls;
ErrorApplet error;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
+ ECommerceApplet e_commerce;
};
class AppletManager {
public:
- AppletManager();
+ explicit AppletManager(Core::System& system_);
~AppletManager();
void SetAppletFrontendSet(AppletFrontendSet set);
@@ -175,6 +199,7 @@ public:
private:
AppletFrontendSet frontend;
+ Core::System& system;
};
} // namespace Applets
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index 04774bedc..a7db26725 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -9,8 +9,10 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/error.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/error.h"
+#include "core/reporter.h"
namespace Service::AM::Applets {
@@ -83,7 +85,8 @@ ResultCode Decode64BitError(u64 error) {
} // Anonymous namespace
-Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {}
+Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
Error::~Error() = default;
@@ -143,9 +146,12 @@ void Error::Execute() {
}
const auto callback = [this] { DisplayCompleted(); };
+ const auto title_id = system.CurrentProcess()->GetTitleID();
+ const auto& reporter{system.GetReporter()};
switch (mode) {
case ErrorAppletMode::ShowError:
+ reporter.SaveErrorReport(title_id, error_code);
frontend.ShowError(error_code, callback);
break;
case ErrorAppletMode::ShowSystemError:
@@ -156,14 +162,18 @@ void Error::Execute() {
const auto& detail_text =
system ? args->system_error.detail_text : args->application_error.detail_text;
- frontend.ShowCustomErrorText(
- error_code,
- Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()),
- Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()),
- callback);
+ const auto main_text_string =
+ Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size());
+ const auto detail_text_string =
+ Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size());
+
+ reporter.SaveErrorReport(title_id, error_code, main_text_string, detail_text_string);
+ frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
break;
}
case ErrorAppletMode::ShowErrorRecord:
+ reporter.SaveErrorReport(title_id, error_code,
+ fmt::format("{:016X}", args->error_record.posix_time));
frontend.ShowErrorWithTimestamp(
error_code, std::chrono::seconds{args->error_record.posix_time}, callback);
break;
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h
index a3590d181..a105cdb0c 100644
--- a/src/core/hle/service/am/applets/error.h
+++ b/src/core/hle/service/am/applets/error.h
@@ -7,6 +7,10 @@
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
+namespace Core {
+class System;
+}
+
namespace Service::AM::Applets {
enum class ErrorAppletMode : u8 {
@@ -21,7 +25,7 @@ enum class ErrorAppletMode : u8 {
class Error final : public Applet {
public:
- explicit Error(const Core::Frontend::ErrorApplet& frontend);
+ explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_);
~Error() override;
void Initialize() override;
@@ -42,6 +46,7 @@ private:
std::unique_ptr<ErrorArguments> args;
bool complete = false;
+ Core::System& system;
};
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index c591b9ac2..328438a1d 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <string>
+#include <string_view>
#include "common/assert.h"
#include "common/hex_util.h"
@@ -13,28 +13,147 @@
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/general_backend.h"
+#include "core/reporter.h"
namespace Service::AM::Applets {
-static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
+constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
+
+static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
- "called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
- prefix, data.size(), Common::HexVectorToString(data));
+ "called (STUBBED), during {} received normal data with size={:08X}, data={}",
+ prefix, data.size(), Common::HexToString(data));
}
storage = broker.PopInteractiveDataToApplet();
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
- "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
- prefix, data.size(), Common::HexVectorToString(data));
+ "called (STUBBED), during {} received interactive data with size={:08X}, data={}",
+ prefix, data.size(), Common::HexToString(data));
}
}
-PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}
+Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_) {}
+
+Auth::~Auth() = default;
+
+void Auth::Initialize() {
+ Applet::Initialize();
+ complete = false;
+
+ const auto storage = broker.PopNormalDataToApplet();
+ ASSERT(storage != nullptr);
+ const auto data = storage->GetData();
+ ASSERT(data.size() >= 0xC);
+
+ struct Arg {
+ INSERT_PADDING_BYTES(4);
+ AuthAppletType type;
+ u8 arg0;
+ u8 arg1;
+ u8 arg2;
+ INSERT_PADDING_BYTES(1);
+ };
+ static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size.");
+
+ Arg arg{};
+ std::memcpy(&arg, data.data(), sizeof(Arg));
+
+ type = arg.type;
+ arg0 = arg.arg0;
+ arg1 = arg.arg1;
+ arg2 = arg.arg2;
+}
+
+bool Auth::TransactionComplete() const {
+ return complete;
+}
+
+ResultCode Auth::GetStatus() const {
+ return successful ? RESULT_SUCCESS : ERROR_INVALID_PIN;
+}
+
+void Auth::ExecuteInteractive() {
+ UNREACHABLE_MSG("Unexpected interactive applet data.");
+}
+
+void Auth::Execute() {
+ if (complete) {
+ return;
+ }
+
+ const auto unimplemented_log = [this] {
+ UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, "
+ "arg1={:02X}, arg2={:02X}",
+ static_cast<u32>(type), arg0, arg1, arg2);
+ };
+
+ switch (type) {
+ case AuthAppletType::ShowParentalAuthentication: {
+ const auto callback = [this](bool successful) { AuthFinished(successful); };
+
+ if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
+ // ShowAuthenticatorForConfiguration
+ frontend.VerifyPINForSettings(callback);
+ } else if (arg1 == 0 && arg2 == 0) {
+ // ShowParentalAuthentication(bool)
+ frontend.VerifyPIN(callback, static_cast<bool>(arg0));
+ } else {
+ unimplemented_log();
+ }
+ break;
+ }
+ case AuthAppletType::RegisterParentalPasscode: {
+ const auto callback = [this] { AuthFinished(true); };
+
+ if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
+ // RegisterParentalPasscode
+ frontend.RegisterPIN(callback);
+ } else {
+ unimplemented_log();
+ }
+ break;
+ }
+ case AuthAppletType::ChangeParentalPasscode: {
+ const auto callback = [this] { AuthFinished(true); };
+
+ if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
+ // ChangeParentalPasscode
+ frontend.ChangePIN(callback);
+ } else {
+ unimplemented_log();
+ }
+ break;
+ }
+ default:
+ unimplemented_log();
+ }
+}
+
+void Auth::AuthFinished(bool successful) {
+ this->successful = successful;
+
+ struct Return {
+ ResultCode result_code;
+ };
+ static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size.");
+
+ Return return_{GetStatus()};
+
+ std::vector<u8> out(sizeof(Return));
+ std::memcpy(out.data(), &return_, sizeof(Return));
+
+ broker.PushNormalDataFromApplet(IStorage{out});
+ broker.SignalStateChanged();
+}
+
+PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
PhotoViewer::~PhotoViewer() = default;
@@ -68,7 +187,7 @@ void PhotoViewer::Execute() {
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
- frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback);
+ frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);
@@ -83,13 +202,21 @@ void PhotoViewer::ViewFinished() {
broker.SignalStateChanged();
}
-StubApplet::StubApplet() = default;
+StubApplet::StubApplet(Core::System& system_, AppletId id_)
+ : Applet{system_.Kernel()}, id(id_), system{system_} {}
StubApplet::~StubApplet() = default;
void StubApplet::Initialize() {
LOG_WARNING(Service_AM, "called (STUBBED)");
Applet::Initialize();
+
+ const auto data = broker.PeekDataToAppletForDebug();
+ system.GetReporter().SaveUnimplementedAppletReport(
+ static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
+ common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
+ data.normal, data.interactive);
+
LogCurrentStorage(broker, "Initialize");
}
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index 2dd255d7c..cfa2df369 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -6,8 +6,42 @@
#include "core/hle/service/am/applets/applets.h"
+namespace Core {
+class System;
+}
+
namespace Service::AM::Applets {
+enum class AuthAppletType : u32 {
+ ShowParentalAuthentication,
+ RegisterParentalPasscode,
+ ChangeParentalPasscode,
+};
+
+class Auth final : public Applet {
+public:
+ explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_);
+ ~Auth() override;
+
+ void Initialize() override;
+ bool TransactionComplete() const override;
+ ResultCode GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+
+ void AuthFinished(bool successful = true);
+
+private:
+ Core::Frontend::ParentalControlsApplet& frontend;
+ bool complete = false;
+ bool successful = false;
+
+ AuthAppletType type = AuthAppletType::ShowParentalAuthentication;
+ u8 arg0 = 0;
+ u8 arg1 = 0;
+ u8 arg2 = 0;
+};
+
enum class PhotoViewerAppletMode : u8 {
CurrentApp = 0,
AllApps = 1,
@@ -15,7 +49,7 @@ enum class PhotoViewerAppletMode : u8 {
class PhotoViewer final : public Applet {
public:
- explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend);
+ explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override;
void Initialize() override;
@@ -30,11 +64,12 @@ private:
const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
+ Core::System& system;
};
class StubApplet final : public Applet {
public:
- StubApplet();
+ explicit StubApplet(Core::System& system_, AppletId id_);
~StubApplet() override;
void Initialize() override;
@@ -43,6 +78,10 @@ public:
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+
+private:
+ AppletId id;
+ Core::System& system;
};
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 57b5419e8..3eba696ca 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -15,8 +15,9 @@ namespace Service::AM::Applets {
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
-ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend)
- : frontend(frontend) {}
+ProfileSelect::ProfileSelect(Core::System& system_,
+ const Core::Frontend::ProfileSelectApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_) {}
ProfileSelect::~ProfileSelect() = default;
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h
index 563cd744a..16364ead7 100644
--- a/src/core/hle/service/am/applets/profile_select.h
+++ b/src/core/hle/service/am/applets/profile_select.h
@@ -11,6 +11,10 @@
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
+namespace Core {
+class System;
+}
+
namespace Service::AM::Applets {
struct UserSelectionConfig {
@@ -29,7 +33,8 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
class ProfileSelect final : public Applet {
public:
- explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend);
+ explicit ProfileSelect(Core::System& system_,
+ const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override;
void Initialize() override;
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index e197990f7..748559cd0 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -39,8 +39,9 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
return params;
}
-SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend)
- : frontend(frontend) {}
+SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
+ const Core::Frontend::SoftwareKeyboardApplet& frontend_)
+ : Applet{system_.Kernel()}, frontend(frontend_) {}
SoftwareKeyboard::~SoftwareKeyboard() = default;
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 0fbc43e51..ef4801fc6 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -16,6 +16,10 @@
union ResultCode;
+namespace Core {
+class System;
+}
+
namespace Service::AM::Applets {
enum class KeysetDisable : u32 {
@@ -55,7 +59,8 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz
class SoftwareKeyboard final : public Applet {
public:
- explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend);
+ explicit SoftwareKeyboard(Core::System& system_,
+ const Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override;
void Initialize() override;
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 7878f5136..32283e819 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -19,7 +19,9 @@
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
+#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs_types.h"
+#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/am/applets/web_browser.h"
@@ -28,74 +30,188 @@
namespace Service::AM::Applets {
-// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
-// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
-// but some may be worth an implementation.
-constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6;
+enum class WebArgTLVType : u16 {
+ InitialURL = 0x1,
+ ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name.
+ CallbackURL = 0x3,
+ CallbackableURL = 0x4,
+ ApplicationID = 0x5,
+ DocumentPath = 0x6,
+ DocumentKind = 0x7,
+ SystemDataID = 0x8,
+ ShareStartPage = 0x9,
+ Whitelist = 0xA,
+ News = 0xB,
+ UserID = 0xE,
+ AlbumEntry0 = 0xF,
+ ScreenShotEnabled = 0x10,
+ EcClientCertEnabled = 0x11,
+ Unk12 = 0x12,
+ PlayReportEnabled = 0x13,
+ Unk14 = 0x14,
+ Unk15 = 0x15,
+ BootDisplayKind = 0x17,
+ BackgroundKind = 0x18,
+ FooterEnabled = 0x19,
+ PointerEnabled = 0x1A,
+ LeftStickMode = 0x1B,
+ KeyRepeatFrame1 = 0x1C,
+ KeyRepeatFrame2 = 0x1D,
+ BootAsMediaPlayerInv = 0x1E,
+ DisplayUrlKind = 0x1F,
+ BootAsMediaPlayer = 0x21,
+ ShopJumpEnabled = 0x22,
+ MediaAutoPlayEnabled = 0x23,
+ LobbyParameter = 0x24,
+ ApplicationAlbumEntry = 0x26,
+ JsExtensionEnabled = 0x27,
+ AdditionalCommentText = 0x28,
+ TouchEnabledOnContents = 0x29,
+ UserAgentAdditionalString = 0x2A,
+ AdditionalMediaData0 = 0x2B,
+ MediaPlayerAutoCloseEnabled = 0x2C,
+ PageCacheEnabled = 0x2D,
+ WebAudioEnabled = 0x2E,
+ Unk2F = 0x2F,
+ YouTubeVideoWhitelist = 0x31,
+ FooterFixedKind = 0x32,
+ PageFadeEnabled = 0x33,
+ MediaCreatorApplicationRatingAge = 0x34,
+ BootLoadingIconEnabled = 0x35,
+ PageScrollIndicationEnabled = 0x36,
+ MediaPlayerSpeedControlEnabled = 0x37,
+ AlbumEntry1 = 0x38,
+ AlbumEntry2 = 0x39,
+ AlbumEntry3 = 0x3A,
+ AdditionalMediaData1 = 0x3B,
+ AdditionalMediaData2 = 0x3C,
+ AdditionalMediaData3 = 0x3D,
+ BootFooterButton = 0x3E,
+ OverrideWebAudioVolume = 0x3F,
+ OverrideMediaAudioVolume = 0x40,
+ BootMode = 0x41,
+ WebSessionEnabled = 0x42,
+};
+
+enum class ShimKind : u32 {
+ Shop = 1,
+ Login = 2,
+ Offline = 3,
+ Share = 4,
+ Web = 5,
+ Wifi = 6,
+ Lobby = 7,
+};
+
+enum class ShopWebTarget {
+ ApplicationInfo,
+ AddOnContentList,
+ SubscriptionList,
+ ConsumableItemList,
+ Home,
+ Settings,
+};
+
+namespace {
-struct WebBufferHeader {
+constexpr std::size_t SHIM_KIND_COUNT = 0x8;
+
+struct WebArgHeader {
u16 count;
- INSERT_PADDING_BYTES(6);
+ INSERT_PADDING_BYTES(2);
+ ShimKind kind;
};
-static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
+static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
-struct WebArgumentHeader {
- u16 type;
+struct WebArgTLV {
+ WebArgTLVType type;
u16 size;
u32 offset;
};
-static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
+static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size.");
-struct WebArgumentResult {
+struct WebCommonReturnValue {
u32 result_code;
+ INSERT_PADDING_BYTES(0x4);
std::array<char, 0x1000> last_url;
u64 last_url_size;
};
-static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
-
-static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
- WebBufferHeader header;
- ASSERT(sizeof(WebBufferHeader) <= data.size());
- std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
-
- u64 offset = sizeof(WebBufferHeader);
- for (u16 i = 0; i < header.count; ++i) {
- WebArgumentHeader arg;
- ASSERT(offset + sizeof(WebArgumentHeader) <= data.size());
- std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
- offset += sizeof(WebArgumentHeader);
-
- if (arg.type == type) {
- std::vector<u8> out(arg.size);
- offset += arg.offset;
- ASSERT(offset + arg.size <= data.size());
- std::memcpy(out.data(), data.data() + offset, out.size());
+static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
+
+struct WebWifiPageArg {
+ INSERT_PADDING_BYTES(4);
+ std::array<char, 0x100> connection_test_url;
+ std::array<char, 0x400> initial_url;
+ std::array<u8, 0x10> nifm_network_uuid;
+ u32 nifm_requirement;
+};
+static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size.");
+
+struct WebWifiReturnValue {
+ INSERT_PADDING_BYTES(4);
+ u32 result;
+};
+static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size.");
+
+enum class OfflineWebSource : u32 {
+ OfflineHtmlPage = 0x1,
+ ApplicationLegalInformation = 0x2,
+ SystemDataPage = 0x3,
+};
+
+std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
+ if (arg.size() < sizeof(WebArgHeader))
+ return {};
+
+ WebArgHeader header{};
+ std::memcpy(&header, arg.data(), sizeof(WebArgHeader));
+
+ std::map<WebArgTLVType, std::vector<u8>> out;
+ u64 offset = sizeof(WebArgHeader);
+ for (std::size_t i = 0; i < header.count; ++i) {
+ if (arg.size() < (offset + sizeof(WebArgTLV)))
+ return out;
+
+ WebArgTLV tlv{};
+ std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV));
+ offset += sizeof(WebArgTLV);
+
+ offset += tlv.offset;
+ if (arg.size() < (offset + tlv.size))
return out;
- }
- offset += arg.offset + arg.size;
+ std::vector<u8> data(tlv.size);
+ std::memcpy(data.data(), arg.data() + offset, tlv.size);
+ offset += tlv.size;
+
+ out.insert_or_assign(tlv.type, data);
}
- return {};
+ return out;
}
-static FileSys::VirtualFile GetManualRomFS() {
- auto& loader{Core::System::GetInstance().GetAppLoader()};
+FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id,
+ FileSys::ContentRecordType type) {
+ const auto& installed{system.GetContentProvider()};
+ const auto res = installed.GetEntry(title_id, type);
- FileSys::VirtualFile out;
- if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
- return out;
+ if (res != nullptr) {
+ return res->GetRomFS();
+ }
- const auto& installed{Core::System::GetInstance().GetContentProvider()};
- const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
- FileSys::ContentRecordType::Manual);
+ if (type == FileSys::ContentRecordType::Data) {
+ return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
+ }
- if (res != nullptr)
- return res->GetRomFS();
return nullptr;
}
-WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {}
+} // Anonymous namespace
+
+WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
+ Core::Frontend::ECommerceApplet* frontend_e_commerce_)
+ : Applet{system_.Kernel()}, frontend(frontend_),
+ frontend_e_commerce(frontend_e_commerce_), system{system_} {}
WebBrowser::~WebBrowser() = default;
@@ -111,24 +227,12 @@ void WebBrowser::Initialize() {
ASSERT(web_arg_storage != nullptr);
const auto& web_arg = web_arg_storage->GetData();
- const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
- filename = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(url_data.data()), url_data.size());
+ ASSERT(web_arg.size() >= 0x8);
+ std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind));
- temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
- "web_applet_manual",
- FileUtil::DirectorySeparator::PlatformDefault);
- FileUtil::DeleteDirRecursively(temporary_dir);
-
- manual_romfs = GetManualRomFS();
- if (manual_romfs == nullptr) {
- status = ResultCode(-1);
- LOG_ERROR(Service_AM, "Failed to find manual for current process!");
- }
+ args = GetWebArguments(web_arg);
- filename =
- FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
- FileUtil::DirectorySeparator::PlatformDefault);
+ InitializeInternal();
}
bool WebBrowser::TransactionComplete() const {
@@ -144,25 +248,26 @@ void WebBrowser::ExecuteInteractive() {
}
void WebBrowser::Execute() {
- if (complete)
+ if (complete) {
return;
+ }
if (status != RESULT_SUCCESS) {
complete = true;
return;
}
- frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
+ ExecuteInternal();
}
void WebBrowser::UnpackRomFS() {
if (unpacked)
return;
- ASSERT(manual_romfs != nullptr);
+ ASSERT(offline_romfs != nullptr);
const auto dir =
- FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard);
- const auto& vfs{Core::System::GetInstance().GetFilesystem()};
+ FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
+ const auto& vfs{system.GetFilesystem()};
const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
FileSys::VfsRawCopyD(dir, temp_dir);
@@ -172,17 +277,275 @@ void WebBrowser::UnpackRomFS() {
void WebBrowser::Finalize() {
complete = true;
- WebArgumentResult out{};
+ WebCommonReturnValue out{};
out.result_code = 0;
out.last_url_size = 0;
- std::vector<u8> data(sizeof(WebArgumentResult));
- std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
+ std::vector<u8> data(sizeof(WebCommonReturnValue));
+ std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
broker.PushNormalDataFromApplet(IStorage{data});
broker.SignalStateChanged();
+ if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
+ FileUtil::DeleteDirRecursively(temporary_dir);
+ }
+}
+
+void WebBrowser::InitializeInternal() {
+ using WebAppletInitializer = void (WebBrowser::*)();
+
+ constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{
+ nullptr, &WebBrowser::InitializeShop,
+ nullptr, &WebBrowser::InitializeOffline,
+ nullptr, nullptr,
+ nullptr, nullptr,
+ };
+
+ const auto index = static_cast<u32>(kind);
+
+ if (index > functions.size() || functions[index] == nullptr) {
+ LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
+ return;
+ }
+
+ const auto function = functions[index];
+ (this->*function)();
+}
+
+void WebBrowser::ExecuteInternal() {
+ using WebAppletExecutor = void (WebBrowser::*)();
+
+ constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{
+ nullptr, &WebBrowser::ExecuteShop,
+ nullptr, &WebBrowser::ExecuteOffline,
+ nullptr, nullptr,
+ nullptr, nullptr,
+ };
+
+ const auto index = static_cast<u32>(kind);
+
+ if (index > functions.size() || functions[index] == nullptr) {
+ LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
+ return;
+ }
+
+ const auto function = functions[index];
+ (this->*function)();
+}
+
+void WebBrowser::InitializeShop() {
+ if (frontend_e_commerce == nullptr) {
+ LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!");
+ status = ResultCode(-1);
+ return;
+ }
+
+ const auto user_id_data = args.find(WebArgTLVType::UserID);
+
+ user_id = std::nullopt;
+ if (user_id_data != args.end()) {
+ user_id = u128{};
+ std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128));
+ }
+
+ const auto url = args.find(WebArgTLVType::ShopArgumentsURL);
+
+ if (url == args.end()) {
+ LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!");
+ status = ResultCode(-1);
+ return;
+ }
+
+ std::vector<std::string> split_query;
+ Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(url->second.data()), url->second.size()),
+ '?', split_query);
+
+ // 2 -> Main URL '?' Query Parameters
+ // Less is missing info, More is malformed
+ if (split_query.size() != 2) {
+ LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed");
+ status = ResultCode(-1);
+ return;
+ }
+
+ std::vector<std::string> queries;
+ Common::SplitString(split_query[1], '&', queries);
+
+ const auto split_single_query =
+ [](const std::string& in) -> std::pair<std::string, std::string> {
+ const auto index = in.find('=');
+ if (index == std::string::npos || index == in.size() - 1) {
+ return {in, ""};
+ }
+
+ return {in.substr(0, index), in.substr(index + 1)};
+ };
+
+ std::transform(queries.begin(), queries.end(),
+ std::inserter(shop_query, std::next(shop_query.begin())), split_single_query);
+
+ const auto scene = shop_query.find("scene");
+
+ if (scene == shop_query.end()) {
+ LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!");
+ status = ResultCode(-1);
+ return;
+ }
+
+ const std::map<std::string, ShopWebTarget, std::less<>> target_map{
+ {"product_detail", ShopWebTarget::ApplicationInfo},
+ {"aocs", ShopWebTarget::AddOnContentList},
+ {"subscriptions", ShopWebTarget::SubscriptionList},
+ {"consumption", ShopWebTarget::ConsumableItemList},
+ {"settings", ShopWebTarget::Settings},
+ {"top", ShopWebTarget::Home},
+ };
+
+ const auto target = target_map.find(scene->second);
+ if (target == target_map.end()) {
+ LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second);
+ status = ResultCode(-1);
+ return;
+ }
+
+ shop_web_target = target->second;
+
+ const auto title_id_data = shop_query.find("dst_app_id");
+ if (title_id_data != shop_query.end()) {
+ title_id = std::stoull(title_id_data->second, nullptr, 0x10);
+ }
+
+ const auto mode_data = shop_query.find("mode");
+ if (mode_data != shop_query.end()) {
+ shop_full_display = mode_data->second == "full";
+ }
+}
+
+void WebBrowser::InitializeOffline() {
+ if (args.find(WebArgTLVType::DocumentPath) == args.end() ||
+ args.find(WebArgTLVType::DocumentKind) == args.end() ||
+ args.find(WebArgTLVType::ApplicationID) == args.end()) {
+ status = ResultCode(-1);
+ LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!");
+ }
+
+ const auto url_data = args[WebArgTLVType::DocumentPath];
+ filename = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(url_data.data()), url_data.size());
+
+ OfflineWebSource source;
+ ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4);
+ std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource));
+
+ constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{
+ "manual",
+ "legal",
+ "system",
+ };
+
+ temporary_dir =
+ FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" +
+ WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
+ FileUtil::DirectorySeparator::PlatformDefault);
FileUtil::DeleteDirRecursively(temporary_dir);
+
+ u64 title_id = 0; // 0 corresponds to current process
+ ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
+ std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64));
+ FileSys::ContentRecordType type = FileSys::ContentRecordType::Data;
+
+ switch (source) {
+ case OfflineWebSource::OfflineHtmlPage:
+ // While there is an AppID TLV field, in official SW this is always ignored.
+ title_id = 0;
+ type = FileSys::ContentRecordType::HtmlDocument;
+ break;
+ case OfflineWebSource::ApplicationLegalInformation:
+ type = FileSys::ContentRecordType::LegalInformation;
+ break;
+ case OfflineWebSource::SystemDataPage:
+ type = FileSys::ContentRecordType::Data;
+ break;
+ }
+
+ if (title_id == 0) {
+ title_id = system.CurrentProcess()->GetTitleID();
+ }
+
+ offline_romfs = GetApplicationRomFS(system, title_id, type);
+ if (offline_romfs == nullptr) {
+ status = ResultCode(-1);
+ LOG_ERROR(Service_AM, "Failed to find offline data for request!");
+ }
+
+ std::string path_additional_directory;
+ if (source == OfflineWebSource::OfflineHtmlPage) {
+ path_additional_directory = std::string(DIR_SEP).append("html-document");
+ }
+
+ filename =
+ FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
+ FileUtil::DirectorySeparator::PlatformDefault);
+}
+
+void WebBrowser::ExecuteShop() {
+ const auto callback = [this]() { Finalize(); };
+
+ const auto check_optional_parameter = [this](const auto& p) {
+ if (!p.has_value()) {
+ LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!");
+ status = ResultCode(-1);
+ return false;
+ }
+
+ return true;
+ };
+
+ switch (shop_web_target) {
+ case ShopWebTarget::ApplicationInfo:
+ if (!check_optional_parameter(title_id))
+ return;
+ frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id,
+ shop_full_display, shop_extra_parameter);
+ break;
+ case ShopWebTarget::AddOnContentList:
+ if (!check_optional_parameter(title_id))
+ return;
+ frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display);
+ break;
+ case ShopWebTarget::ConsumableItemList:
+ if (!check_optional_parameter(title_id))
+ return;
+ frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id);
+ break;
+ case ShopWebTarget::Home:
+ if (!check_optional_parameter(user_id))
+ return;
+ if (!check_optional_parameter(shop_full_display))
+ return;
+ frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display);
+ break;
+ case ShopWebTarget::Settings:
+ if (!check_optional_parameter(user_id))
+ return;
+ if (!check_optional_parameter(shop_full_display))
+ return;
+ frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display);
+ break;
+ case ShopWebTarget::SubscriptionList:
+ if (!check_optional_parameter(title_id))
+ return;
+ frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+void WebBrowser::ExecuteOffline() {
+ frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
}
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 7e0f34c7d..8d4027411 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -4,15 +4,26 @@
#pragma once
+#include <map>
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
+namespace Core {
+class System;
+}
+
namespace Service::AM::Applets {
+enum class ShimKind : u32;
+enum class ShopWebTarget;
+enum class WebArgTLVType : u16;
+
class WebBrowser final : public Applet {
public:
- WebBrowser(Core::Frontend::WebBrowserApplet& frontend);
+ WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
+ Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr);
+
~WebBrowser() override;
void Initialize() override;
@@ -32,15 +43,41 @@ public:
void Finalize();
private:
+ void InitializeInternal();
+ void ExecuteInternal();
+
+ // Specific initializers for the types of web applets
+ void InitializeShop();
+ void InitializeOffline();
+
+ // Specific executors for the types of web applets
+ void ExecuteShop();
+ void ExecuteOffline();
+
Core::Frontend::WebBrowserApplet& frontend;
+ // Extra frontends for specialized functions
+ Core::Frontend::ECommerceApplet* frontend_e_commerce;
+
bool complete = false;
bool unpacked = false;
ResultCode status = RESULT_SUCCESS;
- FileSys::VirtualFile manual_romfs;
+ ShimKind kind;
+ std::map<WebArgTLVType, std::vector<u8>> args;
+
+ FileSys::VirtualFile offline_romfs;
std::string temporary_dir;
std::string filename;
+
+ ShopWebTarget shop_web_target;
+ std::map<std::string, std::string, std::less<>> shop_query;
+ std::optional<u64> title_id = 0;
+ std::optional<u128> user_id;
+ std::optional<bool> shop_full_display;
+ std::string shop_extra_parameter;
+
+ Core::System& system;
};
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 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) {
return (title_id & DLC_BASE_TITLE_ID_MASK) == base;
}
-static std::vector<u64> AccumulateAOCTitleIDs() {
+static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
- const auto& rcu = Core::System::GetInstance().GetContentProvider();
+ const auto& rcu = system.GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
@@ -47,7 +47,8 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
return add_on_content;
}
-AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs()) {
+AOC_U::AOC_U(Core::System& system)
+ : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CountAddOnContentByApplicationId"},
@@ -65,7 +66,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
"GetAddOnContentListChanged:Event");
}
@@ -86,7 +87,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+ const auto current = system.CurrentProcess()->GetTitleID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -113,7 +114,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
- const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+ const auto current = system.CurrentProcess()->GetTitleID();
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -159,7 +160,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+ const auto title_id = system.CurrentProcess()->GetTitleID();
FileSys::PatchManager pm{title_id};
const auto res = pm.GetControlMetadata();
@@ -196,8 +197,8 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(aoc_change_event.readable);
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<AOC_U>()->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<AOC_U>(system)->InstallAsService(service_manager);
}
} // 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 {
class AOC_U final : public ServiceFramework<AOC_U> {
public:
- AOC_U();
+ explicit AOC_U(Core::System& system);
~AOC_U() override;
private:
@@ -26,9 +26,10 @@ private:
std::vector<u64> add_on_content;
Kernel::EventPair aoc_change_event;
+ Core::System& system;
};
/// Registers all AOC services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::AOC
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index f3c09bbb1..85bbf5988 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/interface.h"
@@ -12,11 +11,15 @@ namespace Service::APM {
Module::Module() = default;
Module::~Module() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(Core::System& system) {
auto module_ = std::make_shared<Module>();
- std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
- std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
- std::make_shared<APM_Sys>()->InstallAsService(service_manager);
+ std::make_shared<APM>(module_, system.GetAPMController(), "apm")
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<APM>(module_, system.GetAPMController(), "apm:p")
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<APM>(module_, system.GetAPMController(), "apm:am")
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager());
}
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index 4d7d5bb7c..cf4c2bb11 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -8,11 +8,6 @@
namespace Service::APM {
-enum class PerformanceMode : u8 {
- Handheld = 0,
- Docked = 1,
-};
-
class Module final {
public:
Module();
@@ -20,6 +15,6 @@ public:
};
/// Registers all AM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(Core::System& system);
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
new file mode 100644
index 000000000..4376612eb
--- /dev/null
+++ b/src/core/hle/service/apm/controller.cpp
@@ -0,0 +1,68 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/core_timing.h"
+#include "core/hle/service/apm/controller.h"
+#include "core/settings.h"
+
+namespace Service::APM {
+
+constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION =
+ PerformanceConfiguration::Config7;
+
+Controller::Controller(Core::Timing::CoreTiming& core_timing)
+ : core_timing(core_timing), configs{
+ {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
+ {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
+ } {}
+
+Controller::~Controller() = default;
+
+void Controller::SetPerformanceConfiguration(PerformanceMode mode,
+ PerformanceConfiguration config) {
+ static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{
+ {PerformanceConfiguration::Config1, 1020}, {PerformanceConfiguration::Config2, 1020},
+ {PerformanceConfiguration::Config3, 1224}, {PerformanceConfiguration::Config4, 1020},
+ {PerformanceConfiguration::Config5, 1020}, {PerformanceConfiguration::Config6, 1224},
+ {PerformanceConfiguration::Config7, 1020}, {PerformanceConfiguration::Config8, 1020},
+ {PerformanceConfiguration::Config9, 1020}, {PerformanceConfiguration::Config10, 1020},
+ {PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020},
+ {PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785},
+ {PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020},
+ };
+
+ SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second);
+ configs.insert_or_assign(mode, config);
+}
+
+void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
+ constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{
+ PerformanceConfiguration::Config7,
+ PerformanceConfiguration::Config13,
+ PerformanceConfiguration::Config15,
+ }};
+
+ SetPerformanceConfiguration(PerformanceMode::Docked,
+ BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode)));
+}
+
+PerformanceMode Controller::GetCurrentPerformanceMode() {
+ return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
+}
+
+PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
+ if (configs.find(mode) == configs.end()) {
+ configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION);
+ }
+
+ return configs[mode];
+}
+
+void Controller::SetClockSpeed(u32 mhz) {
+ LOG_INFO(Service_APM, "called, mhz={:08X}", mhz);
+ // TODO(DarkLordZach): Actually signal core_timing to change clock speed.
+}
+
+} // namespace Service::APM
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h
new file mode 100644
index 000000000..8ac80eaea
--- /dev/null
+++ b/src/core/hle/service/apm/controller.h
@@ -0,0 +1,70 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+#include "common/common_types.h"
+
+namespace Core::Timing {
+class CoreTiming;
+}
+
+namespace Service::APM {
+
+enum class PerformanceConfiguration : u32 {
+ Config1 = 0x00010000,
+ Config2 = 0x00010001,
+ Config3 = 0x00010002,
+ Config4 = 0x00020000,
+ Config5 = 0x00020001,
+ Config6 = 0x00020002,
+ Config7 = 0x00020003,
+ Config8 = 0x00020004,
+ Config9 = 0x00020005,
+ Config10 = 0x00020006,
+ Config11 = 0x92220007,
+ Config12 = 0x92220008,
+ Config13 = 0x92220009,
+ Config14 = 0x9222000A,
+ Config15 = 0x9222000B,
+ Config16 = 0x9222000C,
+};
+
+enum class CpuBoostMode : u32 {
+ Disabled = 0,
+ Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16
+ Partial = 2, // GPU Only -> Config 15 or 16
+};
+
+enum class PerformanceMode : u8 {
+ Handheld = 0,
+ Docked = 1,
+};
+
+// Class to manage the state and change of the emulated system performance.
+// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or
+// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate
+// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the
+// system during times of high load -- this simply maps to different PerformanceConfigs to use.
+class Controller {
+public:
+ Controller(Core::Timing::CoreTiming& core_timing);
+ ~Controller();
+
+ void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
+ void SetFromCpuBoostMode(CpuBoostMode mode);
+
+ PerformanceMode GetCurrentPerformanceMode();
+ PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode);
+
+private:
+ void SetClockSpeed(u32 mhz);
+
+ std::map<PerformanceMode, PerformanceConfiguration> configs;
+
+ Core::Timing::CoreTiming& core_timing;
+};
+
+} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index d058c0245..06f0f8edd 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -5,43 +5,32 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/apm/apm.h"
+#include "core/hle/service/apm/controller.h"
#include "core/hle/service/apm/interface.h"
namespace Service::APM {
class ISession final : public ServiceFramework<ISession> {
public:
- ISession() : ServiceFramework("ISession") {
+ ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) {
static const FunctionInfo functions[] = {
{0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
{1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
+ {2, nullptr, "SetCpuOverclockEnabled"},
};
RegisterHandlers(functions);
}
private:
- enum class PerformanceConfiguration : u32 {
- Config1 = 0x00010000,
- Config2 = 0x00010001,
- Config3 = 0x00010002,
- Config4 = 0x00020000,
- Config5 = 0x00020001,
- Config6 = 0x00020002,
- Config7 = 0x00020003,
- Config8 = 0x00020004,
- Config9 = 0x00020005,
- Config10 = 0x00020006,
- Config11 = 0x92220007,
- Config12 = 0x92220008,
- };
-
void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
- u32 config = rp.Pop<u32>();
- LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
- config);
+ const auto mode = rp.PopEnum<PerformanceMode>();
+ const auto config = rp.PopEnum<PerformanceConfiguration>();
+ LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode),
+ static_cast<u32>(config));
+
+ controller.SetPerformanceConfiguration(mode, config);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -50,20 +39,23 @@ private:
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
- LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
+ const auto mode = rp.PopEnum<PerformanceMode>();
+ LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
+ rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
}
+
+ Controller& controller;
};
-APM::APM(std::shared_ptr<Module> apm, const char* name)
- : ServiceFramework(name), apm(std::move(apm)) {
+APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name)
+ : ServiceFramework(name), apm(std::move(apm)), controller(controller) {
static const FunctionInfo functions[] = {
{0, &APM::OpenSession, "OpenSession"},
- {1, nullptr, "GetPerformanceMode"},
+ {1, &APM::GetPerformanceMode, "GetPerformanceMode"},
+ {6, nullptr, "IsCpuOverclockEnabled"},
};
RegisterHandlers(functions);
}
@@ -75,10 +67,17 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISession>();
+ rb.PushIpcInterface<ISession>(controller);
+}
+
+void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_APM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.PushEnum(controller.GetCurrentPerformanceMode());
}
-APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
+APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestPerformanceMode"},
@@ -87,8 +86,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
{3, nullptr, "GetLastThrottlingState"},
{4, nullptr, "ClearLastThrottlingState"},
{5, nullptr, "LoadAndApplySettings"},
- {6, nullptr, "SetCpuBoostMode"},
- {7, nullptr, "GetCurrentPerformanceConfiguration"},
+ {6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"},
+ {7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"},
};
// clang-format on
@@ -102,7 +101,28 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISession>();
+ rb.PushIpcInterface<ISession>(controller);
+}
+
+void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto mode = rp.PopEnum<CpuBoostMode>();
+
+ LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode));
+
+ controller.SetFromCpuBoostMode(mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_APM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushEnum(
+ controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode()));
}
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index 773541aa4..de1b89437 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -8,24 +8,34 @@
namespace Service::APM {
+class Controller;
+class Module;
+
class APM final : public ServiceFramework<APM> {
public:
- explicit APM(std::shared_ptr<Module> apm, const char* name);
+ explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name);
~APM() override;
private:
void OpenSession(Kernel::HLERequestContext& ctx);
+ void GetPerformanceMode(Kernel::HLERequestContext& ctx);
std::shared_ptr<Module> apm;
+ Controller& controller;
};
class APM_Sys final : public ServiceFramework<APM_Sys> {
public:
- explicit APM_Sys();
+ explicit APM_Sys(Controller& controller);
~APM_Sys() override;
+ void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
+
private:
void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
+ void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx);
+
+ Controller& controller;
};
} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
deleted file mode 100644
index e675b0188..000000000
--- a/src/core/hle/service/arp/arp.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <memory>
-
-#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/service/arp/arp.h"
-#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
-
-namespace Service::ARP {
-
-class ARP_R final : public ServiceFramework<ARP_R> {
-public:
- explicit ARP_R() : ServiceFramework{"arp:r"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetApplicationLaunchProperty"},
- {1, nullptr, "GetApplicationLaunchPropertyWithApplicationId"},
- {2, nullptr, "GetApplicationControlProperty"},
- {3, nullptr, "GetApplicationControlPropertyWithApplicationId"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class IRegistrar final : public ServiceFramework<IRegistrar> {
-public:
- explicit IRegistrar() : ServiceFramework{"IRegistrar"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Issue"},
- {1, nullptr, "SetApplicationLaunchProperty"},
- {2, nullptr, "SetApplicationControlProperty"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class ARP_W final : public ServiceFramework<ARP_W> {
-public:
- explicit ARP_W() : ServiceFramework{"arp:w"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
- {1, nullptr, "DeleteProperties"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_ARP, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IRegistrar>();
- }
-};
-
-void InstallInterfaces(SM::ServiceManager& sm) {
- std::make_shared<ARP_R>()->InstallAsService(sm);
- std::make_shared<ARP_W>()->InstallAsService(sm);
-}
-
-} // namespace Service::ARP
diff --git a/src/core/hle/service/arp/arp.h b/src/core/hle/service/arp/arp.h
deleted file mode 100644
index 9d100187c..000000000
--- a/src/core/hle/service/arp/arp.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2018 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-namespace Service::SM {
-class ServiceManager;
-}
-
-namespace Service::ARP {
-
-/// Registers all ARP services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm);
-
-} // namespace Service::ARP
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 128df7db5..1781bec83 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -19,16 +19,16 @@
namespace Service::Audio {
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<AudCtl>()->InstallAsService(service_manager);
std::make_shared<AudOutA>()->InstallAsService(service_manager);
- std::make_shared<AudOutU>()->InstallAsService(service_manager);
+ std::make_shared<AudOutU>(system)->InstallAsService(service_manager);
std::make_shared<AudInA>()->InstallAsService(service_manager);
std::make_shared<AudInU>()->InstallAsService(service_manager);
std::make_shared<AudRecA>()->InstallAsService(service_manager);
std::make_shared<AudRecU>()->InstallAsService(service_manager);
std::make_shared<AudRenA>()->InstallAsService(service_manager);
- std::make_shared<AudRenU>()->InstallAsService(service_manager);
+ std::make_shared<AudRenU>(system)->InstallAsService(service_manager);
std::make_shared<CodecCtl>()->InstallAsService(service_manager);
std::make_shared<HwOpus>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index f5bd3bf5f..b6d13912e 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -4,6 +4,10 @@
#pragma once
+namespace Core {
+class System;
+}
+
namespace Service::SM {
class ServiceManager;
}
@@ -11,6 +15,6 @@ class ServiceManager;
namespace Service::Audio {
/// Registers all Audio services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 6ba41b20a..fb84a8f13 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -40,8 +40,8 @@ enum class AudioState : u32 {
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
- IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
- std::string&& unique_name)
+ IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core,
+ std::string&& device_name, std::string&& unique_name)
: ServiceFramework("IAudioOut"), audio_core(audio_core),
device_name(std::move(device_name)), audio_params(audio_params) {
// clang-format off
@@ -58,14 +58,13 @@ public:
{9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
{10, nullptr, "GetAudioOutPlayedSampleCount"},
{11, nullptr, "FlushAudioOutBuffers"},
- {12, nullptr, "SetAudioOutVolume"},
- {13, nullptr, "GetAudioOutVolume"},
+ {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
+ {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
};
// clang-format on
RegisterHandlers(functions);
// This is the event handle used to check if the audio buffer was released
- auto& system = Core::System::GetInstance();
buffer_event = Kernel::WritableEvent::CreateEventPair(
system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased");
@@ -183,6 +182,25 @@ private:
rb.Push(static_cast<u32>(stream->GetQueueSize()));
}
+ void SetAudioOutVolume(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const float volume = rp.Pop<float>();
+ LOG_DEBUG(Service_Audio, "called, volume={}", volume);
+
+ stream->SetVolume(volume);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void GetAudioOutVolume(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(stream->GetVolume());
+ }
+
AudioCore::AudioOut& audio_core;
AudioCore::StreamPtr stream;
std::string device_name;
@@ -193,6 +211,22 @@ private:
Kernel::EventPair buffer_event;
};
+AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
+ {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"},
+ {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
+ {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ audio_core = std::make_unique<AudioCore::AudioOut>();
+}
+
+AudOutU::~AudOutU() = default;
+
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
@@ -229,7 +263,7 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
auto audio_out_interface = std::make_shared<IAudioOut>(
- params, *audio_core, std::move(device_name), std::move(unique_name));
+ system, params, *audio_core, std::move(device_name), std::move(unique_name));
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -237,20 +271,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(params.channel_count);
rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
- rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
+ rb.PushIpcInterface<IAudioOut>(audio_out_interface);
audio_out_interfaces.push_back(std::move(audio_out_interface));
}
-AudOutU::AudOutU() : ServiceFramework("audout:u") {
- static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
- {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"},
- {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
- {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
- RegisterHandlers(functions);
- audio_core = std::make_unique<AudioCore::AudioOut>();
-}
-
-AudOutU::~AudOutU() = default;
-
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index aed4c43b2..c9f532ccd 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -11,6 +11,10 @@ namespace AudioCore {
class AudioOut;
}
+namespace Core {
+class System;
+}
+
namespace Kernel {
class HLERequestContext;
}
@@ -21,15 +25,17 @@ class IAudioOut;
class AudOutU final : public ServiceFramework<AudOutU> {
public:
- AudOutU();
+ explicit AudOutU(Core::System& system_);
~AudOutU() override;
private:
+ void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
+ void OpenAudioOutImpl(Kernel::HLERequestContext& ctx);
+
std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
std::unique_ptr<AudioCore::AudioOut> audio_core;
- void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
- void OpenAudioOutImpl(Kernel::HLERequestContext& ctx);
+ Core::System& system;
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 75db0c2dc..f162249ed 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <memory>
+#include <string_view>
#include "audio_core/audio_renderer.h"
#include "common/alignment.h"
@@ -25,7 +26,8 @@ namespace Service::Audio {
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
- explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params)
+ explicit IAudioRenderer(Core::System& system, AudioCore::AudioRendererParameter audren_params,
+ const std::size_t instance_number)
: ServiceFramework("IAudioRenderer") {
// clang-format off
static const FunctionInfo functions[] = {
@@ -45,11 +47,10 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& system = Core::System::GetInstance();
system_event = Kernel::WritableEvent::CreateEventPair(
system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent");
- renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params,
- system_event.writable);
+ renderer = std::make_unique<AudioCore::AudioRenderer>(
+ system.CoreTiming(), audren_params, system_event.writable, instance_number);
}
private:
@@ -159,40 +160,81 @@ private:
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
public:
- IAudioDevice() : ServiceFramework("IAudioDevice") {
+ explicit IAudioDevice(Core::System& system, u32_le revision_num)
+ : ServiceFramework("IAudioDevice"), revision{revision_num} {
static const FunctionInfo functions[] = {
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
{1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
- {2, nullptr, "GetAudioDeviceOutputVolume"},
+ {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
{3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
{4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
{5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
- {6, &IAudioDevice::ListAudioDeviceName,
- "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto
+ {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
{7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
- {8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
+ {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
{10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
- {11, nullptr, "QueryAudioDeviceInputEvent"},
- {12, nullptr, "QueryAudioDeviceOutputEvent"},
+ {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
+ {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
{13, nullptr, "GetAudioSystemMasterVolumeSetting"},
};
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IAudioOutBufferReleasedEvent");
+
+ // Should be similar to audio_output_device_switch_event
+ audio_input_device_switch_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioInputDeviceSwitchedEvent");
+
+ // Should only be signalled when an audio output device has been changed, example: speaker
+ // to headset
+ audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
}
private:
+ using AudioDeviceName = std::array<char, 256>;
+ static constexpr std::array<std::string_view, 4> audio_device_names{{
+ "AudioStereoJackOutput",
+ "AudioBuiltInSpeakerOutput",
+ "AudioTvOutput",
+ "AudioUsbDeviceOutput",
+ }};
+ enum class DeviceType {
+ AHUBHeadphones,
+ AHUBSpeakers,
+ HDA,
+ USBOutput,
+ };
+
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_DEBUG(Service_Audio, "called");
+
+ const bool usb_output_supported =
+ IsFeatureSupported(AudioFeatures::AudioUSBDeviceOutput, revision);
+ const std::size_t count = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName);
- constexpr std::array<char, 15> audio_interface{{"AudioInterface"}};
- ctx.WriteBuffer(audio_interface);
+ std::vector<AudioDeviceName> name_buffer;
+ name_buffer.reserve(audio_device_names.size());
+
+ for (std::size_t i = 0; i < count && i < audio_device_names.size(); i++) {
+ const auto type = static_cast<DeviceType>(i);
+
+ if (!usb_output_supported && type == DeviceType::USBOutput) {
+ continue;
+ }
+
+ const auto& device_name = audio_device_names[i];
+ auto& entry = name_buffer.emplace_back();
+ device_name.copy(entry.data(), device_name.size());
+ }
+
+ ctx.WriteBuffer(name_buffer);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(1);
+ rb.Push(static_cast<u32>(name_buffer.size()));
}
void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
@@ -208,15 +250,32 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void GetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto device_name_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(device_name_buffer);
+
+ LOG_WARNING(Service_Audio, "(STUBBED) called. name={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(1.0f);
+ }
+
void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- constexpr std::array<char, 12> audio_interface{{"AudioDevice"}};
- ctx.WriteBuffer(audio_interface);
+ // Currently set to always be TV audio output.
+ const auto& device_name = audio_device_names[2];
- IPC::ResponseBuilder rb{ctx, 3};
+ AudioDeviceName out_device_name{};
+ device_name.copy(out_device_name.data(), device_name.size());
+
+ ctx.WriteBuffer(out_device_name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(1);
}
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
@@ -237,11 +296,31 @@ private:
rb.Push<u32>(1);
}
+ // Should be similar to QueryAudioDeviceOutputEvent
+ void QueryAudioDeviceInputEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(audio_input_device_switch_event.readable);
+ }
+
+ void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(audio_output_device_switch_event.readable);
+ }
+
+ u32_le revision = 0;
Kernel::EventPair buffer_event;
+ Kernel::EventPair audio_input_device_switch_event;
+ Kernel::EventPair audio_output_device_switch_event;
}; // namespace Audio
-AudRenU::AudRenU() : ServiceFramework("audren:u") {
+AudRenU::AudRenU(Core::System& system_) : ServiceFramework("audren:u"), system{system_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -314,7 +393,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the portion of the size related to the mix data (and the sorting thereof).
- const auto calculate_mix_info_size = [this](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_mix_info_size = [](const AudioCore::AudioRendererParameter& params) {
// The size of the mixing info data structure.
constexpr u64 mix_info_size = 0x940;
@@ -386,7 +465,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
// Calculates the part of the size related to the splitter context.
const auto calculate_splitter_context_size =
- [this](const AudioCore::AudioRendererParameter& params) -> u64 {
+ [](const AudioCore::AudioRendererParameter& params) -> u64 {
if (!IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
return 0;
}
@@ -433,7 +512,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size related to performance statistics.
- const auto calculate_perf_size = [this](const AudioCore::AudioRendererParameter& params) {
+ const auto calculate_perf_size = [](const AudioCore::AudioRendererParameter& params) {
// Extra size value appended to the end of the calculation.
constexpr u64 appended = 128;
@@ -460,78 +539,76 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
};
// Calculates the part of the size that relates to the audio command buffer.
- const auto calculate_command_buffer_size =
- [this](const AudioCore::AudioRendererParameter& params) {
- constexpr u64 alignment = (buffer_alignment_size - 1) * 2;
+ const auto calculate_command_buffer_size = [](const AudioCore::AudioRendererParameter& params) {
+ constexpr u64 alignment = (buffer_alignment_size - 1) * 2;
- if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) {
- constexpr u64 command_buffer_size = 0x18000;
+ if (!IsFeatureSupported(AudioFeatures::VariadicCommandBuffer, params.revision)) {
+ constexpr u64 command_buffer_size = 0x18000;
- return command_buffer_size + alignment;
- }
+ return command_buffer_size + alignment;
+ }
- // When the variadic command buffer is supported, this means
- // the command generator for the audio renderer can issue commands
- // that are (as one would expect), variable in size. So what we need to do
- // is determine the maximum possible size for a few command data structures
- // then multiply them by the amount of present commands indicated by the given
- // respective audio parameters.
+ // When the variadic command buffer is supported, this means
+ // the command generator for the audio renderer can issue commands
+ // that are (as one would expect), variable in size. So what we need to do
+ // is determine the maximum possible size for a few command data structures
+ // then multiply them by the amount of present commands indicated by the given
+ // respective audio parameters.
- constexpr u64 max_biquad_filters = 2;
- constexpr u64 max_mix_buffers = 24;
+ constexpr u64 max_biquad_filters = 2;
+ constexpr u64 max_mix_buffers = 24;
- constexpr u64 biquad_filter_command_size = 0x2C;
+ constexpr u64 biquad_filter_command_size = 0x2C;
- constexpr u64 depop_mix_command_size = 0x24;
- constexpr u64 depop_setup_command_size = 0x50;
+ constexpr u64 depop_mix_command_size = 0x24;
+ constexpr u64 depop_setup_command_size = 0x50;
- constexpr u64 effect_command_max_size = 0x540;
+ constexpr u64 effect_command_max_size = 0x540;
- constexpr u64 mix_command_size = 0x1C;
- constexpr u64 mix_ramp_command_size = 0x24;
- constexpr u64 mix_ramp_grouped_command_size = 0x13C;
+ constexpr u64 mix_command_size = 0x1C;
+ constexpr u64 mix_ramp_command_size = 0x24;
+ constexpr u64 mix_ramp_grouped_command_size = 0x13C;
- constexpr u64 perf_command_size = 0x28;
+ constexpr u64 perf_command_size = 0x28;
- constexpr u64 sink_command_size = 0x130;
+ constexpr u64 sink_command_size = 0x130;
- constexpr u64 submix_command_max_size =
- depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers;
+ constexpr u64 submix_command_max_size =
+ depop_mix_command_size + (mix_command_size * max_mix_buffers) * max_mix_buffers;
- constexpr u64 volume_command_size = 0x1C;
- constexpr u64 volume_ramp_command_size = 0x20;
+ constexpr u64 volume_command_size = 0x1C;
+ constexpr u64 volume_ramp_command_size = 0x20;
- constexpr u64 voice_biquad_filter_command_size =
- biquad_filter_command_size * max_biquad_filters;
- constexpr u64 voice_data_command_size = 0x9C;
- const u64 voice_command_max_size =
- (params.splitter_count * depop_setup_command_size) +
- (voice_data_command_size + voice_biquad_filter_command_size +
- volume_ramp_command_size + mix_ramp_grouped_command_size);
+ constexpr u64 voice_biquad_filter_command_size =
+ biquad_filter_command_size * max_biquad_filters;
+ constexpr u64 voice_data_command_size = 0x9C;
+ const u64 voice_command_max_size =
+ (params.splitter_count * depop_setup_command_size) +
+ (voice_data_command_size + voice_biquad_filter_command_size + volume_ramp_command_size +
+ mix_ramp_grouped_command_size);
- // Now calculate the individual elements that comprise the size and add them together.
- const u64 effect_commands_size = params.effect_count * effect_command_max_size;
+ // Now calculate the individual elements that comprise the size and add them together.
+ const u64 effect_commands_size = params.effect_count * effect_command_max_size;
- const u64 final_mix_commands_size =
- depop_mix_command_size + volume_command_size * max_mix_buffers;
+ const u64 final_mix_commands_size =
+ depop_mix_command_size + volume_command_size * max_mix_buffers;
- const u64 perf_commands_size =
- perf_command_size *
- (CalculateNumPerformanceEntries(params) + max_perf_detail_entries);
+ const u64 perf_commands_size =
+ perf_command_size * (CalculateNumPerformanceEntries(params) + max_perf_detail_entries);
- const u64 sink_commands_size = params.sink_count * sink_command_size;
+ const u64 sink_commands_size = params.sink_count * sink_command_size;
- const u64 splitter_commands_size =
- params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size;
+ const u64 splitter_commands_size =
+ params.num_splitter_send_channels * max_mix_buffers * mix_ramp_command_size;
- const u64 submix_commands_size = params.submix_count * submix_command_max_size;
+ const u64 submix_commands_size = params.submix_count * submix_command_max_size;
- const u64 voice_commands_size = params.voice_count * voice_command_max_size;
+ const u64 voice_commands_size = params.voice_count * voice_command_max_size;
- return effect_commands_size + final_mix_commands_size + perf_commands_size +
- sink_commands_size + splitter_commands_size + submix_commands_size +
- voice_commands_size + alignment;
- };
+ return effect_commands_size + final_mix_commands_size + perf_commands_size +
+ sink_commands_size + splitter_commands_size + submix_commands_size +
+ voice_commands_size + alignment;
+ };
IPC::RequestParser rp{ctx};
const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
@@ -564,12 +641,16 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
}
void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
+ IPC::RequestParser rp{ctx};
+ const u64 aruid = rp.Pop<u64>();
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ LOG_DEBUG(Service_Audio, "called. aruid={:016X}", aruid);
+ // Revisionless variant of GetAudioDeviceServiceWithRevisionInfo that
+ // always assumes the initial release revision (REV1).
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Audio::IAudioDevice>();
+ rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
}
void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
@@ -579,13 +660,19 @@ void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
}
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ struct Parameters {
+ u32 revision;
+ u64 aruid;
+ };
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ IPC::RequestParser rp{ctx};
+ const auto [revision, aruid] = rp.PopRaw<Parameters>();
+
+ LOG_DEBUG(Service_Audio, "called. revision={:08X}, aruid={:016X}", revision, aruid);
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
- // based on the current revision
+ rb.PushIpcInterface<IAudioDevice>(system, revision);
}
void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
@@ -594,14 +681,16 @@ void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IAudioRenderer>(params);
+ rb.PushIpcInterface<IAudioRenderer>(system, params, audren_instance_count++);
}
-bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
+bool IsFeatureSupported(AudioFeatures feature, u32_le revision) {
// Byte swap
const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0');
switch (feature) {
+ case AudioFeatures::AudioUSBDeviceOutput:
+ return version_num >= 4U;
case AudioFeatures::Splitter:
return version_num >= 2U;
case AudioFeatures::PerformanceMetricsVersion2:
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 1d3c8df61..4e0ccc792 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -6,6 +6,10 @@
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Kernel {
class HLERequestContext;
}
@@ -14,7 +18,7 @@ namespace Service::Audio {
class AudRenU final : public ServiceFramework<AudRenU> {
public:
- explicit AudRenU();
+ explicit AudRenU(Core::System& system_);
~AudRenU() override;
private:
@@ -26,13 +30,19 @@ private:
void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
- enum class AudioFeatures : u32 {
- Splitter,
- PerformanceMetricsVersion2,
- VariadicCommandBuffer,
- };
+ std::size_t audren_instance_count = 0;
+ Core::System& system;
+};
- bool IsFeatureSupported(AudioFeatures feature, u32_le revision) const;
+// Describes a particular audio feature that may be supported in a particular revision.
+enum class AudioFeatures : u32 {
+ AudioUSBDeviceOutput,
+ Splitter,
+ PerformanceMetricsVersion2,
+ VariadicCommandBuffer,
};
+// Tests if a particular audio feature is supported with a given audio revision.
+bool IsFeatureSupported(AudioFeatures feature, u32_le revision);
+
} // namespace Service::Audio
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 {
class Bt final : public ServiceFramework<Bt> {
public:
- explicit Bt() : ServiceFramework{"bt"} {
+ explicit Bt(Core::System& system) : ServiceFramework{"bt"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "LeClientReadCharacteristic"},
@@ -33,7 +33,7 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
register_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent");
}
@@ -163,9 +163,9 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm) {
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<BtDrv>()->InstallAsService(sm);
- std::make_shared<Bt>()->InstallAsService(sm);
+ std::make_shared<Bt>(system)->InstallAsService(sm);
}
} // 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 {
class ServiceManager;
}
+namespace Core {
+class System;
+}
+
namespace Service::BtDrv {
/// Registers all BtDrv services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm);
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // 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 {
class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
public:
- explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
+ explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -56,7 +56,7 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IBtmUserCore:ScanEvent");
connection_event = Kernel::WritableEvent::CreateEventPair(
@@ -108,7 +108,7 @@ private:
class BTM_USR final : public ServiceFramework<BTM_USR> {
public:
- explicit BTM_USR() : ServiceFramework{"btm:u"} {
+ explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BTM_USR::GetCore, "GetCore"},
@@ -123,8 +123,10 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IBtmUserCore>();
+ rb.PushIpcInterface<IBtmUserCore>(system);
}
+
+ Core::System& system;
};
class BTM final : public ServiceFramework<BTM> {
@@ -268,11 +270,11 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm) {
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<BTM>()->InstallAsService(sm);
std::make_shared<BTM_DBG>()->InstallAsService(sm);
std::make_shared<BTM_SYS>()->InstallAsService(sm);
- std::make_shared<BTM_USR>()->InstallAsService(sm);
+ std::make_shared<BTM_USR>(system)->InstallAsService(sm);
}
} // 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 {
class ServiceManager;
}
+namespace Core {
+class System;
+};
+
namespace Service::BTM {
-void InstallInterfaces(SM::ServiceManager& sm);
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::BTM
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index 6701cb913..af70d174d 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -2,32 +2,37 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/crypto/key_manager.h"
+#include "core/hle/ipc_helpers.h"
#include "core/hle/service/service.h"
namespace Service::ES {
+constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::ETicket, 2};
+constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3};
+
class ETicket final : public ServiceFramework<ETicket> {
public:
explicit ETicket() : ServiceFramework{"es"} {
// clang-format off
static const FunctionInfo functions[] = {
- {1, nullptr, "ImportTicket"},
+ {1, &ETicket::ImportTicket, "ImportTicket"},
{2, nullptr, "ImportTicketCertificateSet"},
{3, nullptr, "DeleteTicket"},
{4, nullptr, "DeletePersonalizedTicket"},
{5, nullptr, "DeleteAllCommonTicket"},
{6, nullptr, "DeleteAllPersonalizedTicket"},
{7, nullptr, "DeleteAllPersonalizedTicketEx"},
- {8, nullptr, "GetTitleKey"},
- {9, nullptr, "CountCommonTicket"},
- {10, nullptr, "CountPersonalizedTicket"},
- {11, nullptr, "ListCommonTicket"},
- {12, nullptr, "ListPersonalizedTicket"},
+ {8, &ETicket::GetTitleKey, "GetTitleKey"},
+ {9, &ETicket::CountCommonTicket, "CountCommonTicket"},
+ {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"},
+ {11, &ETicket::ListCommonTicket, "ListCommonTicket"},
+ {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"},
{13, nullptr, "ListMissingPersonalizedTicket"},
- {14, nullptr, "GetCommonTicketSize"},
- {15, nullptr, "GetPersonalizedTicketSize"},
- {16, nullptr, "GetCommonTicketData"},
- {17, nullptr, "GetPersonalizedTicketData"},
+ {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"},
+ {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"},
+ {16, &ETicket::GetCommonTicketData, "GetCommonTicketData"},
+ {17, &ETicket::GetPersonalizedTicketData, "GetPersonalizedTicketData"},
{18, nullptr, "OwnTicket"},
{19, nullptr, "GetTicketInfo"},
{20, nullptr, "ListLightTicketInfo"},
@@ -51,7 +56,212 @@ public:
};
// clang-format on
RegisterHandlers(functions);
+
+ keys.PopulateTickets();
+ keys.SynthesizeTickets();
+ }
+
+private:
+ bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) {
+ if (rights_id == u128{}) {
+ LOG_ERROR(Service_ETicket, "The rights ID was invalid!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_RIGHTS_ID);
+ return false;
+ }
+
+ return true;
+ }
+
+ void ImportTicket(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto ticket = ctx.ReadBuffer();
+ const auto cert = ctx.ReadBuffer(1);
+
+ if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
+ LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ARGUMENT);
+ return;
+ }
+
+ Core::Crypto::Ticket raw{};
+ std::memcpy(&raw, ticket.data(), sizeof(Core::Crypto::Ticket));
+
+ if (!keys.AddTicketPersonalized(raw)) {
+ LOG_ERROR(Service_ETicket, "The ticket could not be imported!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ARGUMENT);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void GetTitleKey(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto rights_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
+
+ if (!CheckRightsId(ctx, rights_id))
+ return;
+
+ const auto key =
+ keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
+
+ if (key == Core::Crypto::Key128{}) {
+ LOG_ERROR(Service_ETicket,
+ "The titlekey doesn't exist in the KeyManager or the rights ID was invalid!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_RIGHTS_ID);
+ return;
+ }
+
+ ctx.WriteBuffer(key.data(), key.size());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void CountCommonTicket(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ETicket, "called");
+
+ const auto count = keys.GetCommonTickets().size();
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(count);
+ }
+
+ void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ETicket, "called");
+
+ const auto count = keys.GetPersonalizedTickets().size();
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(count);
+ }
+
+ void ListCommonTicket(Kernel::HLERequestContext& ctx) {
+ u32 out_entries;
+ if (keys.GetCommonTickets().empty())
+ out_entries = 0;
+ else
+ out_entries = ctx.GetWriteBufferSize() / sizeof(u128);
+
+ LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
+
+ keys.PopulateTickets();
+ const auto tickets = keys.GetCommonTickets();
+ std::vector<u128> ids;
+ std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
+ [](const auto& pair) { return pair.first; });
+
+ out_entries = std::min<u32>(ids.size(), out_entries);
+ ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(out_entries);
}
+
+ void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) {
+ u32 out_entries;
+ if (keys.GetPersonalizedTickets().empty())
+ out_entries = 0;
+ else
+ out_entries = ctx.GetWriteBufferSize() / sizeof(u128);
+
+ LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
+
+ keys.PopulateTickets();
+ const auto tickets = keys.GetPersonalizedTickets();
+ std::vector<u128> ids;
+ std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
+ [](const auto& pair) { return pair.first; });
+
+ out_entries = std::min<u32>(ids.size(), out_entries);
+ ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(out_entries);
+ }
+
+ void GetCommonTicketSize(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto rights_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
+
+ if (!CheckRightsId(ctx, rights_id))
+ return;
+
+ const auto ticket = keys.GetCommonTickets().at(rights_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(ticket.GetSize());
+ }
+
+ void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto rights_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
+
+ if (!CheckRightsId(ctx, rights_id))
+ return;
+
+ const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(ticket.GetSize());
+ }
+
+ void GetCommonTicketData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto rights_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
+
+ if (!CheckRightsId(ctx, rights_id))
+ return;
+
+ const auto ticket = keys.GetCommonTickets().at(rights_id);
+
+ const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize());
+ ctx.WriteBuffer(&ticket, write_size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(write_size);
+ }
+
+ void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto rights_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]);
+
+ if (!CheckRightsId(ctx, rights_id))
+ return;
+
+ const auto ticket = keys.GetPersonalizedTickets().at(rights_id);
+
+ const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize());
+ ctx.WriteBuffer(&ticket, write_size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(write_size);
+ }
+
+ Core::Crypto::KeyManager keys;
};
void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 2c229bcad..b2ebf6240 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -5,7 +5,7 @@
#include <array>
#include <cstring>
#include <ctime>
-#include <fmt/time.h>
+#include <fmt/chrono.h>
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
@@ -16,11 +16,12 @@
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
+#include "core/reporter.h"
namespace Service::Fatal {
-Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {}
+Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
+ : ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::~Interface() = default;
@@ -63,7 +64,8 @@ enum class FatalType : u32 {
ErrorScreen = 2,
};
-static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
+static void GenerateErrorReport(Core::System& system, ResultCode error_code,
+ const FatalInfo& info) {
const auto title_id = Core::CurrentProcess()->GetTitleID();
std::string crash_report = fmt::format(
"Yuzu {}-{} crash report\n"
@@ -100,35 +102,19 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
LOG_ERROR(Service_Fatal, "{}", crash_report);
- const std::string crashreport_dir =
- FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "crash_logs";
-
- if (!FileUtil::CreateFullPath(crashreport_dir)) {
- LOG_ERROR(
- Service_Fatal,
- "Unable to create crash report directory. Possible log directory permissions issue.");
- return;
- }
-
- const std::time_t t = std::time(nullptr);
- const std::string crashreport_filename =
- fmt::format("{}/{:016x}-{:%F-%H%M%S}.log", crashreport_dir, title_id, *std::localtime(&t));
-
- auto file = FileUtil::IOFile(crashreport_filename, "wb");
- if (file.IsOpen()) {
- file.WriteString(crash_report);
- LOG_ERROR(Service_Fatal, "Saving error report to {}", crashreport_filename);
- } else {
- LOG_ERROR(Service_Fatal, "Failed to save error report to {}", crashreport_filename);
- }
+ system.GetReporter().SaveCrashReport(
+ title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc,
+ info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace,
+ info.backtrace_size, info.ArchAsString(), info.unk10);
}
-static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
+static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type,
+ const FatalInfo& info) {
LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}",
static_cast<u32>(fatal_type), error_code.raw);
switch (fatal_type) {
case FatalType::ErrorReportAndScreen:
- GenerateErrorReport(error_code, info);
+ GenerateErrorReport(system, error_code, info);
[[fallthrough]];
case FatalType::ErrorScreen:
// Since we have no fatal:u error screen. We should just kill execution instead
@@ -136,7 +122,7 @@ static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const F
break;
// Should not throw a fatal screen but should generate an error report
case FatalType::ErrorReport:
- GenerateErrorReport(error_code, info);
+ GenerateErrorReport(system, error_code, info);
break;
}
}
@@ -146,7 +132,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto error_code = rp.Pop<ResultCode>();
- ThrowFatalError(error_code, FatalType::ErrorScreen, {});
+ ThrowFatalError(system, error_code, FatalType::ErrorScreen, {});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -157,7 +143,8 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
const auto error_code = rp.Pop<ResultCode>();
const auto fatal_type = rp.PopEnum<FatalType>();
- ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy
+ ThrowFatalError(system, error_code, fatal_type,
+ {}); // No info is passed with ThrowFatalWithPolicy
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -173,15 +160,15 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx)
ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
- ThrowFatalError(error_code, fatal_type, info);
+ ThrowFatalError(system, error_code, fatal_type, info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
- std::make_shared<Fatal_P>(module)->InstallAsService(service_manager);
- std::make_shared<Fatal_U>(module)->InstallAsService(service_manager);
+ std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
+ std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
}
} // 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 @@
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Service::Fatal {
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(std::shared_ptr<Module> module, const char* name);
+ explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
void ThrowFatal(Kernel::HLERequestContext& ctx);
@@ -21,9 +25,10 @@ public:
protected:
std::shared_ptr<Module> module;
+ Core::System& system;
};
};
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // 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 @@
namespace Service::Fatal {
-Fatal_P::Fatal_P(std::shared_ptr<Module> module)
- : Module::Interface(std::move(module), "fatal:p") {}
+Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system)
+ : Module::Interface(std::move(module), system, "fatal:p") {}
Fatal_P::~Fatal_P() = default;
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 {
class Fatal_P final : public Module::Interface {
public:
- explicit Fatal_P(std::shared_ptr<Module> module);
+ explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system);
~Fatal_P() override;
};
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 @@
namespace Service::Fatal {
-Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") {
+Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system)
+ : Module::Interface(std::move(module), system, "fatal:u") {
static const FunctionInfo functions[] = {
{0, &Fatal_U::ThrowFatal, "ThrowFatal"},
{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 {
class Fatal_U final : public Module::Interface {
public:
- explicit Fatal_U(std::shared_ptr<Module> module);
+ explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system);
~Fatal_U() override;
};
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 1ebfeb4bf..14cd0e322 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -8,6 +8,7 @@
#include "common/file_util.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
+#include "core/file_sys/card_image.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/mode.h"
@@ -25,14 +26,10 @@
#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/loader/loader.h"
+#include "core/settings.h"
namespace Service::FileSystem {
-// Size of emulated sd card free space, reported in bytes.
-// Just using 32GB because thats reasonable
-// TODO(DarkLordZach): Eventually make this configurable in settings.
-constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
-
// A default size for normal/journal save data size if application control metadata cannot be found.
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
@@ -226,13 +223,6 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
return MakeResult(dir);
}
-u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
- if (backing->IsWritable())
- return EMULATED_SD_REPORTED_SIZE;
-
- return 0;
-}
-
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
const std::string& path_) const {
std::string path(FileUtil::SanitizePath(path_));
@@ -251,44 +241,39 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
return FileSys::ERROR_PATH_NOT_FOUND;
}
-/**
- * Map of registered file systems, identified by type. Once an file system is registered here, it
- * is never removed until UnregisterFileSystems is called.
- */
-static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
-static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
-static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
-static std::unique_ptr<FileSys::BISFactory> bis_factory;
+FileSystemController::FileSystemController() = default;
+
+FileSystemController::~FileSystemController() = default;
-ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
- ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
+ResultCode FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
romfs_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered RomFS");
return RESULT_SUCCESS;
}
-ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
- ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
+ResultCode FileSystemController::RegisterSaveData(
+ std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
+ ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
save_data_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered save data");
return RESULT_SUCCESS;
}
-ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
+ResultCode FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
sdmc_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered SDMC");
return RESULT_SUCCESS;
}
-ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
+ResultCode FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
bis_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered BIS");
return RESULT_SUCCESS;
}
-void SetPackedUpdate(FileSys::VirtualFile update_raw) {
+void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
LOG_TRACE(Service_FS, "Setting packed update for romfs");
if (romfs_factory == nullptr)
@@ -297,7 +282,7 @@ void SetPackedUpdate(FileSys::VirtualFile update_raw) {
romfs_factory->SetPackedUpdate(std::move(update_raw));
}
-ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
@@ -308,8 +293,8 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
return romfs_factory->OpenCurrentProcess();
}
-ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type) {
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
+ u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
@@ -321,8 +306,20 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
return romfs_factory->Open(title_id, storage_id, type);
}
-ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataDescriptor& descriptor) {
+ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const {
+ LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
+ static_cast<u8>(space), save_struct.DebugInfo());
+
+ if (save_data_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ return save_data_factory->Create(space, save_struct);
+}
+
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), descriptor.DebugInfo());
@@ -333,7 +330,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
return save_data_factory->Open(space, descriptor);
}
-ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
+ FileSys::SaveDataSpaceId space) const {
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
if (save_data_factory == nullptr) {
@@ -343,7 +341,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
}
-ResultVal<FileSys::VirtualDir> OpenSDMC() {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
@@ -353,7 +351,92 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
-FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
+ FileSys::BisPartitionId id) const {
+ LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id));
+
+ if (bis_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ auto part = bis_factory->OpenPartition(id);
+ if (part == nullptr) {
+ return FileSys::ERROR_INVALID_ARGUMENT;
+ }
+
+ return MakeResult<FileSys::VirtualDir>(std::move(part));
+}
+
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
+ FileSys::BisPartitionId id) const {
+ LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id));
+
+ if (bis_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ auto part = bis_factory->OpenPartitionStorage(id);
+ if (part == nullptr) {
+ return FileSys::ERROR_INVALID_ARGUMENT;
+ }
+
+ return MakeResult<FileSys::VirtualFile>(std::move(part));
+}
+
+u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::GameCard:
+ return 0;
+ case FileSys::StorageId::SdCard:
+ if (sdmc_factory == nullptr)
+ return 0;
+ return sdmc_factory->GetSDMCFreeSpace();
+ case FileSys::StorageId::Host:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
+ case FileSys::StorageId::NandSystem:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDFreeSpace();
+ case FileSys::StorageId::NandUser:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetUserNANDFreeSpace();
+ }
+
+ return 0;
+}
+
+u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::GameCard:
+ return 0;
+ case FileSys::StorageId::SdCard:
+ if (sdmc_factory == nullptr)
+ return 0;
+ return sdmc_factory->GetSDMCTotalSpace();
+ case FileSys::StorageId::Host:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetFullNANDTotalSpace();
+ case FileSys::StorageId::NandSystem:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDTotalSpace();
+ case FileSys::StorageId::NandUser:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetUserNANDTotalSpace();
+ }
+
+ return 0;
+}
+
+FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
+ u64 title_id, u128 user_id) const {
if (save_data_factory == nullptr) {
return {0, 0};
}
@@ -385,13 +468,32 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
return value;
}
-void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
- FileSys::SaveDataSize new_value) {
+void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
+ FileSys::SaveDataSize new_value) const {
if (save_data_factory != nullptr)
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
}
-FileSys::RegisteredCache* GetSystemNANDContents() {
+void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
+ gamecard = std::make_unique<FileSys::XCI>(file);
+ const auto dir = gamecard->ConcatenatedPseudoDirectory();
+ gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
+ gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
+}
+
+FileSys::XCI* FileSystemController::GetGameCard() const {
+ return gamecard.get();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
+ return gamecard_registered.get();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
+ return gamecard_placeholder.get();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
if (bis_factory == nullptr)
@@ -400,7 +502,7 @@ FileSys::RegisteredCache* GetSystemNANDContents() {
return bis_factory->GetSystemNANDContents();
}
-FileSys::RegisteredCache* GetUserNANDContents() {
+FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
LOG_TRACE(Service_FS, "Opening User NAND Contents");
if (bis_factory == nullptr)
@@ -409,7 +511,7 @@ FileSys::RegisteredCache* GetUserNANDContents() {
return bis_factory->GetUserNANDContents();
}
-FileSys::RegisteredCache* GetSDMCContents() {
+FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
LOG_TRACE(Service_FS, "Opening SDMC Contents");
if (sdmc_factory == nullptr)
@@ -418,7 +520,143 @@ FileSys::RegisteredCache* GetSDMCContents() {
return sdmc_factory->GetSDMCContents();
}
-FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
+FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetSystemNANDPlaceholder();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetUserNANDPlaceholder();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetSDMCPlaceholder();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
+ FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::Host:
+ UNIMPLEMENTED();
+ return nullptr;
+ case FileSys::StorageId::GameCard:
+ return GetGameCardContents();
+ case FileSys::StorageId::NandSystem:
+ return GetSystemNANDContents();
+ case FileSys::StorageId::NandUser:
+ return GetUserNANDContents();
+ case FileSys::StorageId::SdCard:
+ return GetSDMCContents();
+ }
+
+ return nullptr;
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
+ FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::Host:
+ UNIMPLEMENTED();
+ return nullptr;
+ case FileSys::StorageId::GameCard:
+ return GetGameCardPlaceholder();
+ case FileSys::StorageId::NandSystem:
+ return GetSystemNANDPlaceholder();
+ case FileSys::StorageId::NandUser:
+ return GetUserNANDPlaceholder();
+ case FileSys::StorageId::SdCard:
+ return GetSDMCPlaceholder();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening system NAND content directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetSystemNANDContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening user NAND content directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetUserNANDContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening SDMC content directory");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetSDMCContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
+ LOG_TRACE(Service_FS, "Opening NAND image directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetImageDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
+ LOG_TRACE(Service_FS, "Opening SDMC image directory");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetImageDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
+ switch (id) {
+ case ContentStorageId::System:
+ return GetSystemNANDContentDirectory();
+ case ContentStorageId::User:
+ return GetUserNANDContentDirectory();
+ case ContentStorageId::SdCard:
+ return GetSDMCContentDirectory();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
+ switch (id) {
+ case ImageDirectoryId::NAND:
+ return GetNANDImageDirectory();
+ case ImageDirectoryId::SdCard:
+ return GetSDMCImageDirectory();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -427,7 +665,7 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
return bis_factory->GetModificationLoadRoot(title_id);
}
-FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
+FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -436,7 +674,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
return bis_factory->GetModificationDumpRoot(title_id);
}
-void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
+void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
@@ -472,12 +710,11 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
}
}
-void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
- romfs_factory = nullptr;
- CreateFactories(vfs, false);
- std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
- std::make_shared<FSP_PR>()->InstallAsService(service_manager);
- std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
+void InstallInterfaces(Core::System& system) {
+ std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
+ std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
+ std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
+ ->InstallAsService(system.ServiceManager());
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6481f237c..3e0c03ec0 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -14,10 +14,13 @@ namespace FileSys {
class BISFactory;
class RegisteredCache;
class RegisteredCacheUnion;
+class PlaceholderCache;
class RomFSFactory;
class SaveDataFactory;
class SDMCFactory;
+class XCI;
+enum class BisPartitionId : u32;
enum class ContentRecordType : u8;
enum class Mode : u32;
enum class SaveDataSpaceId : u8;
@@ -36,36 +39,93 @@ class ServiceManager;
namespace FileSystem {
-ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
-ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
-ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
-ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
-
-void SetPackedUpdate(FileSys::VirtualFile update_raw);
-ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
-ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type);
-ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataDescriptor& descriptor);
-ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
-ResultVal<FileSys::VirtualDir> OpenSDMC();
-
-FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
-void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
- FileSys::SaveDataSize new_value);
+enum class ContentStorageId : u32 {
+ System,
+ User,
+ SdCard,
+};
-FileSys::RegisteredCache* GetSystemNANDContents();
-FileSys::RegisteredCache* GetUserNANDContents();
-FileSys::RegisteredCache* GetSDMCContents();
+enum class ImageDirectoryId : u32 {
+ NAND,
+ SdCard,
+};
-FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
-FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
+class FileSystemController {
+public:
+ FileSystemController();
+ ~FileSystemController();
+
+ ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
+ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
+ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
+ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
+
+ void SetPackedUpdate(FileSys::VirtualFile update_raw);
+ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
+ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type) const;
+ ResultVal<FileSys::VirtualDir> CreateSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
+ ResultVal<FileSys::VirtualDir> OpenSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
+ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
+ ResultVal<FileSys::VirtualDir> OpenSDMC() const;
+ ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
+ ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
+
+ u64 GetFreeSpaceSize(FileSys::StorageId id) const;
+ u64 GetTotalSpaceSize(FileSys::StorageId id) const;
+
+ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
+ u128 user_id) const;
+ void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
+ FileSys::SaveDataSize new_value) const;
+
+ void SetGameCard(FileSys::VirtualFile file);
+ FileSys::XCI* GetGameCard() const;
+
+ FileSys::RegisteredCache* GetSystemNANDContents() const;
+ FileSys::RegisteredCache* GetUserNANDContents() const;
+ FileSys::RegisteredCache* GetSDMCContents() const;
+ FileSys::RegisteredCache* GetGameCardContents() const;
+
+ FileSys::PlaceholderCache* GetSystemNANDPlaceholder() const;
+ FileSys::PlaceholderCache* GetUserNANDPlaceholder() const;
+ FileSys::PlaceholderCache* GetSDMCPlaceholder() const;
+ FileSys::PlaceholderCache* GetGameCardPlaceholder() const;
+
+ FileSys::RegisteredCache* GetRegisteredCacheForStorage(FileSys::StorageId id) const;
+ FileSys::PlaceholderCache* GetPlaceholderCacheForStorage(FileSys::StorageId id) const;
+
+ FileSys::VirtualDir GetSystemNANDContentDirectory() const;
+ FileSys::VirtualDir GetUserNANDContentDirectory() const;
+ FileSys::VirtualDir GetSDMCContentDirectory() const;
+
+ FileSys::VirtualDir GetNANDImageDirectory() const;
+ FileSys::VirtualDir GetSDMCImageDirectory() const;
+
+ FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
+ FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
+
+ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
+ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
+
+ // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
+ // above is called.
+ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
-// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
-// above is called.
-void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
+private:
+ std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
+ std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
+ std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
+ std::unique_ptr<FileSys::BISFactory> bis_factory;
+
+ std::unique_ptr<FileSys::XCI> gamecard;
+ std::unique_ptr<FileSys::RegisteredCache> gamecard_registered;
+ std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder;
+};
-void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs);
+void InstallInterfaces(Core::System& system);
// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
@@ -160,12 +220,6 @@ public:
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
/**
- * Get the free space
- * @return The number of free bytes in the archive
- */
- u64 GetFreeSpaceSize() const;
-
- /**
* Get the type of the specified path
* @return The type of the specified path or error code
*/
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e7df8fd98..eb982ad49 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -19,6 +19,7 @@
#include "core/file_sys/mode.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
@@ -26,9 +27,22 @@
#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
+#include "core/reporter.h"
namespace Service::FileSystem {
+struct SizeGetter {
+ std::function<u64()> get_free_size;
+ std::function<u64()> get_total_size;
+
+ static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
+ return {
+ [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
+ [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
+ };
+ }
+};
+
enum class FileSystemType : u8 {
Invalid0 = 0,
Invalid1 = 1,
@@ -288,8 +302,8 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
- explicit IFileSystem(FileSys::VirtualDir backend)
- : ServiceFramework("IFileSystem"), backend(std::move(backend)) {
+ explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size)
+ : ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -466,14 +480,31 @@ public:
rb.Push(RESULT_SUCCESS);
}
+ void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(size.get_free_size());
+ }
+
+ void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(size.get_total_size());
+ }
+
private:
VfsDirectoryServiceWrapper backend;
+ SizeGetter size;
};
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
public:
- explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
- : ServiceFramework("ISaveDataInfoReader") {
+ explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc)
+ : ServiceFramework("ISaveDataInfoReader"), fsc(fsc) {
static const FunctionInfo functions[] = {
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
};
@@ -519,8 +550,13 @@ private:
}
void FindAllSaves(FileSys::SaveDataSpaceId space) {
- const auto save_root = OpenSaveDataSpace(space);
- ASSERT(save_root.Succeeded());
+ const auto save_root = fsc.OpenSaveDataSpace(space);
+
+ if (save_root.Failed() || *save_root == nullptr) {
+ LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!",
+ static_cast<u8>(space));
+ return;
+ }
for (const auto& type : (*save_root)->GetSubdirectories()) {
if (type->GetName() == "save") {
@@ -609,11 +645,13 @@ private:
};
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+ FileSystemController& fsc;
std::vector<SaveDataInfo> info;
u64 next_entry_index = 0;
};
-FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
+ : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
@@ -710,14 +748,14 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{1001, nullptr, "SetSaveDataSize"},
{1002, nullptr, "SetSaveDataRootPath"},
{1003, nullptr, "DisableAutoSaveDataCreation"},
- {1004, nullptr, "SetGlobalAccessLogMode"},
+ {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
{1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
- {1006, nullptr, "OutputAccessLogToSdCard"},
+ {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
{1007, nullptr, "RegisterUpdatePartition"},
{1008, nullptr, "OpenRegisteredUpdatePartition"},
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
- {1011, nullptr, "OutputAccessLogToSdCard2"},
+ {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, nullptr, "OpenMultiCommitManager"},
@@ -753,7 +791,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- IFileSystem filesystem(OpenSDMC().Unwrap());
+ IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
+ SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -767,8 +806,10 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
u128 uid = rp.PopRaw<u128>();
- LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
- save_struct.DebugInfo(), uid[1], uid[0]);
+ LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
+ uid[1], uid[0]);
+
+ fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -785,14 +826,24 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
- auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
+ auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
}
- IFileSystem filesystem(std::move(dir.Unwrap()));
+ FileSys::StorageId id;
+ if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) {
+ id = FileSys::StorageId::NandUser;
+ } else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem ||
+ parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) {
+ id = FileSys::StorageId::SdCard;
+ } else {
+ id = FileSys::StorageId::NandSystem;
+ }
+
+ IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -811,30 +862,31 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
+ rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
}
-void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
+void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ log_mode = rp.PopEnum<LogMode>();
- enum class LogMode : u32 {
- Off,
- Log,
- RedirectToSdCard,
- LogToSdCard = Log | RedirectToSdCard,
- };
+ LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
- // Given we always want to receive logging information,
- // we always specify logging as enabled.
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.PushEnum(LogMode::Log);
+ rb.PushEnum(log_mode);
}
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- auto romfs = OpenRomFSCurrentProcess();
+ auto romfs = fsc.OpenRomFSCurrentProcess();
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -859,7 +911,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
static_cast<u8>(storage_id), unknown, title_id);
- auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
+ auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
@@ -902,4 +954,26 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
}
+void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
+ const auto raw = ctx.ReadBuffer();
+ auto log = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(raw.data()), raw.size());
+
+ LOG_DEBUG(Service_FS, "called, log='{}'", log);
+
+ reporter.SaveFilesystemAccessReport(log_mode, std::move(log));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushEnum(AccessLogVersion::Latest);
+ rb.Push(access_log_program_index);
+}
+
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index d7572ba7a..d52b55999 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -7,15 +7,32 @@
#include <memory>
#include "core/hle/service/service.h"
+namespace Core {
+class Reporter;
+}
+
namespace FileSys {
class FileSystemBackend;
}
namespace Service::FileSystem {
+enum class AccessLogVersion : u32 {
+ V7_0_0 = 2,
+
+ Latest = V7_0_0,
+};
+
+enum class LogMode : u32 {
+ Off,
+ Log,
+ RedirectToSdCard,
+ LogToSdCard = Log | RedirectToSdCard,
+};
+
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
public:
- explicit FSP_SRV();
+ explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
~FSP_SRV() override;
private:
@@ -26,13 +43,22 @@ private:
void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
+ void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
+ void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
+ void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
+
+ FileSystemController& fsc;
FileSys::VirtualFile romfs;
u64 current_process_id = 0;
+ u32 access_log_program_index = 0;
+ LogMode log_mode = LogMode::LogToSdCard;
+
+ const Core::Reporter& reporter;
};
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h
new file mode 100644
index 000000000..b3996e275
--- /dev/null
+++ b/src/core/hle/service/friend/errors.h
@@ -0,0 +1,12 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::Friend {
+
+constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15};
+}
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 5100e376c..42b4ee861 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -2,8 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <queue>
#include "common/logging/log.h"
+#include "common/uuid.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/friend/errors.h"
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/friend/interface.h"
@@ -17,7 +22,7 @@ public:
{0, nullptr, "GetCompletionEvent"},
{1, nullptr, "Cancel"},
{10100, nullptr, "GetFriendListIds"},
- {10101, nullptr, "GetFriendList"},
+ {10101, &IFriendService::GetFriendList, "GetFriendList"},
{10102, nullptr, "UpdateFriendInfo"},
{10110, nullptr, "GetFriendProfileImage"},
{10200, nullptr, "SendFriendRequestForApplication"},
@@ -94,6 +99,23 @@ public:
}
private:
+ enum class PresenceFilter : u32 {
+ None = 0,
+ Online = 1,
+ OnlinePlay = 2,
+ OnlineOrOnlinePlay = 3,
+ };
+
+ struct SizedFriendFilter {
+ PresenceFilter presence;
+ u8 is_favorite;
+ u8 same_app;
+ u8 same_app_played;
+ u8 arbitary_app_played;
+ u64 group_id;
+ };
+ static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
+
void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_ACC, "(STUBBED) called");
@@ -107,6 +129,118 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+
+ void GetFriendList(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto friend_offset = rp.Pop<u32>();
+ const auto uuid = rp.PopRaw<Common::UUID>();
+ [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
+ const auto pid = rp.Pop<u64>();
+ LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
+ uuid.Format(), pid);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+
+ rb.Push<u32>(0); // Friend count
+ // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
+ }
+};
+
+class INotificationService final : public ServiceFramework<INotificationService> {
+public:
+ INotificationService(Common::UUID uuid, Core::System& system)
+ : ServiceFramework("INotificationService"), uuid(uuid) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &INotificationService::GetEvent, "GetEvent"},
+ {1, &INotificationService::Clear, "Clear"},
+ {2, &INotificationService::Pop, "Pop"}
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+
+ notification_event = Kernel::WritableEvent::CreateEventPair(
+ system.Kernel(), Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
+ }
+
+private:
+ void GetEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(notification_event.readable);
+ }
+
+ void Clear(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
+ while (!notifications.empty()) {
+ notifications.pop();
+ }
+ std::memset(&states, 0, sizeof(States));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void Pop(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
+
+ if (notifications.empty()) {
+ LOG_ERROR(Service_ACC, "No notifications in queue!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NO_NOTIFICATIONS);
+ return;
+ }
+
+ const auto notification = notifications.front();
+ notifications.pop();
+
+ switch (notification.notification_type) {
+ case NotificationTypes::HasUpdatedFriendsList:
+ states.has_updated_friends = false;
+ break;
+ case NotificationTypes::HasReceivedFriendRequest:
+ states.has_received_friend_request = false;
+ break;
+ default:
+ // HOS seems not have an error case for an unknown notification
+ LOG_WARNING(Service_ACC, "Unknown notification {:08X}",
+ static_cast<u32>(notification.notification_type));
+ break;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<SizedNotificationInfo>(notification);
+ }
+
+ enum class NotificationTypes : u32 {
+ HasUpdatedFriendsList = 0x65,
+ HasReceivedFriendRequest = 0x1
+ };
+
+ struct SizedNotificationInfo {
+ NotificationTypes notification_type;
+ INSERT_PADDING_WORDS(
+ 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
+ u64_le account_id;
+ };
+ static_assert(sizeof(SizedNotificationInfo) == 0x10,
+ "SizedNotificationInfo is an incorrect size");
+
+ struct States {
+ bool has_updated_friends;
+ bool has_received_friend_request;
+ };
+
+ Common::UUID uuid;
+ bool is_event_created = false;
+ Kernel::EventPair notification_event;
+ std::queue<SizedNotificationInfo> notifications;
+ States states{};
};
void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
@@ -116,18 +250,29 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
}
-Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {}
+void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ auto uuid = rp.PopRaw<Common::UUID>();
+
+ LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format());
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<INotificationService>(uuid, system);
+}
+
+Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
+ : ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::~Interface() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
- std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager);
+ std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
+ std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
+ std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
+ std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
+ std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
}
} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index e762840cb..24f3fc969 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -6,23 +6,29 @@
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Service::Friend {
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(std::shared_ptr<Module> module, const char* name);
+ explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
void CreateFriendService(Kernel::HLERequestContext& ctx);
+ void CreateNotificationService(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
+ Core::System& system;
};
};
/// Registers all Friend services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp
index 5a6840af5..58155f652 100644
--- a/src/core/hle/service/friend/interface.cpp
+++ b/src/core/hle/service/friend/interface.cpp
@@ -6,11 +6,11 @@
namespace Service::Friend {
-Friend::Friend(std::shared_ptr<Module> module, const char* name)
- : Interface(std::move(module), name) {
+Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name)
+ : Interface(std::move(module), system, name) {
static const FunctionInfo functions[] = {
{0, &Friend::CreateFriendService, "CreateFriendService"},
- {1, nullptr, "CreateNotificationService"},
+ {1, &Friend::CreateNotificationService, "CreateNotificationService"},
{2, nullptr, "CreateDaemonSuspendSessionService"},
};
RegisterHandlers(functions);
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 {
class Friend final : public Module::Interface {
public:
- explicit Friend(std::shared_ptr<Module> module, const char* name);
+ explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Friend() override;
};
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
new file mode 100644
index 000000000..b591ce31b
--- /dev/null
+++ b/src/core/hle/service/glue/arp.cpp
@@ -0,0 +1,297 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/glue/arp.h"
+#include "core/hle/service/glue/errors.h"
+#include "core/hle/service/glue/manager.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Glue {
+
+namespace {
+std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) {
+ const auto& list = system.Kernel().GetProcessList();
+ const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
+ return process->GetProcessID() == process_id;
+ });
+
+ if (iter == list.end()) {
+ return std::nullopt;
+ }
+
+ return (*iter)->GetTitleID();
+}
+} // Anonymous namespace
+
+ARP_R::ARP_R(const Core::System& system, const ARPManager& manager)
+ : ServiceFramework{"arp:r"}, system(system), manager(manager) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"},
+ {1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
+ {2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
+ {3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ARP_R::~ARP_R() = default;
+
+void ARP_R::GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
+
+ const auto title_id = GetTitleIDForProcessID(system, process_id);
+ if (!title_id.has_value()) {
+ LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_REGISTERED);
+ return;
+ }
+
+ const auto res = manager.GetLaunchProperty(*title_id);
+
+ if (res.Failed()) {
+ LOG_ERROR(Service_ARP, "Failed to get launch property!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res.Code());
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(*res);
+}
+
+void ARP_R::GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto title_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
+
+ const auto res = manager.GetLaunchProperty(title_id);
+
+ if (res.Failed()) {
+ LOG_ERROR(Service_ARP, "Failed to get launch property!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res.Code());
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw(*res);
+}
+
+void ARP_R::GetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
+
+ const auto title_id = GetTitleIDForProcessID(system, process_id);
+ if (!title_id.has_value()) {
+ LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_REGISTERED);
+ return;
+ }
+
+ const auto res = manager.GetControlProperty(*title_id);
+
+ if (res.Failed()) {
+ LOG_ERROR(Service_ARP, "Failed to get control property!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res.Code());
+ return;
+ }
+
+ ctx.WriteBuffer(*res);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void ARP_R::GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto title_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
+
+ const auto res = manager.GetControlProperty(title_id);
+
+ if (res.Failed()) {
+ LOG_ERROR(Service_ARP, "Failed to get control property!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res.Code());
+ return;
+ }
+
+ ctx.WriteBuffer(*res);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+class IRegistrar final : public ServiceFramework<IRegistrar> {
+ friend class ARP_W;
+
+public:
+ explicit IRegistrar(
+ std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer)
+ : ServiceFramework{"IRegistrar"}, issue_process_id(std::move(issuer)) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IRegistrar::Issue, "Issue"},
+ {1, &IRegistrar::SetApplicationLaunchProperty, "SetApplicationLaunchProperty"},
+ {2, &IRegistrar::SetApplicationControlProperty, "SetApplicationControlProperty"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void Issue(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
+
+ if (process_id == 0) {
+ LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_PROCESS_ID);
+ return;
+ }
+
+ if (issued) {
+ LOG_ERROR(Service_ARP,
+ "Attempted to issue registrar, but registrar is already issued!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_ACCESS);
+ return;
+ }
+
+ issue_process_id(process_id, launch, std::move(control));
+ issued = true;
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void SetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ARP, "called");
+
+ if (issued) {
+ LOG_ERROR(
+ Service_ARP,
+ "Attempted to set application launch property, but registrar is already issued!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_ACCESS);
+ return;
+ }
+
+ IPC::RequestParser rp{ctx};
+ launch = rp.PopRaw<ApplicationLaunchProperty>();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void SetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ARP, "called");
+
+ if (issued) {
+ LOG_ERROR(
+ Service_ARP,
+ "Attempted to set application control property, but registrar is already issued!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_ACCESS);
+ return;
+ }
+
+ control = ctx.ReadBuffer();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issue_process_id;
+ bool issued = false;
+ ApplicationLaunchProperty launch;
+ std::vector<u8> control;
+};
+
+ARP_W::ARP_W(const Core::System& system, ARPManager& manager)
+ : ServiceFramework{"arp:w"}, system(system), manager(manager) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
+ {1, &ARP_W::DeleteProperties, "DeleteProperties"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ARP_W::~ARP_W() = default;
+
+void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ARP, "called");
+
+ registrar = std::make_shared<IRegistrar>(
+ [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) {
+ const auto res = GetTitleIDForProcessID(system, process_id);
+ if (!res.has_value()) {
+ return ERR_NOT_REGISTERED;
+ }
+
+ return manager.Register(*res, launch, std::move(control));
+ });
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface(registrar);
+}
+
+void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
+
+ if (process_id == 0) {
+ LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_PROCESS_ID);
+ return;
+ }
+
+ const auto title_id = GetTitleIDForProcessID(system, process_id);
+
+ if (!title_id.has_value()) {
+ LOG_ERROR(Service_ARP, "No title ID for process ID!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_REGISTERED);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(manager.Unregister(*title_id));
+}
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
new file mode 100644
index 000000000..d5f8a7e7a
--- /dev/null
+++ b/src/core/hle/service/glue/arp.h
@@ -0,0 +1,43 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Glue {
+
+class ARPManager;
+class IRegistrar;
+
+class ARP_R final : public ServiceFramework<ARP_R> {
+public:
+ explicit ARP_R(const Core::System& system, const ARPManager& manager);
+ ~ARP_R() override;
+
+private:
+ void GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx);
+ void GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
+ void GetApplicationControlProperty(Kernel::HLERequestContext& ctx);
+ void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
+
+ const Core::System& system;
+ const ARPManager& manager;
+};
+
+class ARP_W final : public ServiceFramework<ARP_W> {
+public:
+ explicit ARP_W(const Core::System& system, ARPManager& manager);
+ ~ARP_W() override;
+
+private:
+ void AcquireRegistrar(Kernel::HLERequestContext& ctx);
+ void DeleteProperties(Kernel::HLERequestContext& ctx);
+
+ const Core::System& system;
+ ARPManager& manager;
+ std::shared_ptr<IRegistrar> registrar;
+};
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
new file mode 100644
index 000000000..cd89d088f
--- /dev/null
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -0,0 +1,50 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/glue/bgtc.h"
+
+namespace Service::Glue {
+
+BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, nullptr, "NotifyTaskStarting"},
+ {2, nullptr, "NotifyTaskFinished"},
+ {3, nullptr, "GetTriggerEvent"},
+ {4, nullptr, "IsInHalfAwake"},
+ {5, nullptr, "NotifyClientName"},
+ {6, nullptr, "IsInFullAwake"},
+ {11, nullptr, "ScheduleTask"},
+ {12, nullptr, "GetScheduledTaskInterval"},
+ {13, nullptr, "UnscheduleTask"},
+ {14, nullptr, "GetScheduleEvent"},
+ {15, nullptr, "SchedulePeriodicTask"},
+ {101, nullptr, "GetOperationMode"},
+ {102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
+ {103, nullptr, "WillStayHalfAwakeInsteadSleep"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+BGTC_T::~BGTC_T() = default;
+
+BGTC_SC::BGTC_SC() : ServiceFramework{"bgtc:sc"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, nullptr, "GetState"},
+ {2, nullptr, "GetStateChangedEvent"},
+ {3, nullptr, "NotifyEnteringHalfAwake"},
+ {4, nullptr, "NotifyLeavingHalfAwake"},
+ {5, nullptr, "SetIsUsingSleepUnsupportedDevices"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+BGTC_SC::~BGTC_SC() = default;
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
new file mode 100644
index 000000000..81844f03e
--- /dev/null
+++ b/src/core/hle/service/glue/bgtc.h
@@ -0,0 +1,23 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::Glue {
+
+class BGTC_T final : public ServiceFramework<BGTC_T> {
+public:
+ BGTC_T();
+ ~BGTC_T() override;
+};
+
+class BGTC_SC final : public ServiceFramework<BGTC_SC> {
+public:
+ BGTC_SC();
+ ~BGTC_SC() override;
+};
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/errors.h b/src/core/hle/service/glue/errors.h
new file mode 100644
index 000000000..c2874c585
--- /dev/null
+++ b/src/core/hle/service/glue/errors.h
@@ -0,0 +1,16 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::Glue {
+
+constexpr ResultCode ERR_INVALID_RESOURCE{ErrorModule::ARP, 0x1E};
+constexpr ResultCode ERR_INVALID_PROCESS_ID{ErrorModule::ARP, 0x1F};
+constexpr ResultCode ERR_INVALID_ACCESS{ErrorModule::ARP, 0x2A};
+constexpr ResultCode ERR_NOT_REGISTERED{ErrorModule::ARP, 0x66};
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp
new file mode 100644
index 000000000..c728e815c
--- /dev/null
+++ b/src/core/hle/service/glue/glue.cpp
@@ -0,0 +1,25 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+#include "core/core.h"
+#include "core/hle/service/glue/arp.h"
+#include "core/hle/service/glue/bgtc.h"
+#include "core/hle/service/glue/glue.h"
+
+namespace Service::Glue {
+
+void InstallInterfaces(Core::System& system) {
+ // ARP
+ std::make_shared<ARP_R>(system, system.GetARPManager())
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<ARP_W>(system, system.GetARPManager())
+ ->InstallAsService(system.ServiceManager());
+
+ // BackGround Task Controller
+ std::make_shared<BGTC_T>()->InstallAsService(system.ServiceManager());
+ std::make_shared<BGTC_SC>()->InstallAsService(system.ServiceManager());
+}
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/glue.h b/src/core/hle/service/glue/glue.h
new file mode 100644
index 000000000..112cd238b
--- /dev/null
+++ b/src/core/hle/service/glue/glue.h
@@ -0,0 +1,16 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Service::Glue {
+
+/// Registers all Glue services with the specified service manager.
+void InstallInterfaces(Core::System& system);
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/manager.cpp b/src/core/hle/service/glue/manager.cpp
new file mode 100644
index 000000000..6da52d2d6
--- /dev/null
+++ b/src/core/hle/service/glue/manager.cpp
@@ -0,0 +1,78 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/glue/errors.h"
+#include "core/hle/service/glue/manager.h"
+
+namespace Service::Glue {
+
+struct ARPManager::MapEntry {
+ ApplicationLaunchProperty launch;
+ std::vector<u8> control;
+};
+
+ARPManager::ARPManager() = default;
+
+ARPManager::~ARPManager() = default;
+
+ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
+ if (title_id == 0) {
+ return ERR_INVALID_PROCESS_ID;
+ }
+
+ const auto iter = entries.find(title_id);
+ if (iter == entries.end()) {
+ return ERR_NOT_REGISTERED;
+ }
+
+ return MakeResult<ApplicationLaunchProperty>(iter->second.launch);
+}
+
+ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
+ if (title_id == 0) {
+ return ERR_INVALID_PROCESS_ID;
+ }
+
+ const auto iter = entries.find(title_id);
+ if (iter == entries.end()) {
+ return ERR_NOT_REGISTERED;
+ }
+
+ return MakeResult<std::vector<u8>>(iter->second.control);
+}
+
+ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
+ std::vector<u8> control) {
+ if (title_id == 0) {
+ return ERR_INVALID_PROCESS_ID;
+ }
+
+ const auto iter = entries.find(title_id);
+ if (iter != entries.end()) {
+ return ERR_INVALID_ACCESS;
+ }
+
+ entries.insert_or_assign(title_id, MapEntry{launch, std::move(control)});
+ return RESULT_SUCCESS;
+}
+
+ResultCode ARPManager::Unregister(u64 title_id) {
+ if (title_id == 0) {
+ return ERR_INVALID_PROCESS_ID;
+ }
+
+ const auto iter = entries.find(title_id);
+ if (iter == entries.end()) {
+ return ERR_NOT_REGISTERED;
+ }
+
+ entries.erase(iter);
+ return RESULT_SUCCESS;
+}
+
+void ARPManager::ResetAll() {
+ entries.clear();
+}
+
+} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/manager.h b/src/core/hle/service/glue/manager.h
new file mode 100644
index 000000000..a7f5ce3ee
--- /dev/null
+++ b/src/core/hle/service/glue/manager.h
@@ -0,0 +1,63 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+#include <vector>
+#include "common/common_types.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/romfs_factory.h"
+#include "core/hle/result.h"
+
+namespace Service::Glue {
+
+struct ApplicationLaunchProperty {
+ u64 title_id;
+ u32 version;
+ FileSys::StorageId base_game_storage_id;
+ FileSys::StorageId update_storage_id;
+ u8 program_index;
+ u8 reserved;
+};
+static_assert(sizeof(ApplicationLaunchProperty) == 0x10,
+ "ApplicationLaunchProperty has incorrect size.");
+
+// A class to manage state related to the arp:w and arp:r services, specifically the registration
+// and unregistration of launch and control properties.
+class ARPManager {
+public:
+ ARPManager();
+ ~ARPManager();
+
+ // Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
+ // previously registered, otherwise ERR_NOT_REGISTERED if it was never registered or
+ // ERR_INVALID_PROCESS_ID if the title ID is 0.
+ ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
+
+ // Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
+ // the provided title ID if it was previously registered, otherwise ERR_NOT_REGISTERED if it was
+ // never registered or ERR_INVALID_PROCESS_ID if the title ID is 0.
+ ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
+
+ // Adds a new entry to the internal database with the provided parameters, returning
+ // ERR_INVALID_ACCESS if attempting to re-register a title ID without an intermediate Unregister
+ // step, and ERR_INVALID_PROCESS_ID if the title ID is 0.
+ ResultCode Register(u64 title_id, ApplicationLaunchProperty launch, std::vector<u8> control);
+
+ // Removes the registration for the provided title ID from the database, returning
+ // ERR_NOT_REGISTERED if it doesn't exist in the database and ERR_INVALID_PROCESS_ID if the
+ // title ID is 0.
+ ResultCode Unregister(u64 title_id);
+
+ // Removes all entries from the database, always succeeds. Should only be used when resetting
+ // system state.
+ void ResetAll();
+
+private:
+ struct MapEntry;
+ std::map<u64, MapEntry> entries;
+};
+
+} // namespace Service::Glue
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 @@
namespace Service::HID {
-ControllerBase::ControllerBase() = default;
+ControllerBase::ControllerBase(Core::System& system) : system(system) {}
ControllerBase::~ControllerBase() = default;
void 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 {
class CoreTiming;
}
+namespace Core {
+class System;
+}
+
namespace Service::HID {
class ControllerBase {
public:
- ControllerBase();
+ explicit ControllerBase(Core::System& system);
virtual ~ControllerBase();
// Called when the controller is initialized
@@ -46,5 +50,7 @@ protected:
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
+
+ Core::System& system;
};
} // 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;
constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
-Controller_DebugPad::Controller_DebugPad() = default;
+Controller_DebugPad::Controller_DebugPad(Core::System& system)
+ : ControllerBase(system), system(system) {}
Controller_DebugPad::~Controller_DebugPad() = default;
void Controller_DebugPad::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 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 @@
namespace Service::HID {
class Controller_DebugPad final : public ControllerBase {
public:
- Controller_DebugPad();
+ explicit Controller_DebugPad(Core::System& system);
~Controller_DebugPad() override;
// Called when the controller is initialized
@@ -89,5 +89,6 @@ private:
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
analogs;
+ Core::System& system;
};
} // 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
-Controller_Gesture::Controller_Gesture() = default;
+Controller_Gesture::Controller_Gesture(Core::System& system)
+ : ControllerBase(system), system(system) {}
Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 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 @@
namespace Service::HID {
class Controller_Gesture final : public ControllerBase {
public:
- Controller_Gesture();
+ explicit Controller_Gesture(Core::System& system);
~Controller_Gesture() override;
// Called when the controller is initialized
@@ -59,5 +59,6 @@ private:
std::array<GestureState, 17> gesture_states;
};
SharedMemory shared_memory{};
+ Core::System& system;
};
} // 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 {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
constexpr u8 KEYS_PER_BYTE = 8;
-Controller_Keyboard::Controller_Keyboard() = default;
+Controller_Keyboard::Controller_Keyboard(Core::System& system)
+ : ControllerBase(system), system(system) {}
Controller_Keyboard::~Controller_Keyboard() = default;
void Controller_Keyboard::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 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 @@
namespace Service::HID {
class Controller_Keyboard final : public ControllerBase {
public:
- Controller_Keyboard();
+ explicit Controller_Keyboard(Core::System& system);
~Controller_Keyboard() override;
// Called when the controller is initialized
@@ -53,5 +53,6 @@ private:
keyboard_keys;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
keyboard_mods;
+ Core::System& system;
};
} // 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
-Controller_Mouse::Controller_Mouse() = default;
+Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system), system(system) {}
Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 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 @@
namespace Service::HID {
class Controller_Mouse final : public ControllerBase {
public:
- Controller_Mouse();
+ explicit Controller_Mouse(Core::System& system);
~Controller_Mouse() override;
// Called when the controller is initialized
@@ -53,5 +53,6 @@ private:
std::unique_ptr<Input::MouseDevice> mouse_device;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
mouse_button_devices;
+ Core::System& system;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index fdd6d79a2..44b668fbf 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) {
};
}
-Controller_NPad::Controller_NPad() = default;
+Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_NPad::~Controller_NPad() = default;
void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
@@ -168,9 +168,11 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
}
void Controller_NPad::OnInit() {
- auto& kernel = Core::System::GetInstance().Kernel();
- styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
- kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged");
+ auto& kernel = system.Kernel();
+ for (std::size_t i = 0; i < styleset_changed_events.size(); i++) {
+ styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Automatic, fmt::format("npad:NpadStyleSetChanged_{}", i));
+ }
if (!IsControllerActivated()) {
return;
@@ -453,7 +455,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
had_controller_update = true;
}
if (had_controller_update) {
- styleset_changed_event.writable->Signal();
+ styleset_changed_events[i].writable->Signal();
}
}
}
@@ -468,7 +470,6 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
}
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
- styleset_changed_event.writable->Signal();
hold_type = joy_hold_type;
}
@@ -479,7 +480,10 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
const std::size_t npad_index = NPadIdToIndex(npad_id);
ASSERT(npad_index < shared_memory_entries.size());
- shared_memory_entries[npad_index].pad_assignment = assignment_mode;
+ if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
+ styleset_changed_events[npad_index].writable->Signal();
+ shared_memory_entries[npad_index].pad_assignment = assignment_mode;
+ }
}
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
@@ -498,11 +502,13 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
last_processed_vibration = vibrations.back();
}
-Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
+Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
+ u32 npad_id) const {
// TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
// be signalled at least once, and signaled after a new controller is connected?
- styleset_changed_event.writable->Signal();
- return styleset_changed_event.readable;
+ const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
+ styleset_event.writable->Signal();
+ return styleset_event.readable;
}
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
@@ -548,6 +554,37 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
}
+void Controller_NPad::StartLRAssignmentMode() {
+ // Nothing internally is used for lr assignment mode. Since we have the ability to set the
+ // controller types from boot, it doesn't really matter about showing a selection screen
+ is_in_lr_assignment_mode = true;
+}
+
+void Controller_NPad::StopLRAssignmentMode() {
+ is_in_lr_assignment_mode = false;
+}
+
+bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
+ if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
+ npad_id_2 == NPAD_UNKNOWN) {
+ return true;
+ }
+ const auto npad_index_1 = NPadIdToIndex(npad_id_1);
+ const auto npad_index_2 = NPadIdToIndex(npad_id_2);
+
+ if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
+ !IsControllerSupported(connected_controllers[npad_index_2].type)) {
+ return false;
+ }
+
+ std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
+
+ InitNewlyAddedControler(npad_index_1);
+ InitNewlyAddedControler(npad_index_2);
+
+ return true;
+}
+
bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
if (controller == NPadControllerType::Handheld) {
// Handheld is not even a supported type, lets stop here
@@ -605,10 +642,15 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
return LedPattern{0, 0, 0, 0};
};
}
+
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
can_controllers_vibrate = can_vibrate;
}
+bool Controller_NPad::IsVibrationEnabled() const {
+ return can_controllers_vibrate;
+}
+
void Controller_NPad::ClearAllConnectedControllers() {
for (auto& controller : connected_controllers) {
if (controller.is_connected && controller.type != NPadControllerType::None) {
@@ -617,6 +659,7 @@ void Controller_NPad::ClearAllConnectedControllers() {
}
}
}
+
void Controller_NPad::DisconnectAllConnectedControllers() {
std::for_each(connected_controllers.begin(), connected_controllers.end(),
[](ControllerHolder& controller) { controller.is_connected = false; });
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 4ff50b3cd..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?
class Controller_NPad final : public ControllerBase {
public:
- Controller_NPad();
+ explicit Controller_NPad(Core::System& system);
~Controller_NPad() override;
// Called when the controller is initialized
@@ -109,7 +109,7 @@ public:
void VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations);
- Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
@@ -119,11 +119,16 @@ public:
void DisconnectNPad(u32 npad_id);
LedPattern GetLedPattern(u32 npad_id);
void SetVibrationEnabled(bool can_vibrate);
+ bool IsVibrationEnabled() const;
void ClearAllConnectedControllers();
void DisconnectAllConnectedControllers();
void ConnectAllDisconnectedControllers();
void ClearAllControllers();
+ void StartLRAssignmentMode();
+ void StopLRAssignmentMode();
+ bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
+
// Logical OR for all buttons presses on all controllers
// Specifically for cheat engine and other features.
u32 GetAndResetPressState();
@@ -310,7 +315,8 @@ private:
sticks;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
- Kernel::EventPair styleset_changed_event;
+ // Each controller should have their own styleset changed event
+ std::array<Kernel::EventPair, 10> styleset_changed_events;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
bool can_controllers_vibrate{true};
@@ -321,5 +327,7 @@ private:
void RequestPadStateUpdate(u32 npad_id);
std::array<ControllerPad, 10> npad_pad_states{};
bool IsControllerSupported(NPadControllerType controller);
+ bool is_in_lr_assignment_mode{false};
+ Core::System& system;
};
} // 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 @@
namespace Service::HID {
-Controller_Stubbed::Controller_Stubbed() = default;
+Controller_Stubbed::Controller_Stubbed(Core::System& system)
+ : ControllerBase(system), system(system) {}
Controller_Stubbed::~Controller_Stubbed() = default;
void Controller_Stubbed::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 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 @@
namespace Service::HID {
class Controller_Stubbed final : public ControllerBase {
public:
- Controller_Stubbed();
+ explicit Controller_Stubbed(Core::System& system);
~Controller_Stubbed() override;
// Called when the controller is initialized
@@ -30,5 +30,6 @@ public:
private:
bool smart_update{};
std::size_t common_offset{};
+ Core::System& system;
};
} // 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
-Controller_Touchscreen::Controller_Touchscreen() = default;
+Controller_Touchscreen::Controller_Touchscreen(Core::System& system)
+ : ControllerBase(system), system(system) {}
Controller_Touchscreen::~Controller_Touchscreen() = default;
void Controller_Touchscreen::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 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 @@
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
- Controller_Touchscreen();
+ explicit Controller_Touchscreen(Core::System& system);
~Controller_Touchscreen() override;
// Called when the controller is initialized
@@ -69,5 +69,6 @@ private:
TouchScreenSharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_device;
s64_le last_touch{};
+ Core::System& system;
};
} // 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
-Controller_XPad::Controller_XPad() = default;
+Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system), system(system) {}
Controller_XPad::~Controller_XPad() = default;
void Controller_XPad::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index 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 @@
namespace Service::HID {
class Controller_XPad final : public ControllerBase {
public:
- Controller_XPad();
+ explicit Controller_XPad(Core::System& system);
~Controller_XPad() override;
// Called when the controller is initialized
@@ -56,5 +56,6 @@ private:
};
static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
+ Core::System& system;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
new file mode 100644
index 000000000..3583642e7
--- /dev/null
+++ b/src/core/hle/service/hid/errors.h
@@ -0,0 +1,13 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::HID {
+
+constexpr ResultCode ERR_NPAD_NOT_CONNECTED{ErrorModule::HID, 710};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a4ad95d96..8d76ba746 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -16,6 +16,7 @@
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
@@ -41,13 +42,14 @@ constexpr s64 accelerometer_update_ticks = static_cast<s64>(Core::Timing::BASE_C
constexpr s64 gyroscope_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
-IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
+IAppletResource::IAppletResource(Core::System& system)
+ : ServiceFramework("IAppletResource"), system(system) {
static const FunctionInfo functions[] = {
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
shared_mem = Kernel::SharedMemory::Create(
kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
@@ -73,7 +75,7 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
// Register update callbacks
- auto& core_timing = Core::System::GetInstance().CoreTiming();
+ auto& core_timing = system.CoreTiming();
pad_update_event =
core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
UpdateControllers(userdata, cycles_late);
@@ -95,7 +97,7 @@ void IAppletResource::DeactivateController(HidController controller) {
}
IAppletResource ::~IAppletResource() {
- Core::System::GetInstance().CoreTiming().UnscheduleEvent(pad_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
}
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
@@ -107,7 +109,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
}
void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) {
- auto& core_timing = Core::System::GetInstance().CoreTiming();
+ auto& core_timing = system.CoreTiming();
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
for (const auto& controller : controllers) {
@@ -140,13 +142,13 @@ private:
std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
if (applet_resource == nullptr) {
- applet_resource = std::make_shared<IAppletResource>();
+ applet_resource = std::make_shared<IAppletResource>(system);
}
return applet_resource;
}
-Hid::Hid() : ServiceFramework("hid") {
+Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -202,11 +204,11 @@ Hid::Hid() : ServiceFramework("hid") {
{123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
{124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
{125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
- {126, nullptr, "StartLrAssignmentMode"},
- {127, nullptr, "StopLrAssignmentMode"},
+ {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
+ {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
{129, nullptr, "GetNpadHandheldActivationMode"},
- {130, nullptr, "SwapNpadAssignment"},
+ {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
@@ -215,8 +217,8 @@ Hid::Hid() : ServiceFramework("hid") {
{201, &Hid::SendVibrationValue, "SendVibrationValue"},
{202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
{203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
- {204, nullptr, "PermitVibration"},
- {205, nullptr, "IsVibrationPermitted"},
+ {204, &Hid::PermitVibration, "PermitVibration"},
+ {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"},
{206, &Hid::SendVibrationValues, "SendVibrationValues"},
{207, nullptr, "SendVibrationGcErmCommand"},
{208, nullptr, "GetActualVibrationGcErmCommand"},
@@ -285,7 +287,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
if (applet_resource == nullptr) {
- applet_resource = std::make_shared<IAppletResource>();
+ applet_resource = std::make_shared<IAppletResource>(system);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -478,7 +480,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetStyleSetChangedEvent());
+ .GetStyleSetChangedEvent(npad_id));
}
void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
@@ -678,6 +680,27 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IActiveVibrationDeviceList>();
}
+void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto can_vibrate{rp.Pop<bool>()};
+ applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .SetVibrationEnabled(can_vibrate);
+
+ LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(
+ applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled());
+}
+
void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -733,6 +756,49 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
+void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+ controller.StartLRAssignmentMode();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+ controller.StopLRAssignmentMode();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_1{rp.Pop<u32>()};
+ const auto npad_2{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}",
+ applet_resource_user_id, npad_1, npad_2);
+
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+ IPC::ResponseBuilder rb{ctx, 2};
+ if (controller.SwapNpadAssignment(npad_1, npad_2)) {
+ rb.Push(RESULT_SUCCESS);
+ } else {
+ LOG_ERROR(Service_HID, "Npads are not connected!");
+ rb.Push(ERR_NPAD_NOT_CONNECTED);
+ }
+}
+
class HidDbg final : public ServiceFramework<HidDbg> {
public:
explicit HidDbg() : ServiceFramework{"hid:dbg"} {
@@ -988,14 +1054,14 @@ void ReloadInputDevices() {
Settings::values.is_device_reload_pending.store(true);
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<Hid>()->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<Hid>(system)->InstallAsService(service_manager);
std::make_shared<HidBus>()->InstallAsService(service_manager);
std::make_shared<HidDbg>()->InstallAsService(service_manager);
std::make_shared<HidSys>()->InstallAsService(service_manager);
std::make_shared<HidTmp>()->InstallAsService(service_manager);
- std::make_shared<IRS>()->InstallAsService(service_manager);
+ std::make_shared<IRS>(system)->InstallAsService(service_manager);
std::make_shared<IRS_SYS>()->InstallAsService(service_manager);
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 d3660cad2..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 {
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
- IAppletResource();
+ explicit IAppletResource(Core::System& system);
~IAppletResource() override;
void ActivateController(HidController controller);
@@ -61,7 +61,7 @@ public:
private:
template <typename T>
void MakeController(HidController controller) {
- controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
+ controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
}
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
@@ -70,6 +70,7 @@ private:
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
Core::Timing::EventType* pad_update_event;
+ Core::System& system;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
controllers{};
@@ -77,7 +78,7 @@ private:
class Hid final : public ServiceFramework<Hid> {
public:
- Hid();
+ explicit Hid(Core::System& system);
~Hid() override;
std::shared_ptr<IAppletResource> GetAppletResource();
@@ -114,19 +115,25 @@ private:
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
+ void PermitVibration(Kernel::HLERequestContext& ctx);
+ void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
+ void StartLrAssignmentMode(Kernel::HLERequestContext& ctx);
+ void StopLrAssignmentMode(Kernel::HLERequestContext& ctx);
+ void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
std::shared_ptr<IAppletResource> applet_resource;
+ Core::System& system;
};
/// Reload input devices. Used when input configuration changed
void ReloadInputDevices();
/// Registers all HID services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // 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 @@
namespace Service::HID {
-IRS::IRS() : ServiceFramework{"irs"} {
+IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
@@ -37,7 +37,7 @@ IRS::IRS() : ServiceFramework{"irs"} {
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
shared_mem = Kernel::SharedMemory::Create(
kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
@@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
- rb.PushRaw<u64>(Core::System::GetInstance().CoreTiming().GetTicks());
+ rb.PushRaw<u64>(system.CoreTiming().GetTicks());
rb.PushRaw<u32>(0);
}
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 {
class IRS final : public ServiceFramework<IRS> {
public:
- explicit IRS();
+ explicit IRS(Core::System& system);
~IRS() override;
private:
@@ -39,6 +39,7 @@ private:
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
const u32 device_handle{0xABCD};
+ Core::System& system;
};
class 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 5af925515..3164ca26e 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -78,7 +78,7 @@ public:
class RelocatableObject final : public ServiceFramework<RelocatableObject> {
public:
- explicit RelocatableObject() : ServiceFramework{"ldr:ro"} {
+ explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &RelocatableObject::LoadNro, "LoadNro"},
@@ -310,7 +310,7 @@ public:
if (!IsValidNROHash(hash)) {
LOG_ERROR(Service_LDR,
"NRO hash is not present in any currently loaded NRRs (hash={})!",
- Common::HexArrayToString(hash));
+ Common::HexToString(hash));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_MISSING_NRR_HASH);
return;
@@ -345,14 +345,16 @@ public:
vm_manager
.MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode)
.IsSuccess());
- ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
+ ASSERT(vm_manager.ReprotectRange(nro_address, nro_size, Kernel::VMAPermission::None)
+ .IsSuccess());
if (bss_size > 0) {
ASSERT(vm_manager
.MirrorMemory(*map_address + nro_size, bss_address, bss_size,
Kernel::MemoryState::ModuleCode)
.IsSuccess());
- ASSERT(vm_manager.UnmapRange(bss_address, bss_size).IsSuccess());
+ ASSERT(vm_manager.ReprotectRange(bss_address, bss_size, Kernel::VMAPermission::None)
+ .IsSuccess());
}
vm_manager.ReprotectRange(*map_address, header.text_size,
@@ -362,9 +364,10 @@ public:
vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
Kernel::VMAPermission::ReadWrite);
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ system.InvalidateCpuInstructionCaches();
- nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
+ nro.insert_or_assign(*map_address,
+ NROInfo{hash, nro_address, nro_size, bss_address, bss_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -409,11 +412,25 @@ public:
}
auto& vm_manager = Core::CurrentProcess()->VMManager();
- const auto& nro_size = iter->second.size;
+ const auto& nro_info = iter->second;
- ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess());
+ // Unmap the mirrored memory
+ ASSERT(
+ vm_manager.UnmapRange(nro_address, nro_info.nro_size + nro_info.bss_size).IsSuccess());
+
+ // Reprotect the source memory
+ ASSERT(vm_manager
+ .ReprotectRange(nro_info.nro_address, nro_info.nro_size,
+ Kernel::VMAPermission::ReadWrite)
+ .IsSuccess());
+ if (nro_info.bss_size > 0) {
+ ASSERT(vm_manager
+ .ReprotectRange(nro_info.bss_address, nro_info.bss_size,
+ Kernel::VMAPermission::ReadWrite)
+ .IsSuccess());
+ }
- Core::System::GetInstance().InvalidateCpuInstructionCaches();
+ system.InvalidateCpuInstructionCaches();
nro.erase(iter);
IPC::ResponseBuilder rb{ctx, 2};
@@ -473,7 +490,10 @@ private:
struct NROInfo {
SHA256Hash hash;
- u64 size;
+ VAddr nro_address;
+ u64 nro_size;
+ VAddr bss_address;
+ u64 bss_size;
};
bool initialized = false;
@@ -496,13 +516,14 @@ private:
Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
Common::Is4KBAligned(header.rw_size);
}
+ Core::System& system;
};
-void InstallInterfaces(SM::ServiceManager& sm) {
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<DebugMonitor>()->InstallAsService(sm);
std::make_shared<ProcessManager>()->InstallAsService(sm);
std::make_shared<Shell>()->InstallAsService(sm);
- std::make_shared<RelocatableObject>()->InstallAsService(sm);
+ std::make_shared<RelocatableObject>(system)->InstallAsService(sm);
}
} // 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;
namespace Service::LDR {
/// Registers all LDR services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm);
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::LDR
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index ce84e25ed..0b3923ad9 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -48,7 +48,7 @@ public:
{19, nullptr, "Export"},
{20, nullptr, "IsBrokenDatabaseWithClearFlag"},
{21, &IDatabaseService::GetIndex, "GetIndex"},
- {22, nullptr, "SetInterfaceVersion"},
+ {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
{23, nullptr, "Convert"},
};
// clang-format on
@@ -350,8 +350,22 @@ private:
rb.Push(index);
}
+ void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ current_interface_version = rp.PopRaw<u32>();
+
+ LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
+
+ UNIMPLEMENTED_IF(current_interface_version != 1);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
MiiManager db;
+ u32 current_interface_version = 0;
+
// Last read offsets of Get functions
std::array<u32, 4> offsets{};
};
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 131b01d62..8d0353075 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -175,6 +175,10 @@ MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) {
} // namespace
std::ostream& operator<<(std::ostream& os, Source source) {
+ if (static_cast<std::size_t>(source) >= SOURCE_NAMES.size()) {
+ return os << "[UNKNOWN SOURCE]";
+ }
+
os << SOURCE_NAMES.at(static_cast<std::size_t>(source));
return os;
}
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,
constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
} // namespace ErrCodes
-Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {
- auto& kernel = Core::System::GetInstance().Kernel();
+Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
+ : ServiceFramework(name), module(std::move(module)), system(system) {
+ auto& kernel = system.Kernel();
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IUser:NFCTagDetected");
}
@@ -34,8 +34,8 @@ Module::Interface::~Interface() = default;
class IUser final : public ServiceFramework<IUser> {
public:
- IUser(Module::Interface& nfp_interface)
- : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) {
+ IUser(Module::Interface& nfp_interface, Core::System& system)
+ : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface), system(system) {
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, &IUser::Finalize, "Finalize"},
@@ -65,7 +65,7 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
deactivate_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent");
availability_change_event = Kernel::WritableEvent::CreateEventPair(
@@ -324,6 +324,7 @@ private:
Kernel::EventPair deactivate_event;
Kernel::EventPair availability_change_event;
const Module::Interface& nfp_interface;
+ Core::System& system;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -331,7 +332,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IUser>(*this);
+ rb.PushIpcInterface<IUser>(*this, system);
}
bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
@@ -353,9 +354,9 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const
return amiibo;
}
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
- std::make_shared<NFP_User>(module)->InstallAsService(service_manager);
+ std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
}
} // 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 {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(std::shared_ptr<Module> module, const char* name);
+ explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
~Interface() override;
struct ModelInfo {
@@ -43,9 +43,10 @@ public:
protected:
std::shared_ptr<Module> module;
+ Core::System& system;
};
};
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // 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 @@
namespace Service::NFP {
-NFP_User::NFP_User(std::shared_ptr<Module> module)
- : Module::Interface(std::move(module), "nfp:user") {
+NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system)
+ : Module::Interface(std::move(module), system, "nfp:user") {
static const FunctionInfo functions[] = {
{0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
};
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 {
class NFP_User final : public Module::Interface {
public:
- explicit NFP_User(std::shared_ptr<Module> module);
+ explicit NFP_User(std::shared_ptr<Module> module, Core::System& system);
~NFP_User() override;
};
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 76b12b482..24d1813a7 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -31,7 +31,7 @@ public:
class IRequest final : public ServiceFramework<IRequest> {
public:
- explicit IRequest() : ServiceFramework("IRequest") {
+ explicit IRequest(Core::System& system) : ServiceFramework("IRequest") {
static const FunctionInfo functions[] = {
{0, &IRequest::GetRequestState, "GetRequestState"},
{1, &IRequest::GetResult, "GetResult"},
@@ -61,7 +61,7 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
"IRequest:Event1");
event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
@@ -130,7 +130,7 @@ public:
class IGeneralService final : public ServiceFramework<IGeneralService> {
public:
- IGeneralService();
+ IGeneralService(Core::System& system);
private:
void GetClientId(Kernel::HLERequestContext& ctx) {
@@ -155,7 +155,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IRequest>();
+ rb.PushIpcInterface<IRequest>(system);
}
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -198,9 +198,11 @@ private:
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
+ Core::System& system;
};
-IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
+IGeneralService::IGeneralService(Core::System& system)
+ : ServiceFramework("IGeneralService"), system(system) {
static const FunctionInfo functions[] = {
{1, &IGeneralService::GetClientId, "GetClientId"},
{2, &IGeneralService::CreateScanRequest, "CreateScanRequest"},
@@ -245,7 +247,8 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") {
class NetworkInterface final : public ServiceFramework<NetworkInterface> {
public:
- explicit NetworkInterface(const char* name) : ServiceFramework{name} {
+ explicit NetworkInterface(const char* name, Core::System& system)
+ : ServiceFramework{name}, system(system) {
static const FunctionInfo functions[] = {
{4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
{5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
@@ -258,7 +261,7 @@ public:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IGeneralService>();
+ rb.PushIpcInterface<IGeneralService>(system);
}
void CreateGeneralService(Kernel::HLERequestContext& ctx) {
@@ -266,14 +269,17 @@ public:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IGeneralService>();
+ rb.PushIpcInterface<IGeneralService>(system);
}
+
+private:
+ Core::System& system;
};
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<NetworkInterface>("nifm:a")->InstallAsService(service_manager);
- std::make_shared<NetworkInterface>("nifm:s")->InstallAsService(service_manager);
- std::make_shared<NetworkInterface>("nifm:u")->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
+ std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
+ std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
}
} // 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 {
class ServiceManager;
}
+namespace Core {
+class System;
+}
+
namespace Service::NIFM {
/// Registers all NIFM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // 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:
class IEnsureNetworkClockAvailabilityService final
: public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
public:
- IEnsureNetworkClockAvailabilityService()
+ explicit IEnsureNetworkClockAvailabilityService(Core::System& system)
: ServiceFramework("IEnsureNetworkClockAvailabilityService") {
static const FunctionInfo functions[] = {
{0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
@@ -139,7 +139,7 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
finished_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::Automatic,
"IEnsureNetworkClockAvailabilityService:FinishEvent");
@@ -200,7 +200,7 @@ private:
class NTC final : public ServiceFramework<NTC> {
public:
- explicit NTC() : ServiceFramework{"ntc"} {
+ explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
@@ -218,7 +218,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
+ rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system);
}
// TODO(ogniK): Do we need these?
@@ -235,13 +235,14 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+ Core::System& system;
};
-void InstallInterfaces(SM::ServiceManager& sm) {
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<NIM>()->InstallAsService(sm);
std::make_shared<NIM_ECA>()->InstallAsService(sm);
std::make_shared<NIM_SHP>()->InstallAsService(sm);
- std::make_shared<NTC>()->InstallAsService(sm);
+ std::make_shared<NTC>(system)->InstallAsService(sm);
}
} // 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 {
class ServiceManager;
}
+namespace Core {
+class System;
+}
+
namespace Service::NIM {
-void InstallInterfaces(SM::ServiceManager& sm);
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::NIM
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index ce88a2941..15c156ce1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -617,7 +617,8 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+
std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
@@ -628,7 +629,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<NS_SU>()->InstallAsService(service_manager);
std::make_shared<NS_VM>()->InstallAsService(service_manager);
- std::make_shared<PL_U>()->InstallAsService(service_manager);
+ std::make_shared<PL_U>(system)->InstallAsService(service_manager);
}
} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 0e8256cb4..13a64ad88 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -6,7 +6,13 @@
#include "core/hle/service/service.h"
-namespace Service::NS {
+namespace Service {
+
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
+namespace NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
@@ -91,6 +97,7 @@ private:
};
/// Registers all NS services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
-} // namespace Service::NS
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index ad176f89d..7dcdb4a07 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -77,7 +77,7 @@ enum class LoadState : u32 {
Done = 1,
};
-static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output,
+static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output,
std::size_t& offset) {
ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE,
"Shared fonts exceeds 17mb!");
@@ -94,7 +94,7 @@ static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& ou
offset += transformed_font.size() * sizeof(u32);
}
-static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& output,
+static void EncryptSharedFont(const std::vector<u8>& input, Kernel::PhysicalMemory& output,
std::size_t& offset) {
ASSERT_MSG(offset + input.size() + 8 < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!");
const u32 KEY = EXPECTED_MAGIC ^ EXPECTED_RESULT;
@@ -121,7 +121,7 @@ struct PL_U::Impl {
return shared_font_regions.at(index);
}
- void BuildSharedFontsRawRegions(const std::vector<u8>& input) {
+ void BuildSharedFontsRawRegions(const Kernel::PhysicalMemory& input) {
// As we can derive the xor key we can just populate the offsets
// based on the shared memory dump
unsigned cur_offset = 0;
@@ -144,13 +144,15 @@ struct PL_U::Impl {
Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
/// Backing memory for the shared font data
- std::shared_ptr<std::vector<u8>> shared_font;
+ std::shared_ptr<Kernel::PhysicalMemory> shared_font;
// Automatically populated based on shared_fonts dump or system archives.
std::vector<FontRegion> shared_font_regions;
};
-PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
+PL_U::PL_U(Core::System& system)
+ : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) {
+
static const FunctionInfo functions[] = {
{0, &PL_U::RequestLoad, "RequestLoad"},
{1, &PL_U::GetLoadState, "GetLoadState"},
@@ -160,13 +162,16 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
{5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
};
RegisterHandlers(functions);
+
+ auto& fsc = system.GetFileSystemController();
+
// Attempt to load shared font data from disk
- const auto* nand = FileSystem::GetSystemNANDContents();
+ const auto* nand = fsc.GetSystemNANDContents();
std::size_t offset = 0;
// Rebuild shared fonts from data ncas
if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
FileSys::ContentRecordType::Data)) {
- impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE);
+ impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(SHARED_FONT_MEM_SIZE);
for (auto font : SHARED_FONTS) {
const auto nca =
nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
@@ -207,7 +212,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
}
} else {
- impl->shared_font = std::make_shared<std::vector<u8>>(
+ impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(
SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size
const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir);
@@ -324,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
Kernel::MemoryState::Shared);
// Create shared font memory object
- auto& kernel = Core::System::GetInstance().Kernel();
+ auto& kernel = system.Kernel();
impl->shared_font_mem = Kernel::SharedMemory::Create(
kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite,
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 253f26a2a..1063f4204 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -7,11 +7,17 @@
#include <memory>
#include "core/hle/service/service.h"
-namespace Service::NS {
+namespace Service {
+
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
+namespace NS {
class PL_U final : public ServiceFramework<PL_U> {
public:
- PL_U();
+ explicit PL_U(Core::System& system);
~PL_U() override;
private:
@@ -24,6 +30,9 @@ private:
struct Impl;
std::unique_ptr<Impl> impl;
+ Core::System& system;
};
-} // namespace Service::NS
+} // namespace NS
+
+} // namespace Service
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 4f6042b00..1b52511a5 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -8,6 +8,12 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/swap.h"
+#include "core/hle/service/nvdrv/nvdata.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
namespace Service::Nvidia::Devices {
@@ -15,7 +21,7 @@ namespace Service::Nvidia::Devices {
/// implement the ioctl interface.
class nvdevice {
public:
- nvdevice() = default;
+ explicit nvdevice(Core::System& system) : system{system} {};
virtual ~nvdevice() = default;
union Ioctl {
u32_le raw;
@@ -33,7 +39,12 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
+ virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) = 0;
+
+protected:
+ Core::System& system;
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 20c7c39aa..f764388bc 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -13,10 +13,13 @@
namespace Service::Nvidia::Devices {
-nvdisp_disp0::nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
+nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
+ : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvdisp_disp0 ::~nvdisp_disp0() = default;
-u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
}
@@ -34,9 +37,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
transform, crop_rect};
- auto& instance = Core::System::GetInstance();
- instance.GetPerfStats().EndGameFrame();
- instance.GPU().SwapBuffers(framebuffer);
+ system.GetPerfStats().EndGameFrame();
+ system.GPU().SwapBuffers(&framebuffer);
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 12f3ef825..6fcdeee84 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -17,10 +17,12 @@ class nvmap;
class nvdisp_disp0 final : public nvdevice {
public:
- explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev);
+ explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvdisp_disp0() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
/// Performs a screen flip, drawing the buffer pointed to by the handle.
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 af62d33d2..6bc053f27 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -22,10 +22,13 @@ enum {
};
}
-nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
+nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
+ : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvhost_as_gpu::~nvhost_as_gpu() = default;
-u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
@@ -65,7 +68,7 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
params.page_size, params.flags);
- auto& gpu = Core::System::GetInstance().GPU();
+ auto& gpu = system.GPU();
const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
if (params.flags & 1) {
params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1);
@@ -85,7 +88,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
std::vector<IoctlRemapEntry> entries(num_entries);
std::memcpy(entries.data(), input.data(), input.size());
- auto& gpu = Core::System::GetInstance().GPU();
+ auto& gpu = system.GPU();
for (const auto& entry : entries) {
LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
entry.offset, entry.nvmap_handle, entry.pages);
@@ -136,7 +139,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
// case to prevent unexpected behavior.
ASSERT(object->id == params.nvmap_handle);
- auto& gpu = Core::System::GetInstance().GPU();
+ auto& gpu = system.GPU();
if (params.flags & 1) {
params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size);
@@ -173,8 +176,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
return 0;
}
- params.offset = Core::System::GetInstance().GPU().MemoryManager().UnmapBuffer(params.offset,
- itr->second.size);
+ params.offset = system.GPU().MemoryManager().UnmapBuffer(params.offset, itr->second.size);
buffer_mappings.erase(itr->second.offset);
std::memcpy(output.data(), &params, output.size());
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 eb14b1da8..169fb8f0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -17,10 +17,12 @@ class nvmap;
class nvhost_as_gpu final : public nvdevice {
public:
- explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev);
+ explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_as_gpu() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
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 b39fb9ef9..ff6b1abae 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -7,14 +7,21 @@
#include "common/assert.h"
#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
+#include "video_core/gpu.h"
namespace Service::Nvidia::Devices {
-nvhost_ctrl::nvhost_ctrl() = default;
+nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface)
+ : nvdevice(system), events_interface{events_interface} {}
nvhost_ctrl::~nvhost_ctrl() = default;
-u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
@@ -22,11 +29,15 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
case IoctlCommand::IocGetConfigCommand:
return NvOsGetConfigU32(input, output);
case IoctlCommand::IocCtrlEventWaitCommand:
- return IocCtrlEventWait(input, output, false);
+ return IocCtrlEventWait(input, output, false, ctrl);
case IoctlCommand::IocCtrlEventWaitAsyncCommand:
- return IocCtrlEventWait(input, output, true);
+ return IocCtrlEventWait(input, output, true, ctrl);
case IoctlCommand::IocCtrlEventRegisterCommand:
return IocCtrlEventRegister(input, output);
+ case IoctlCommand::IocCtrlEventUnregisterCommand:
+ return IocCtrlEventUnregister(input, output);
+ case IoctlCommand::IocCtrlEventSignalCommand:
+ return IocCtrlEventSignal(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -41,23 +52,137 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>&
}
u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
- bool is_async) {
+ bool is_async, IoctlCtrl& ctrl) {
IocCtrlEventWaitParams params{};
std::memcpy(&params, input.data(), sizeof(params));
- LOG_WARNING(Service_NVDRV,
- "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}",
- params.syncpt_id, params.threshold, params.timeout, is_async);
+ LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
+ params.syncpt_id, params.threshold, params.timeout, is_async);
- // TODO(Subv): Implement actual syncpt waiting.
- params.value = 0;
+ if (params.syncpt_id >= MaxSyncPoints) {
+ return NvResult::BadParameter;
+ }
+
+ auto& gpu = system.GPU();
+ // This is mostly to take into account unimplemented features. As synced
+ // gpu is always synced.
+ if (!gpu.IsAsync()) {
+ return NvResult::Success;
+ }
+ auto lock = gpu.LockSync();
+ const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id);
+ const s32 diff = current_syncpoint_value - params.threshold;
+ if (diff >= 0) {
+ params.value = current_syncpoint_value;
+ std::memcpy(output.data(), &params, sizeof(params));
+ return NvResult::Success;
+ }
+ const u32 target_value = current_syncpoint_value - diff;
+
+ if (!is_async) {
+ params.value = 0;
+ }
+
+ if (params.timeout == 0) {
+ std::memcpy(output.data(), &params, sizeof(params));
+ return NvResult::Timeout;
+ }
+
+ u32 event_id;
+ if (is_async) {
+ event_id = params.value & 0x00FF;
+ if (event_id >= MaxNvEvents) {
+ std::memcpy(output.data(), &params, sizeof(params));
+ return NvResult::BadParameter;
+ }
+ } else {
+ if (ctrl.fresh_call) {
+ const auto result = events_interface.GetFreeEvent();
+ if (result) {
+ event_id = *result;
+ } else {
+ LOG_CRITICAL(Service_NVDRV, "No Free Events available!");
+ event_id = params.value & 0x00FF;
+ }
+ } else {
+ event_id = ctrl.event_id;
+ }
+ }
+
+ EventState status = events_interface.status[event_id];
+ if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) {
+ events_interface.SetEventStatus(event_id, EventState::Waiting);
+ events_interface.assigned_syncpt[event_id] = params.syncpt_id;
+ events_interface.assigned_value[event_id] = target_value;
+ if (is_async) {
+ params.value = params.syncpt_id << 4;
+ } else {
+ params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
+ }
+ params.value |= event_id;
+ events_interface.events[event_id].writable->Clear();
+ gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
+ if (!is_async && ctrl.fresh_call) {
+ ctrl.must_delay = true;
+ ctrl.timeout = params.timeout;
+ ctrl.event_id = event_id;
+ return NvResult::Timeout;
+ }
+ std::memcpy(output.data(), &params, sizeof(params));
+ return NvResult::Timeout;
+ }
std::memcpy(output.data(), &params, sizeof(params));
- return 0;
+ return NvResult::BadParameter;
}
u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
- // TODO(bunnei): Implement this.
- return 0;
+ IocCtrlEventRegisterParams params{};
+ std::memcpy(&params, input.data(), sizeof(params));
+ const u32 event_id = params.user_event_id & 0x00FF;
+ LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
+ if (event_id >= MaxNvEvents) {
+ return NvResult::BadParameter;
+ }
+ if (events_interface.registered[event_id]) {
+ return NvResult::BadParameter;
+ }
+ events_interface.RegisterEvent(event_id);
+ return NvResult::Success;
+}
+
+u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) {
+ IocCtrlEventUnregisterParams params{};
+ std::memcpy(&params, input.data(), sizeof(params));
+ const u32 event_id = params.user_event_id & 0x00FF;
+ LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
+ if (event_id >= MaxNvEvents) {
+ return NvResult::BadParameter;
+ }
+ if (!events_interface.registered[event_id]) {
+ return NvResult::BadParameter;
+ }
+ events_interface.UnregisterEvent(event_id);
+ return NvResult::Success;
+}
+
+u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output) {
+ IocCtrlEventSignalParams params{};
+ std::memcpy(&params, input.data(), sizeof(params));
+ // TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization
+ // It is believed from RE to cancel the GPU Event. However, better research is required
+ u32 event_id = params.user_event_id & 0x00FF;
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id);
+ if (event_id >= MaxNvEvents) {
+ return NvResult::BadParameter;
+ }
+ if (events_interface.status[event_id] == EventState::Waiting) {
+ auto& gpu = system.GPU();
+ if (gpu.CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id],
+ events_interface.assigned_value[event_id])) {
+ events_interface.LiberateEvent(event_id);
+ events_interface.events[event_id].writable->Signal();
+ }
+ }
+ return NvResult::Success;
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 6d0de2212..9898623de 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -8,15 +8,18 @@
#include <vector>
#include "common/common_types.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
namespace Service::Nvidia::Devices {
class nvhost_ctrl final : public nvdevice {
public:
- nvhost_ctrl();
+ explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface);
~nvhost_ctrl() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
enum class IoctlCommand : u32_le {
@@ -132,9 +135,16 @@ private:
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
- u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
+ u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async,
+ IoctlCtrl& ctrl);
u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
+
+ u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
+
+ u32 IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output);
+
+ EventInterface& events_interface;
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 0e28755bd..389ace76f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -12,16 +12,18 @@
namespace Service::Nvidia::Devices {
-nvhost_ctrl_gpu::nvhost_ctrl_gpu() = default;
+nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
-u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input,
+ const std::vector<u8>& input2, std::vector<u8>& output,
+ std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::IocGetCharacteristicsCommand:
- return GetCharacteristics(input, output);
+ return GetCharacteristics(input, output, output2, version);
case IoctlCommand::IocGetTPCMasksCommand:
return GetTPCMasks(input, output);
case IoctlCommand::IocGetActiveSlotMaskCommand:
@@ -43,7 +45,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
return 0;
}
-u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
+ std::vector<u8>& output2, IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlCharacteristics params{};
std::memcpy(&params, input.data(), input.size());
@@ -84,7 +87,13 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
params.gc.gr_compbit_store_base_hw = 0x0;
params.gpu_characteristics_buf_size = 0xA0;
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
- std::memcpy(output.data(), &params, output.size());
+
+ if (version == IoctlVersion::Version3) {
+ std::memcpy(output.data(), input.data(), output.size());
+ std::memcpy(output2.data(), &params.gc, output2.size());
+ } else {
+ std::memcpy(output.data(), &params, output.size());
+ }
return 0;
}
@@ -185,7 +194,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o
IoctlGetGpuTime params{};
std::memcpy(&params, input.data(), input.size());
- const auto ns = Core::Timing::CyclesToNs(Core::System::GetInstance().CoreTiming().GetTicks());
+ const auto ns = Core::Timing::CyclesToNs(system.CoreTiming().GetTicks());
params.gpu_time = static_cast<u64_le>(ns.count());
std::memcpy(output.data(), &params, output.size());
return 0;
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 240435eea..642b0a2cb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -13,10 +13,12 @@ namespace Service::Nvidia::Devices {
class nvhost_ctrl_gpu final : public nvdevice {
public:
- nvhost_ctrl_gpu();
+ explicit nvhost_ctrl_gpu(Core::System& system);
~nvhost_ctrl_gpu() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
enum class IoctlCommand : u32_le {
@@ -161,7 +163,8 @@ private:
};
static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
- u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
+ std::vector<u8>& output2, IoctlVersion version);
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
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 8ce7bc7a5..2b8d1bef6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -13,10 +13,13 @@
namespace Service::Nvidia::Devices {
-nvhost_gpu::nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
+nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
+ : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
nvhost_gpu::~nvhost_gpu() = default;
-u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
@@ -48,7 +51,7 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
return SubmitGPFIFO(input, output);
}
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
- return KickoffPB(input, output);
+ return KickoffPB(input, output, input2, version);
}
}
@@ -119,8 +122,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
params.unk3);
- params.fence_out.id = 0;
- params.fence_out.value = 0;
+ auto& gpu = system.GPU();
+ params.fence_out.id = assigned_syncpoints;
+ params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints);
+ assigned_syncpoints++;
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -142,8 +147,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
- LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
- params.address, params.num_entries, params.flags);
+ LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
+ params.num_entries, params.flags.raw);
ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) +
params.num_entries * sizeof(Tegra::CommandListHeader),
@@ -153,31 +158,52 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(Tegra::CommandListHeader));
- Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));
+ UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
+ UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
+
+ auto& gpu = system.GPU();
+ u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id);
+ if (params.flags.increment.Value()) {
+ params.fence_out.value += current_syncpoint_value;
+ } else {
+ params.fence_out.value = current_syncpoint_value;
+ }
+ gpu.PushGPUEntries(std::move(entries));
- params.fence_out.id = 0;
- params.fence_out.value = 0;
std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
return 0;
}
-u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
+ const std::vector<u8>& input2, IoctlVersion version) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
- LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
- params.address, params.num_entries, params.flags);
+ LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
+ params.num_entries, params.flags.raw);
Tegra::CommandList entries(params.num_entries);
- Memory::ReadBlock(params.address, entries.data(),
- params.num_entries * sizeof(Tegra::CommandListHeader));
-
- Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));
+ if (version == IoctlVersion::Version2) {
+ std::memcpy(entries.data(), input2.data(),
+ params.num_entries * sizeof(Tegra::CommandListHeader));
+ } else {
+ Memory::ReadBlock(params.address, entries.data(),
+ params.num_entries * sizeof(Tegra::CommandListHeader));
+ }
+ UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
+ UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
+
+ auto& gpu = system.GPU();
+ u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id);
+ if (params.flags.increment.Value()) {
+ params.fence_out.value += current_syncpoint_value;
+ } else {
+ params.fence_out.value = current_syncpoint_value;
+ }
+ gpu.PushGPUEntries(std::move(entries));
- params.fence_out.id = 0;
- params.fence_out.value = 0;
std::memcpy(output.data(), &params, output.size());
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 62beb5c0c..d056dd046 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
+#include "core/hle/service/nvdrv/nvdata.h"
namespace Service::Nvidia::Devices {
@@ -20,10 +21,12 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice {
public:
- explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev);
+ explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
~nvhost_gpu() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
enum class IoctlCommand : u32_le {
@@ -113,11 +116,7 @@ private:
static_assert(sizeof(IoctlGetErrorNotification) == 16,
"IoctlGetErrorNotification is incorrect size");
- struct IoctlFence {
- u32_le id;
- u32_le value;
- };
- static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size");
+ static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
struct IoctlAllocGpfifoEx {
u32_le num_entries;
@@ -132,13 +131,13 @@ private:
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
struct IoctlAllocGpfifoEx2 {
- u32_le num_entries; // in
- u32_le flags; // in
- u32_le unk0; // in (1 works)
- IoctlFence fence_out; // out
- u32_le unk1; // in
- u32_le unk2; // in
- u32_le unk3; // in
+ u32_le num_entries; // in
+ u32_le flags; // in
+ u32_le unk0; // in (1 works)
+ Fence fence_out; // out
+ u32_le unk1; // in
+ u32_le unk2; // in
+ u32_le unk3; // in
};
static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
@@ -153,10 +152,16 @@ private:
struct IoctlSubmitGpfifo {
u64_le address; // pointer to gpfifo entry structs
u32_le num_entries; // number of fence objects being submitted
- u32_le flags;
- IoctlFence fence_out; // returned new fence object for others to wait on
- };
- static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(IoctlFence),
+ union {
+ u32_le raw;
+ BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
+ BitField<1, 1, u32_le> add_increment; // append an increment to the list
+ BitField<2, 1, u32_le> new_hw_format; // Mostly ignored
+ BitField<8, 1, u32_le> increment; // increment the returned fence
+ } flags;
+ Fence fence_out; // returned new fence object for others to wait on
+ };
+ static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence),
"IoctlSubmitGpfifo is incorrect size");
struct IoctlGetWaitbase {
@@ -179,11 +184,13 @@ private:
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
- u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
+ const std::vector<u8>& input2, IoctlVersion version);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
std::shared_ptr<nvmap> nvmap_dev;
+ u32 assigned_syncpoints{};
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index f5e8ea7c3..bdae8b887 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -10,10 +10,12 @@
namespace Service::Nvidia::Devices {
-nvhost_nvdec::nvhost_nvdec() = default;
+nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {}
nvhost_nvdec::~nvhost_nvdec() = default;
-u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 0e7b284f8..cbdac8069 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -13,10 +13,12 @@ namespace Service::Nvidia::Devices {
class nvhost_nvdec final : public nvdevice {
public:
- nvhost_nvdec();
+ explicit nvhost_nvdec(Core::System& system);
~nvhost_nvdec() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
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 3e0951ab0..96e7b7dab 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -10,10 +10,12 @@
namespace Service::Nvidia::Devices {
-nvhost_nvjpg::nvhost_nvjpg() = default;
+nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
nvhost_nvjpg::~nvhost_nvjpg() = default;
-u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 89fd5e95e..98dcac52f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -13,10 +13,12 @@ namespace Service::Nvidia::Devices {
class nvhost_nvjpg final : public nvdevice {
public:
- nvhost_nvjpg();
+ explicit nvhost_nvjpg(Core::System& system);
~nvhost_nvjpg() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
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 d544f0f31..c695b8863 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -10,10 +10,12 @@
namespace Service::Nvidia::Devices {
-nvhost_vic::nvhost_vic() = default;
+nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
nvhost_vic::~nvhost_vic() = default;
-u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
command.raw, input.size(), output.size());
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index fc24c3f9c..bec32bea1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -13,10 +13,12 @@ namespace Service::Nvidia::Devices {
class nvhost_vic final : public nvdevice {
public:
- nvhost_vic();
+ explicit nvhost_vic(Core::System& system);
~nvhost_vic() override;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
private:
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 1ec796fc6..8c742316c 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -18,7 +18,7 @@ enum {
};
}
-nvmap::nvmap() = default;
+nvmap::nvmap(Core::System& system) : nvdevice(system) {}
nvmap::~nvmap() = default;
VAddr nvmap::GetObjectAddress(u32 handle) const {
@@ -28,7 +28,9 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
return object->addr;
}
-u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::Create:
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 396230c19..73c2e8809 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -16,13 +16,15 @@ namespace Service::Nvidia::Devices {
class nvmap final : public nvdevice {
public:
- nvmap();
+ explicit nvmap(Core::System& system);
~nvmap() override;
/// Returns the allocated address of an nvmap object given its handle.
VAddr GetObjectAddress(u32 handle) const;
- u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+ u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) override;
/// Represents an nvmap object.
struct Object {
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index b60fc748b..5e0c23602 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -8,12 +8,18 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/interface.h"
+#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/nvdrv.h"
namespace Service::Nvidia {
+void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
+ nvdrv->SignalSyncpt(syncpoint_id, value);
+}
+
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NVDRV, "called");
@@ -27,20 +33,75 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0);
}
-void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NVDRV, "called");
-
+void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
IPC::RequestParser rp{ctx};
u32 fd = rp.Pop<u32>();
u32 command = rp.Pop<u32>();
- std::vector<u8> output(ctx.GetWriteBufferSize());
-
+ /// Ioctl 3 has 2 outputs, first in the input params, second is the result
+ std::vector<u8> output(ctx.GetWriteBufferSize(0));
+ std::vector<u8> output2;
+ if (version == IoctlVersion::Version3) {
+ output2.resize((ctx.GetWriteBufferSize(1)));
+ }
+
+ /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer.
+ /// KickOfPB uses this
+ auto input = ctx.ReadBuffer(0);
+
+ std::vector<u8> input2;
+ if (version == IoctlVersion::Version2) {
+ input2 = ctx.ReadBuffer(1);
+ }
+
+ IoctlCtrl ctrl{};
+
+ u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
+
+ if (ctrl.must_delay) {
+ ctrl.fresh_call = false;
+ ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout,
+ [=](Kernel::SharedPtr<Kernel::Thread> thread,
+ Kernel::HLERequestContext& ctx,
+ Kernel::ThreadWakeupReason reason) {
+ IoctlCtrl ctrl2{ctrl};
+ std::vector<u8> tmp_output = output;
+ std::vector<u8> tmp_output2 = output2;
+ u32 result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
+ tmp_output2, ctrl2, version);
+ ctx.WriteBuffer(tmp_output, 0);
+ if (version == IoctlVersion::Version3) {
+ ctx.WriteBuffer(tmp_output2, 1);
+ }
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(result);
+ },
+ nvdrv->GetEventWriteable(ctrl.event_id));
+ } else {
+ ctx.WriteBuffer(output);
+ if (version == IoctlVersion::Version3) {
+ ctx.WriteBuffer(output2, 1);
+ }
+ }
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output));
+ rb.Push(result);
+}
+
+void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NVDRV, "called");
+ IoctlBase(ctx, IoctlVersion::Version1);
+}
- ctx.WriteBuffer(output);
+void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NVDRV, "called");
+ IoctlBase(ctx, IoctlVersion::Version2);
+}
+
+void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NVDRV, "called");
+ IoctlBase(ctx, IoctlVersion::Version3);
}
void NVDRV::Close(Kernel::HLERequestContext& ctx) {
@@ -66,13 +127,19 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u32 fd = rp.Pop<u32>();
- u32 event_id = rp.Pop<u32>();
+ // TODO(Blinkhawk): Figure the meaning of the flag at bit 16
+ u32 event_id = rp.Pop<u32>() & 0x000000FF;
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(query_event.readable);
- rb.Push<u32>(0);
+ if (event_id < MaxNvEvents) {
+ rb.PushCopyObjects(nvdrv->GetEvent(event_id));
+ rb.Push<u32>(NvResult::Success);
+ } else {
+ rb.Push<u32>(0);
+ rb.Push<u32>(NvResult::BadParameter);
+ }
}
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
@@ -122,15 +189,11 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{8, &NVDRV::SetClientPID, "SetClientPID"},
{9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
- {11, &NVDRV::Ioctl, "Ioctl2"},
- {12, nullptr, "Ioctl3"},
+ {11, &NVDRV::Ioctl2, "Ioctl2"},
+ {12, &NVDRV::Ioctl3, "Ioctl3"},
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
};
RegisterHandlers(functions);
-
- auto& kernel = Core::System::GetInstance().Kernel();
- query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
- "NVDRV::query_event");
}
NVDRV::~NVDRV() = default;
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 5b4889910..9269ce00c 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -19,9 +19,13 @@ public:
NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
~NVDRV() override;
+ void SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value);
+
private:
void Open(Kernel::HLERequestContext& ctx);
void Ioctl(Kernel::HLERequestContext& ctx);
+ void Ioctl2(Kernel::HLERequestContext& ctx);
+ void Ioctl3(Kernel::HLERequestContext& ctx);
void Close(Kernel::HLERequestContext& ctx);
void Initialize(Kernel::HLERequestContext& ctx);
void QueryEvent(Kernel::HLERequestContext& ctx);
@@ -29,12 +33,11 @@ private:
void FinishInitialize(Kernel::HLERequestContext& ctx);
void GetStatus(Kernel::HLERequestContext& ctx);
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
+ void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
std::shared_ptr<Module> nvdrv;
u64 pid{};
-
- Kernel::EventPair query_event;
};
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
new file mode 100644
index 000000000..529b03471
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <array>
+#include "common/common_types.h"
+
+namespace Service::Nvidia {
+
+constexpr u32 MaxSyncPoints = 192;
+constexpr u32 MaxNvEvents = 64;
+
+struct Fence {
+ s32 id;
+ u32 value;
+};
+
+static_assert(sizeof(Fence) == 8, "Fence has wrong size");
+
+struct MultiFence {
+ u32 num_fences;
+ std::array<Fence, 4> fences;
+};
+
+enum NvResult : u32 {
+ Success = 0,
+ BadParameter = 4,
+ Timeout = 5,
+ ResourceError = 15,
+};
+
+enum class EventState {
+ Free = 0,
+ Registered = 1,
+ Waiting = 2,
+ Busy = 3,
+};
+
+enum class IoctlVersion : u32 {
+ Version1,
+ Version2,
+ Version3,
+};
+
+struct IoctlCtrl {
+ // First call done to the servioce for services that call itself again after a call.
+ bool fresh_call{true};
+ // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
+ bool must_delay{};
+ // Timeout for the delay
+ s64 timeout{};
+ // NV Event Id
+ s32 event_id{-1};
+};
+
+} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 6e4b8f2c6..307a7e928 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -4,7 +4,10 @@
#include <utility>
+#include <fmt/format.h>
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
@@ -22,8 +25,9 @@
namespace Service::Nvidia {
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) {
- auto module_ = std::make_shared<Module>();
+void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
+ Core::System& system) {
+ auto module_ = std::make_shared<Module>(system);
std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager);
@@ -32,17 +36,25 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
nvflinger.SetNVDrvInstance(module_);
}
-Module::Module() {
- auto nvmap_dev = std::make_shared<Devices::nvmap>();
- devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev);
- devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(nvmap_dev);
- devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>();
+Module::Module(Core::System& system) {
+ auto& kernel = system.Kernel();
+ for (u32 i = 0; i < MaxNvEvents; i++) {
+ std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
+ events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Automatic, event_label);
+ events_interface.status[i] = EventState::Free;
+ events_interface.registered[i] = false;
+ }
+ auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
+ devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev);
+ devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev);
+ devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system);
devices["/dev/nvmap"] = nvmap_dev;
- devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
- devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
- devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
- devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>();
- devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>();
+ devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
+ devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface);
+ devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system);
+ devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
+ devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system);
}
Module::~Module() = default;
@@ -59,12 +71,14 @@ u32 Module::Open(const std::string& device_name) {
return fd;
}
-u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
+u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version) {
auto itr = open_files.find(fd);
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
auto& device = itr->second;
- return device->ioctl({command}, input, output);
+ return device->ioctl({command}, input, input2, output, output2, ctrl, version);
}
ResultCode Module::Close(u32 fd) {
@@ -77,4 +91,22 @@ ResultCode Module::Close(u32 fd) {
return RESULT_SUCCESS;
}
+void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
+ for (u32 i = 0; i < MaxNvEvents; i++) {
+ if (events_interface.assigned_syncpt[i] == syncpoint_id &&
+ events_interface.assigned_value[i] == value) {
+ events_interface.LiberateEvent(i);
+ events_interface.events[i].writable->Signal();
+ }
+ }
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const {
+ return events_interface.events[event_id].readable;
+}
+
+Kernel::SharedPtr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const {
+ return events_interface.events[event_id].writable;
+}
+
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 53564f696..f8bb28969 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -8,8 +8,14 @@
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
+#include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Service::NVFlinger {
class NVFlinger;
}
@@ -20,16 +26,72 @@ namespace Devices {
class nvdevice;
}
-struct IoctlFence {
- u32 id;
- u32 value;
+struct EventInterface {
+ // Mask representing currently busy events
+ u64 events_mask{};
+ // Each kernel event associated to an NV event
+ std::array<Kernel::EventPair, MaxNvEvents> events;
+ // The status of the current NVEvent
+ std::array<EventState, MaxNvEvents> status{};
+ // Tells if an NVEvent is registered or not
+ std::array<bool, MaxNvEvents> registered{};
+ // When an NVEvent is waiting on GPU interrupt, this is the sync_point
+ // associated with it.
+ std::array<u32, MaxNvEvents> assigned_syncpt{};
+ // This is the value of the GPU interrupt for which the NVEvent is waiting
+ // for.
+ std::array<u32, MaxNvEvents> assigned_value{};
+ // Constant to denote an unasigned syncpoint.
+ static constexpr u32 unassigned_syncpt = 0xFFFFFFFF;
+ std::optional<u32> GetFreeEvent() const {
+ u64 mask = events_mask;
+ for (u32 i = 0; i < MaxNvEvents; i++) {
+ const bool is_free = (mask & 0x1) == 0;
+ if (is_free) {
+ if (status[i] == EventState::Registered || status[i] == EventState::Free) {
+ return {i};
+ }
+ }
+ mask = mask >> 1;
+ }
+ return {};
+ }
+ void SetEventStatus(const u32 event_id, EventState new_status) {
+ EventState old_status = status[event_id];
+ if (old_status == new_status) {
+ return;
+ }
+ status[event_id] = new_status;
+ if (new_status == EventState::Registered) {
+ registered[event_id] = true;
+ }
+ if (new_status == EventState::Waiting || new_status == EventState::Busy) {
+ events_mask |= (1ULL << event_id);
+ }
+ }
+ void RegisterEvent(const u32 event_id) {
+ registered[event_id] = true;
+ if (status[event_id] == EventState::Free) {
+ status[event_id] = EventState::Registered;
+ }
+ }
+ void UnregisterEvent(const u32 event_id) {
+ registered[event_id] = false;
+ if (status[event_id] == EventState::Registered) {
+ status[event_id] = EventState::Free;
+ }
+ }
+ void LiberateEvent(const u32 event_id) {
+ status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
+ events_mask &= ~(1ULL << event_id);
+ assigned_syncpt[event_id] = unassigned_syncpt;
+ assigned_value[event_id] = 0;
+ }
};
-static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size");
-
class Module final {
public:
- Module();
+ Module(Core::System& system);
~Module();
/// Returns a pointer to one of the available devices, identified by its name.
@@ -44,10 +106,18 @@ public:
/// Opens a device node and returns a file descriptor to it.
u32 Open(const std::string& device_name);
/// Sends an ioctl command to the specified file descriptor.
- u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output);
+ u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
+ std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
+ IoctlVersion version);
/// Closes a device file descriptor and returns operation success.
ResultCode Close(u32 fd);
+ void SignalSyncpt(const u32 syncpoint_id, const u32 value);
+
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(u32 event_id) const;
+
+ Kernel::SharedPtr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const;
+
private:
/// Id to use for the next open file descriptor.
u32 next_fd = 1;
@@ -57,9 +127,12 @@ private:
/// Mapping of device node names to their implementation.
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
+
+ EventInterface events_interface;
};
/// Registers all NVDRV services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger);
+void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
+ Core::System& system);
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 5731e815f..e1a07d3ee 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -34,7 +34,8 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
buffer_wait_event.writable->Signal();
}
-std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
+std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
+ u32 height) {
auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
// Only consider free buffers. Buffers become free once again after they've been Acquired
// and Released by the compositor, see the NVFlinger::Compose method.
@@ -51,7 +52,7 @@ std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
}
itr->status = Buffer::Status::Dequeued;
- return itr->slot;
+ return {{itr->slot, &itr->multi_fence}};
}
const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
@@ -63,7 +64,8 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
}
void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
- const Common::Rectangle<int>& crop_rect) {
+ const Common::Rectangle<int>& crop_rect, u32 swap_interval,
+ Service::Nvidia::MultiFence& multi_fence) {
auto itr = std::find_if(queue.begin(), queue.end(),
[&](const Buffer& buffer) { return buffer.slot == slot; });
ASSERT(itr != queue.end());
@@ -71,12 +73,21 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
itr->status = Buffer::Status::Queued;
itr->transform = transform;
itr->crop_rect = crop_rect;
+ itr->swap_interval = swap_interval;
+ itr->multi_fence = multi_fence;
+ queue_sequence.push_back(slot);
}
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
- auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
- return buffer.status == Buffer::Status::Queued;
- });
+ auto itr = queue.end();
+ // Iterate to find a queued buffer matching the requested slot.
+ while (itr == queue.end() && !queue_sequence.empty()) {
+ u32 slot = queue_sequence.front();
+ itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
+ return buffer.status == Buffer::Status::Queued && buffer.slot == slot;
+ });
+ queue_sequence.pop_front();
+ }
if (itr == queue.end())
return {};
itr->status = Buffer::Status::Acquired;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index e1ccb6171..356bedb81 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -4,6 +4,7 @@
#pragma once
+#include <list>
#include <optional>
#include <vector>
@@ -12,6 +13,7 @@
#include "common/swap.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/nvdrv/nvdata.h"
namespace Service::NVFlinger {
@@ -68,13 +70,17 @@ public:
IGBPBuffer igbp_buffer;
BufferTransformFlags transform;
Common::Rectangle<int> crop_rect;
+ u32 swap_interval;
+ Service::Nvidia::MultiFence multi_fence;
};
void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
- std::optional<u32> DequeueBuffer(u32 width, u32 height);
+ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> DequeueBuffer(u32 width,
+ u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform,
- const Common::Rectangle<int>& crop_rect);
+ const Common::Rectangle<int>& crop_rect, u32 swap_interval,
+ Service::Nvidia::MultiFence& multi_fence);
std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
void ReleaseBuffer(u32 slot);
u32 Query(QueryType type);
@@ -92,6 +98,7 @@ private:
u64 layer_id;
std::vector<Buffer> queue;
+ std::list<u32> queue_sequence;
Kernel::EventPair buffer_wait_event;
};
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 3c5c53e24..2e4d707b9 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -29,27 +29,28 @@ namespace Service::NVFlinger {
constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
-NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} {
- displays.emplace_back(0, "Default");
- displays.emplace_back(1, "External");
- displays.emplace_back(2, "Edid");
- displays.emplace_back(3, "Internal");
- displays.emplace_back(4, "Null");
+NVFlinger::NVFlinger(Core::System& system) : system(system) {
+ displays.emplace_back(0, "Default", system);
+ displays.emplace_back(1, "External", system);
+ displays.emplace_back(2, "Edid", system);
+ displays.emplace_back(3, "Internal", system);
+ displays.emplace_back(4, "Null", system);
// Schedule the screen composition events
- const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks;
-
- composition_event = core_timing.RegisterEvent(
- "ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) {
+ composition_event = system.CoreTiming().RegisterEvent(
+ "ScreenComposition", [this](u64 userdata, s64 cycles_late) {
Compose();
- this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event);
+ const auto ticks =
+ Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks();
+ this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - cycles_late),
+ composition_event);
});
- core_timing.ScheduleEvent(ticks, composition_event);
+ system.CoreTiming().ScheduleEvent(frame_ticks, composition_event);
}
NVFlinger::~NVFlinger() {
- core_timing.UnscheduleEvent(composition_event, 0);
+ system.CoreTiming().UnscheduleEvent(composition_event, 0);
}
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -186,11 +187,9 @@ void NVFlinger::Compose() {
MicroProfileFlip();
if (!buffer) {
- auto& system_instance = Core::System::GetInstance();
-
// There was no queued buffer to draw, render previous frame
- system_instance.GetPerfStats().EndGameFrame();
- system_instance.GPU().SwapBuffers({});
+ system.GetPerfStats().EndGameFrame();
+ system.GPU().SwapBuffers({});
continue;
}
@@ -206,8 +205,14 @@ void NVFlinger::Compose() {
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
buffer->get().transform, buffer->get().crop_rect);
+ swap_interval = buffer->get().swap_interval;
buffer_queue.ReleaseBuffer(buffer->get().slot);
}
}
+s64 NVFlinger::GetNextTicks() const {
+ constexpr s64 max_hertz = 120LL;
+ return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
+}
+
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index c0a83fffb..5d7e3bfb8 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -38,7 +38,7 @@ class BufferQueue;
class NVFlinger final {
public:
- explicit NVFlinger(Core::Timing::CoreTiming& core_timing);
+ explicit NVFlinger(Core::System& system);
~NVFlinger();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -74,6 +74,8 @@ public:
/// finished.
void Compose();
+ s64 GetNextTicks() const;
+
private:
/// Finds the display identified by the specified ID.
VI::Display* FindDisplay(u64 display_id);
@@ -98,11 +100,12 @@ private:
/// layers.
u32 next_buffer_queue_id = 1;
+ u32 swap_interval = 1;
+
/// Event that handles screen composition.
Core::Timing::EventType* composition_event;
- /// Core timing instance for registering/unregistering the composition event.
- Core::Timing::CoreTiming& core_timing;
+ Core::System& system;
};
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index ebcc41a43..fe6b5f798 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -3,11 +3,44 @@
// Refer to the license.txt file included.
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
namespace Service::PM {
+namespace {
+
+constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
+
+constexpr u64 NO_PROCESS_FOUND_PID{0};
+
+std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList(
+ const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list,
+ std::function<bool(const Kernel::SharedPtr<Kernel::Process>&)> predicate) {
+ const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
+
+ if (iter == process_list.end()) {
+ return std::nullopt;
+ }
+
+ return *iter;
+}
+
+void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
+ const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) {
+ const auto process = SearchProcessList(process_list, [](const auto& process) {
+ return process->GetProcessID() == Kernel::Process::ProcessIDMin;
+ });
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(process.has_value() ? (*process)->GetProcessID() : NO_PROCESS_FOUND_PID);
+}
+
+} // Anonymous namespace
+
class BootMode final : public ServiceFramework<BootMode> {
public:
explicit BootMode() : ServiceFramework{"pm:bm"} {
@@ -41,14 +74,15 @@ private:
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
- explicit DebugMonitor() : ServiceFramework{"pm:dmnt"} {
+ explicit DebugMonitor(const Kernel::KernelCore& kernel)
+ : ServiceFramework{"pm:dmnt"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetDebugProcesses"},
{1, nullptr, "StartDebugProcess"},
- {2, nullptr, "GetTitlePid"},
+ {2, &DebugMonitor::GetTitlePid, "GetTitlePid"},
{3, nullptr, "EnableDebugForTitleId"},
- {4, nullptr, "GetApplicationPid"},
+ {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"},
{5, nullptr, "EnableDebugForApplication"},
{6, nullptr, "DisableDebug"},
};
@@ -56,21 +90,77 @@ public:
RegisterHandlers(functions);
}
+
+private:
+ void GetTitlePid(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto title_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
+
+ const auto process =
+ SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) {
+ return process->GetTitleID() == title_id;
+ });
+
+ if (!process.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_PROCESS_NOT_FOUND);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push((*process)->GetProcessID());
+ }
+
+ void GetApplicationPid(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PM, "called");
+ GetApplicationPidGeneric(ctx, kernel.GetProcessList());
+ }
+
+ const Kernel::KernelCore& kernel;
};
class Info final : public ServiceFramework<Info> {
public:
- explicit Info() : ServiceFramework{"pm:info"} {
+ explicit Info(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list)
+ : ServiceFramework{"pm:info"}, process_list(process_list) {
static const FunctionInfo functions[] = {
- {0, nullptr, "GetTitleId"},
+ {0, &Info::GetTitleId, "GetTitleId"},
};
RegisterHandlers(functions);
}
+
+private:
+ void GetTitleId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
+
+ const auto process = SearchProcessList(process_list, [process_id](const auto& process) {
+ return process->GetProcessID() == process_id;
+ });
+
+ if (!process.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_PROCESS_NOT_FOUND);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push((*process)->GetTitleID());
+ }
+
+ const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list;
};
class Shell final : public ServiceFramework<Shell> {
public:
- explicit Shell() : ServiceFramework{"pm:shell"} {
+ explicit Shell(const Kernel::KernelCore& kernel)
+ : ServiceFramework{"pm:shell"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "LaunchProcess"},
@@ -79,21 +169,31 @@ public:
{3, nullptr, "GetProcessEventWaiter"},
{4, nullptr, "GetProcessEventType"},
{5, nullptr, "NotifyBootFinished"},
- {6, nullptr, "GetApplicationPid"},
+ {6, &Shell::GetApplicationPid, "GetApplicationPid"},
{7, nullptr, "BoostSystemMemoryResourceLimit"},
{8, nullptr, "EnableAdditionalSystemThreads"},
+ {9, nullptr, "GetUnimplementedEventHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
+
+private:
+ void GetApplicationPid(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PM, "called");
+ GetApplicationPidGeneric(ctx, kernel.GetProcessList());
+ }
+
+ const Kernel::KernelCore& kernel;
};
-void InstallInterfaces(SM::ServiceManager& sm) {
- std::make_shared<BootMode>()->InstallAsService(sm);
- std::make_shared<DebugMonitor>()->InstallAsService(sm);
- std::make_shared<Info>()->InstallAsService(sm);
- std::make_shared<Shell>()->InstallAsService(sm);
+void InstallInterfaces(Core::System& system) {
+ std::make_shared<BootMode>()->InstallAsService(system.ServiceManager());
+ std::make_shared<DebugMonitor>(system.Kernel())->InstallAsService(system.ServiceManager());
+ std::make_shared<Info>(system.Kernel().GetProcessList())
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<Shell>(system.Kernel())->InstallAsService(system.ServiceManager());
}
} // namespace Service::PM
diff --git a/src/core/hle/service/pm/pm.h b/src/core/hle/service/pm/pm.h
index cc8d3f215..852e7050c 100644
--- a/src/core/hle/service/pm/pm.h
+++ b/src/core/hle/service/pm/pm.h
@@ -4,8 +4,8 @@
#pragma once
-namespace Service::SM {
-class ServiceManager;
+namespace Core {
+class System;
}
namespace Service::PM {
@@ -16,6 +16,6 @@ enum class SystemBootMode {
};
/// Registers all PM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(Core::System& system);
} // namespace Service::PM
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index e4fcee9f8..18d895263 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -2,26 +2,31 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/service.h"
+#include "core/reporter.h"
namespace Service::PlayReport {
class PlayReport final : public ServiceFramework<PlayReport> {
public:
- explicit PlayReport(const char* name) : ServiceFramework{name} {
+ explicit PlayReport(const char* name, Core::System& system)
+ : ServiceFramework{name}, system(system) {
// clang-format off
static const FunctionInfo functions[] = {
- {10100, nullptr, "SaveReportOld"},
- {10101, &PlayReport::SaveReportWithUserOld, "SaveReportWithUserOld"},
- {10102, nullptr, "SaveReport"},
- {10103, nullptr, "SaveReportWithUser"},
+ {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"},
+ {10101, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old>, "SaveReportWithUserOld"},
+ {10102, &PlayReport::SaveReport<Core::Reporter::PlayReportType::New>, "SaveReport"},
+ {10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::New>, "SaveReportWithUser"},
{10200, nullptr, "RequestImmediateTransmission"},
{10300, nullptr, "GetTransmissionStatus"},
- {20100, nullptr, "SaveSystemReport"},
- {20101, nullptr, "SaveSystemReportWithUser"},
+ {20100, &PlayReport::SaveSystemReport, "SaveSystemReport"},
+ {20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20200, nullptr, "SetOperationMode"},
{30100, nullptr, "ClearStorage"},
{30200, nullptr, "ClearStatistics"},
@@ -39,21 +44,96 @@ public:
}
private:
- void SaveReportWithUserOld(Kernel::HLERequestContext& ctx) {
- // TODO(ogniK): Do we want to add play report?
- LOG_WARNING(Service_PREPO, "(STUBBED) called");
+ template <Core::Reporter::PlayReportType Type>
+ void SaveReport(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto process_id = rp.PopRaw<u64>();
+
+ const auto data1 = ctx.ReadBuffer(0);
+ const auto data2 = ctx.ReadBuffer(1);
+
+ LOG_DEBUG(Service_PREPO,
+ "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}",
+ static_cast<u8>(Type), process_id, data1.size(), data2.size());
+
+ const auto& reporter{system.GetReporter()};
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
+ process_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ template <Core::Reporter::PlayReportType Type>
+ void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto user_id = rp.PopRaw<u128>();
+ const auto process_id = rp.PopRaw<u64>();
+
+ const auto data1 = ctx.ReadBuffer(0);
+ const auto data2 = ctx.ReadBuffer(1);
+
+ LOG_DEBUG(
+ Service_PREPO,
+ "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}, "
+ "data2_size={:016X}",
+ static_cast<u8>(Type), user_id[1], user_id[0], process_id, data1.size(), data2.size());
+
+ const auto& reporter{system.GetReporter()};
+ reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), {data1, data2},
+ process_id, user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void SaveSystemReport(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto title_id = rp.PopRaw<u64>();
+
+ const auto data1 = ctx.ReadBuffer(0);
+ const auto data2 = ctx.ReadBuffer(1);
+
+ LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
+ title_id, data1.size(), data2.size());
+
+ const auto& reporter{system.GetReporter()};
+ reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2});
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void SaveSystemReportWithUser(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto user_id = rp.PopRaw<u128>();
+ const auto title_id = rp.PopRaw<u64>();
+
+ const auto data1 = ctx.ReadBuffer(0);
+ const auto data2 = ctx.ReadBuffer(1);
+
+ LOG_DEBUG(Service_PREPO,
+ "called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, "
+ "data2_size={:016X}",
+ user_id[1], user_id[0], title_id, data1.size(), data2.size());
+
+ const auto& reporter{system.GetReporter()};
+ reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2},
+ std::nullopt, user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+
+ Core::System& system;
};
-void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:a2")->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<PlayReport>("prepo:a", system)->InstallAsService(service_manager);
+ std::make_shared<PlayReport>("prepo:a2", system)->InstallAsService(service_manager);
+ std::make_shared<PlayReport>("prepo:m", system)->InstallAsService(service_manager);
+ std::make_shared<PlayReport>("prepo:s", system)->InstallAsService(service_manager);
+ std::make_shared<PlayReport>("prepo:u", system)->InstallAsService(service_manager);
}
} // namespace Service::PlayReport
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index 0e7b01331..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 {
class ServiceManager;
}
+namespace Core {
+class System;
+}
+
namespace Service::PlayReport {
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::PlayReport
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 00806b0ed..831a427de 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -19,7 +19,6 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/apm/apm.h"
-#include "core/hle/service/arp/arp.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/bcat/module.h"
#include "core/hle/service/bpc/bpc.h"
@@ -33,6 +32,7 @@
#include "core/hle/service/fgm/fgm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/friend/friend.h"
+#include "core/hle/service/glue/glue.h"
#include "core/hle/service/grc/grc.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/lbl/lbl.h"
@@ -68,6 +68,7 @@
#include "core/hle/service/usb/usb.h"
#include "core/hle/service/vi/vi.h"
#include "core/hle/service/wlan/wlan.h"
+#include "core/reporter.h"
namespace Service {
@@ -148,6 +149,8 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
}
buf.push_back('}');
+ Core::System::GetInstance().GetReporter().SaveUnimplementedFunctionReport(
+ ctx, ctx.GetCommand(), function_name, service_name);
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
}
@@ -192,61 +195,61 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
// Module interface
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
- FileSys::VfsFilesystem& vfs) {
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
- auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
+ auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
+ system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
SM::ServiceManager::InstallInterfaces(sm);
- Account::InstallInterfaces(*sm);
- AM::InstallInterfaces(*sm, nv_flinger);
- AOC::InstallInterfaces(*sm);
- APM::InstallInterfaces(*sm);
- ARP::InstallInterfaces(*sm);
- Audio::InstallInterfaces(*sm);
+ Account::InstallInterfaces(system);
+ AM::InstallInterfaces(*sm, nv_flinger, system);
+ AOC::InstallInterfaces(*sm, system);
+ APM::InstallInterfaces(system);
+ Audio::InstallInterfaces(*sm, system);
BCAT::InstallInterfaces(*sm);
BPC::InstallInterfaces(*sm);
- BtDrv::InstallInterfaces(*sm);
- BTM::InstallInterfaces(*sm);
+ BtDrv::InstallInterfaces(*sm, system);
+ BTM::InstallInterfaces(*sm, system);
Capture::InstallInterfaces(*sm);
ERPT::InstallInterfaces(*sm);
ES::InstallInterfaces(*sm);
EUPLD::InstallInterfaces(*sm);
- Fatal::InstallInterfaces(*sm);
+ Fatal::InstallInterfaces(*sm, system);
FGM::InstallInterfaces(*sm);
- FileSystem::InstallInterfaces(*sm, vfs);
- Friend::InstallInterfaces(*sm);
+ FileSystem::InstallInterfaces(system);
+ Friend::InstallInterfaces(*sm, system);
+ Glue::InstallInterfaces(system);
GRC::InstallInterfaces(*sm);
- HID::InstallInterfaces(*sm);
+ HID::InstallInterfaces(*sm, system);
LBL::InstallInterfaces(*sm);
LDN::InstallInterfaces(*sm);
- LDR::InstallInterfaces(*sm);
+ LDR::InstallInterfaces(*sm, system);
LM::InstallInterfaces(*sm);
Migration::InstallInterfaces(*sm);
Mii::InstallInterfaces(*sm);
MM::InstallInterfaces(*sm);
NCM::InstallInterfaces(*sm);
NFC::InstallInterfaces(*sm);
- NFP::InstallInterfaces(*sm);
- NIFM::InstallInterfaces(*sm);
- NIM::InstallInterfaces(*sm);
+ NFP::InstallInterfaces(*sm, system);
+ NIFM::InstallInterfaces(*sm, system);
+ NIM::InstallInterfaces(*sm, system);
NPNS::InstallInterfaces(*sm);
- NS::InstallInterfaces(*sm);
- Nvidia::InstallInterfaces(*sm, *nv_flinger);
+ NS::InstallInterfaces(*sm, system);
+ Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
PCIe::InstallInterfaces(*sm);
PCTL::InstallInterfaces(*sm);
PCV::InstallInterfaces(*sm);
- PlayReport::InstallInterfaces(*sm);
- PM::InstallInterfaces(*sm);
+ PlayReport::InstallInterfaces(*sm, system);
+ PM::InstallInterfaces(system);
PSC::InstallInterfaces(*sm);
PSM::InstallInterfaces(*sm);
Set::InstallInterfaces(*sm);
Sockets::InstallInterfaces(*sm);
SPL::InstallInterfaces(*sm);
SSL::InstallInterfaces(*sm);
- Time::InstallInterfaces(*sm);
+ Time::InstallInterfaces(system);
USB::InstallInterfaces(*sm);
VI::InstallInterfaces(*sm, nv_flinger);
WLAN::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index abbfe5524..aef964861 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -18,10 +18,6 @@ namespace Core {
class System;
}
-namespace FileSys {
-class VfsFilesystem;
-}
-
namespace Kernel {
class ClientPort;
class ServerPort;
@@ -31,6 +27,10 @@ class HLERequestContext;
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
namespace SM {
class ServiceManager;
}
@@ -182,8 +182,7 @@ private:
};
/// Initialize ServiceManager
-void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
- FileSys::VfsFilesystem& vfs);
+void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
/// Shutdown ServiceManager
void Shutdown();
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 298d85011..b54214421 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -95,6 +95,14 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
}
+void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(static_cast<u32>(Settings::values.quest_flag));
+}
+
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
@@ -114,7 +122,7 @@ SET::SET() : ServiceFramework("set") {
{5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
{6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"},
{7, nullptr, "GetKeyCodeMap"},
- {8, nullptr, "GetQuestFlag"},
+ {8, &SET::GetQuestFlag, "GetQuestFlag"},
{9, nullptr, "GetKeyCodeMap2"},
};
// clang-format on
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 31f9cb296..b154e08aa 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -42,6 +42,7 @@ private:
void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
+ void GetQuestFlag(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Set
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 8d122ae33..9565e7de5 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -6,8 +6,9 @@
namespace Service::Time {
-Time::Time(std::shared_ptr<Module> time, const char* name)
- : Module::Interface(std::move(time), name) {
+Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
+ Core::System& system, const char* name)
+ : Module::Interface(std::move(time), std::move(shared_memory), system, name) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
@@ -16,12 +17,12 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{3, &Time::GetTimeZoneService, "GetTimeZoneService"},
{4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
{5, nullptr, "GetEphemeralNetworkSystemClock"},
- {20, nullptr, "GetSharedMemoryNativeHandle"},
+ {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
- {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
- {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
+ {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h
index cd6b44dec..5c63a07f4 100644
--- a/src/core/hle/service/time/interface.h
+++ b/src/core/hle/service/time/interface.h
@@ -8,9 +8,12 @@
namespace Service::Time {
+class SharedMemory;
+
class Time final : public Module::Interface {
public:
- explicit Time(std::shared_ptr<Module> time, const char* name);
+ explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
+ Core::System& system, const char* name);
~Time() override;
};
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 346bad80d..1b9ab8401 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -13,6 +13,7 @@
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/time/interface.h"
#include "core/hle/service/time/time.h"
+#include "core/hle/service/time/time_sharedmemory.h"
#include "core/settings.h"
namespace Service::Time {
@@ -61,9 +62,18 @@ static u64 CalendarToPosix(const CalendarTime& calendar_time,
return static_cast<u64>(epoch_time);
}
+enum class ClockContextType {
+ StandardSteady,
+ StandardUserSystem,
+ StandardNetworkSystem,
+ StandardLocalSystem,
+};
+
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
- ISystemClock() : ServiceFramework("ISystemClock") {
+ ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory,
+ ClockContextType clock_type)
+ : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"},
@@ -72,6 +82,8 @@ public:
};
RegisterHandlers(functions);
+
+ UpdateSharedMemoryContext(system_clock_context);
}
private:
@@ -87,34 +99,64 @@ private:
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Time, "(STUBBED) called");
- SystemClockContext system_clock_ontext{};
+ // TODO(ogniK): This should be updated periodically however since we have it stubbed we'll
+ // only update when we get a new context
+ UpdateSharedMemoryContext(system_clock_context);
+
IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
rb.Push(RESULT_SUCCESS);
- rb.PushRaw(system_clock_ontext);
+ rb.PushRaw(system_clock_context);
}
+
+ void UpdateSharedMemoryContext(const SystemClockContext& clock_context) {
+ switch (clock_type) {
+ case ClockContextType::StandardLocalSystem:
+ shared_memory->SetStandardLocalSystemClockContext(clock_context);
+ break;
+ case ClockContextType::StandardNetworkSystem:
+ shared_memory->SetStandardNetworkSystemClockContext(clock_context);
+ break;
+ }
+ }
+
+ SystemClockContext system_clock_context{};
+ std::shared_ptr<Service::Time::SharedMemory> shared_memory;
+ ClockContextType clock_type;
};
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public:
- ISteadyClock() : ServiceFramework("ISteadyClock") {
+ ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system)
+ : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) {
static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
};
RegisterHandlers(functions);
+
+ shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
}
private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
- const auto& core_timing = Core::System::GetInstance().CoreTiming();
- const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
- const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000),
- {}};
+ const auto time_point = GetCurrentTimePoint();
+ // TODO(ogniK): This should be updated periodically
+ shared_memory->SetStandardSteadyClockTimepoint(time_point);
+
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS);
- rb.PushRaw(steady_clock_time_point);
+ rb.PushRaw(time_point);
+ }
+
+ SteadyClockTimePoint GetCurrentTimePoint() const {
+ const auto& core_timing = system.CoreTiming();
+ const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
+ return {static_cast<u64_le>(ms.count() / 1000), {}};
}
+
+ std::shared_ptr<SharedMemory> shared_memory;
+ Core::System& system;
};
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@@ -233,7 +275,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemClock>();
+ rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);
}
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
@@ -241,7 +283,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemClock>();
+ rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);
}
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
@@ -249,7 +291,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISteadyClock>();
+ rb.PushIpcInterface<ISteadyClock>(shared_memory, system);
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
@@ -265,7 +307,7 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemClock>();
+ rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);
}
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
@@ -284,7 +326,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
return;
}
- const auto& core_timing = Core::System::GetInstance().CoreTiming();
+ const auto& core_timing = system.CoreTiming();
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}};
@@ -333,16 +375,56 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
rb.PushRaw<u64>(difference);
}
-Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
- : ServiceFramework(name), time(std::move(time)) {}
+void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder());
+}
+
+void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled(
+ Kernel::HLERequestContext& ctx) {
+ // ogniK(TODO): When clock contexts are implemented, the value should be read from the context
+ // instead of our shared memory holder
+ LOG_DEBUG(Service_Time, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled());
+}
+
+void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
+ Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto enabled = rp.Pop<u8>();
+
+ LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called");
+
+ // TODO(ogniK): Update clock contexts and correct timespans
+
+ shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+Module::Interface::Interface(std::shared_ptr<Module> time,
+ std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
+ const char* name)
+ : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)),
+ system(system) {}
Module::Interface::~Interface() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(Core::System& system) {
auto time = std::make_shared<Module>();
- std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager);
- std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager);
- std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager);
+ auto shared_mem = std::make_shared<SharedMemory>(system);
+
+ std::make_shared<Time>(time, shared_mem, system, "time:a")
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<Time>(time, shared_mem, system, "time:s")
+ ->InstallAsService(system.ServiceManager());
+ std::make_shared<Time>(std::move(time), shared_mem, system, "time:u")
+ ->InstallAsService(system.ServiceManager());
}
} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index f11affe95..c32d32860 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -10,6 +10,8 @@
namespace Service::Time {
+class SharedMemory;
+
struct LocationName {
std::array<u8, 0x24> name;
};
@@ -77,7 +79,9 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(std::shared_ptr<Module> time, const char* name);
+ explicit Interface(std::shared_ptr<Module> time,
+ std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
+ const char* name);
~Interface() override;
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -87,13 +91,18 @@ public:
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
+ void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
+ void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
+ void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;
+ std::shared_ptr<SharedMemory> shared_memory;
+ Core::System& system;
};
};
/// Registers all Time services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(Core::System& system);
} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
new file mode 100644
index 000000000..bfc81b83c
--- /dev/null
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -0,0 +1,68 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hle/service/time/time_sharedmemory.h"
+
+namespace Service::Time {
+const std::size_t SHARED_MEMORY_SIZE = 0x1000;
+
+SharedMemory::SharedMemory(Core::System& system) : system(system) {
+ shared_memory_holder = Kernel::SharedMemory::Create(
+ system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
+
+ // Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash
+ // if it's set to anything else
+ shared_memory_format.format_version = 14;
+ std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format));
+}
+
+SharedMemory::~SharedMemory() = default;
+
+Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const {
+ return shared_memory_holder;
+}
+
+void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) {
+ shared_memory_format.standard_steady_clock_timepoint.StoreData(
+ shared_memory_holder->GetPointer(), timepoint);
+}
+
+void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) {
+ shared_memory_format.standard_local_system_clock_context.StoreData(
+ shared_memory_holder->GetPointer(), context);
+}
+
+void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) {
+ shared_memory_format.standard_network_system_clock_context.StoreData(
+ shared_memory_holder->GetPointer(), context);
+}
+
+void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
+ shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
+ shared_memory_holder->GetPointer(), enabled);
+}
+
+SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() {
+ return shared_memory_format.standard_steady_clock_timepoint.ReadData(
+ shared_memory_holder->GetPointer());
+}
+
+SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() {
+ return shared_memory_format.standard_local_system_clock_context.ReadData(
+ shared_memory_holder->GetPointer());
+}
+
+SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() {
+ return shared_memory_format.standard_network_system_clock_context.ReadData(
+ shared_memory_holder->GetPointer());
+}
+
+bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() {
+ return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData(
+ shared_memory_holder->GetPointer());
+}
+
+} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
new file mode 100644
index 000000000..cb8253541
--- /dev/null
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -0,0 +1,74 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/time/time.h"
+
+namespace Service::Time {
+class SharedMemory {
+public:
+ explicit SharedMemory(Core::System& system);
+ ~SharedMemory();
+
+ // Return the shared memory handle
+ Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
+
+ // Set memory barriers in shared memory and update them
+ void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
+ void SetStandardLocalSystemClockContext(const SystemClockContext& context);
+ void SetStandardNetworkSystemClockContext(const SystemClockContext& context);
+ void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled);
+
+ // Pull from memory barriers in the shared memory
+ SteadyClockTimePoint GetStandardSteadyClockTimepoint();
+ SystemClockContext GetStandardLocalSystemClockContext();
+ SystemClockContext GetStandardNetworkSystemClockContext();
+ bool GetStandardUserSystemClockAutomaticCorrectionEnabled();
+
+ // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
+ template <typename T, std::size_t Offset>
+ struct MemoryBarrier {
+ static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable");
+ u32_le read_attempt{};
+ std::array<T, 2> data{};
+
+ // These are not actually memory barriers at the moment as we don't have multicore and all
+ // HLE is mutexed. This will need to properly be implemented when we start updating the time
+ // points on threads. As of right now, we'll be updated both values synchronously and just
+ // incrementing the read_attempt to indicate that we waited.
+ void StoreData(u8* shared_memory, T data_to_store) {
+ std::memcpy(this, shared_memory + Offset, sizeof(*this));
+ read_attempt++;
+ data[read_attempt & 1] = data_to_store;
+ std::memcpy(shared_memory + Offset, this, sizeof(*this));
+ }
+
+ // For reading we're just going to read the last stored value. If there was no value stored
+ // it will just end up reading an empty value as intended.
+ T ReadData(u8* shared_memory) {
+ std::memcpy(this, shared_memory + Offset, sizeof(*this));
+ return data[(read_attempt - 1) & 1];
+ }
+ };
+
+ // Shared memory format
+ struct Format {
+ MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint;
+ MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context;
+ MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context;
+ MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
+ u32_le format_version;
+ };
+ static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
+
+private:
+ Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{};
+ Core::System& system;
+ Format shared_memory_format{};
+};
+
+} // namespace Service::Time
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 @@
namespace Service::VI {
-Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} {
- auto& kernel = Core::System::GetInstance().Kernel();
+Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} {
+ auto& kernel = system.Kernel();
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
fmt::format("Display VSync Event {}", id));
}
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:
/// @param id The unique ID for this display.
/// @param name The name for this display.
///
- Display(u64 id, std::string name);
+ Display(u64 id, std::string name, Core::System& system);
~Display();
Display(const Display&) = delete;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index f1fa6ccd1..199b30635 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -21,6 +21,7 @@
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -328,32 +329,22 @@ public:
Data data;
};
-struct BufferProducerFence {
- u32 is_valid;
- std::array<Nvidia::IoctlFence, 4> fences;
-};
-static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size");
-
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
- explicit IGBPDequeueBufferResponseParcel(u32 slot) : slot(slot) {}
+ explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
+ : slot(slot), multi_fence(multi_fence) {}
~IGBPDequeueBufferResponseParcel() override = default;
protected:
void SerializeData() override {
- // TODO(Subv): Find out how this Fence is used.
- BufferProducerFence fence = {};
- fence.is_valid = 1;
- for (auto& fence_ : fence.fences)
- fence_.id = -1;
-
Write(slot);
Write<u32_le>(1);
- WriteObject(fence);
+ WriteObject(multi_fence);
Write<u32_le>(0);
}
u32_le slot;
+ Service::Nvidia::MultiFence multi_fence;
};
class IGBPRequestBufferRequestParcel : public Parcel {
@@ -400,12 +391,6 @@ public:
data = Read<Data>();
}
- struct Fence {
- u32_le id;
- u32_le value;
- };
- static_assert(sizeof(Fence) == 8, "Fence has wrong size");
-
struct Data {
u32_le slot;
INSERT_PADDING_WORDS(3);
@@ -418,15 +403,15 @@ public:
s32_le scaling_mode;
NVFlinger::BufferQueue::BufferTransformFlags transform;
u32_le sticky_transform;
- INSERT_PADDING_WORDS(2);
- u32_le fence_is_valid;
- std::array<Fence, 2> fences;
+ INSERT_PADDING_WORDS(1);
+ u32_le swap_interval;
+ Service::Nvidia::MultiFence multi_fence;
Common::Rectangle<int> GetCropRect() const {
return {crop_left, crop_top, crop_right, crop_bottom};
}
};
- static_assert(sizeof(Data) == 80, "ParcelData has wrong size");
+ static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
Data data;
};
@@ -547,11 +532,11 @@ private:
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width};
const u32 height{request.data.height};
- std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height);
+ auto result = buffer_queue.DequeueBuffer(width, height);
- if (slot) {
+ if (result) {
// Buffer is available
- IGBPDequeueBufferResponseParcel response{*slot};
+ IGBPDequeueBufferResponseParcel response{result->first, *result->second};
ctx.WriteBuffer(response.Serialize());
} else {
// Wait the current thread until a buffer becomes available
@@ -561,10 +546,10 @@ private:
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
- std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height);
- ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
+ auto result = buffer_queue.DequeueBuffer(width, height);
+ ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
- IGBPDequeueBufferResponseParcel response{*slot};
+ IGBPDequeueBufferResponseParcel response{result->first, *result->second};
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -582,7 +567,8 @@ private:
IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
- request.data.GetCropRect());
+ request.data.GetCropRect(), request.data.swap_interval,
+ request.data.multi_fence);
IGBPQueueBufferResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize());