aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/acc/acc.cpp6
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp25
-rw-r--r--src/core/hle/service/acc/profile_manager.h13
-rw-r--r--src/core/hle/service/audio/audren_u.cpp25
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp153
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp2
-rw-r--r--src/core/hle/service/ns/ns.cpp64
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/spl/module.cpp9
-rw-r--r--src/core/hle/service/spl/module.h4
-rw-r--r--src/core/hle/service/time/interface.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp132
-rw-r--r--src/core/hle/service/time/time.h19
17 files changed, 424 insertions, 47 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 8318eff5f..c629f9357 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -252,8 +252,10 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
rb.PushRaw<u128>(INVALID_UUID);
return;
}
- auto user_list = profile_manager->GetAllUsers();
- if (user_list.empty()) {
+
+ const auto user_list = profile_manager->GetAllUsers();
+ if (std::all_of(user_list.begin(), user_list.end(),
+ [](const auto& user) { return user.uuid == INVALID_UUID; })) {
rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
rb.PushRaw<u128>(INVALID_UUID);
return;
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index c08394e4c..968263846 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <random>
+#include <fmt/format.h>
+
#include "common/file_util.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h"
@@ -39,6 +42,19 @@ UUID UUID::Generate() {
return UUID{distribution(gen), distribution(gen)};
}
+std::string UUID::Format() const {
+ return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
+}
+
+std::string UUID::FormatSwitch() const {
+ std::array<u8, 16> s{};
+ std::memcpy(s.data(), uuid.data(), sizeof(u128));
+ return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
+ ":02x}{:02x}{:02x}{:02x}{:02x}",
+ s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
+ s[12], s[13], s[14], s[15]);
+}
+
ProfileManager::ProfileManager() {
ParseUserSaveFile();
@@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() {
return;
}
- for (std::size_t i = 0; i < MAX_USERS; ++i) {
- const auto& user = data.users[i];
+ for (const auto& user : data.users) {
+ if (user.uuid == UUID(INVALID_UUID)) {
+ continue;
+ }
- if (user.uuid != UUID(INVALID_UUID))
- AddUser({user.uuid, user.username, user.timestamp, {}, false});
+ AddUser({user.uuid, user.username, user.timestamp, {}, false});
}
std::stable_partition(profiles.begin(), profiles.end(),
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 747c46c20..d2d8e6c6b 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -42,18 +42,9 @@ struct UUID {
void Invalidate() {
uuid = INVALID_UUID;
}
- std::string Format() const {
- return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
- }
- std::string FormatSwitch() const {
- std::array<u8, 16> s{};
- std::memcpy(s.data(), uuid.data(), sizeof(u128));
- return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
- ":02x}{:02x}{:02x}{:02x}{:02x}",
- s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
- s[12], s[13], s[14], s[15]);
- }
+ std::string Format() const;
+ std::string FormatSwitch() const;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fac6785a5..35a8bef6c 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -32,8 +32,8 @@ public:
{5, &IAudioRenderer::Start, "Start"},
{6, &IAudioRenderer::Stop, "Stop"},
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
- {8, nullptr, "SetRenderingTimeLimit"},
- {9, nullptr, "GetRenderingTimeLimit"},
+ {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
+ {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
{10, nullptr, "RequestUpdateAuto"},
{11, nullptr, "ExecuteAudioRendererRendering"},
};
@@ -110,8 +110,29 @@ private:
LOG_WARNING(Service_Audio, "(STUBBED) called");
}
+ void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rendering_time_limit_percent = rp.Pop<u32>();
+ ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+
+ LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
+ rendering_time_limit_percent);
+ }
+
+ void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(rendering_time_limit_percent);
+ }
+
Kernel::SharedPtr<Kernel::Event> system_event;
std::unique_ptr<AudioCore::AudioRenderer> renderer;
+ u32 rendering_time_limit_percent = 100;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e32a7c48e..ea8fd965a 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -309,6 +309,16 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
return save_data_factory->Open(space, save_struct);
}
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+ LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
+
+ if (save_data_factory == nullptr) {
+ return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
+ }
+
+ return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
+}
+
ResultVal<FileSys::VirtualDir> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6ca5c5636..2cbb70c87 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -45,6 +45,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index c1c83a11d..b9a1d5105 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -11,6 +11,7 @@
#include "common/assert.h"
#include "common/common_types.h"
+#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/file_sys/directory.h"
@@ -451,7 +452,147 @@ private:
VfsDirectoryServiceWrapper backend;
};
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
+ : ServiceFramework("ISaveDataInfoReader") {
+ static const FunctionInfo functions[] = {
+ {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+ }
+
+ void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ ctx.WriteBuffer(begin, range_size);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(actual_entries));
+ }
+
+private:
+ static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16)
+ return 0;
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+ }
+
+ void FindAllSaves(FileSys::SaveDataSpaceId space) {
+ const auto save_root = OpenSaveDataSpace(space);
+ ASSERT(save_root.Succeeded());
+
+ for (const auto& type : (*save_root)->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::SystemSaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device =
+ std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::DeviceSaveData
+ : FileSys::SaveDataType::SaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
+ // Temporary Storage
+ for (const auto& user_id : type->GetSubdirectories()) {
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() ||
+ !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric =
+ Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::TemporaryStorage,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ INSERT_PADDING_BYTES(0x28);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "MountContent"},
{1, &FSP_SRV::Initialize, "Initialize"},
@@ -485,7 +626,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
- {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
{62, nullptr, "OpenCacheStorageList"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
@@ -544,6 +685,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
};
+ // clang-format on
RegisterHandlers(functions);
}
@@ -618,6 +760,15 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
MountSaveData(ctx);
}
+void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
+}
+
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4aa0358cb..e7abec0a3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -25,6 +25,7 @@ private:
void CreateSaveData(Kernel::HLERequestContext& ctx);
void MountSaveData(Kernel::HLERequestContext& ctx);
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ff9b64be4..56c415e4e 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -310,6 +310,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
dual_entry.pad_states.raw = pad_state.raw;
dual_entry.l_stick = lstick_entry;
dual_entry.r_stick = rstick_entry;
+ break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index c1af878fe..1d6e7756f 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -212,7 +212,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
auto amiibo = nfp_interface.GetAmiiboBuffer();
TagInfo tag_info{};
- std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size()));
+ tag_info.uuid = amiibo.uuid;
tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 07c1381fe..1d2978f24 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.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/hle_ipc.h"
#include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
- {400, nullptr, "GetApplicationControlData"},
+ {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
RegisterHandlers(functions);
}
+
+ void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto flag = rp.PopRaw<u64>();
+ LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
+
+ const auto title_id = rp.PopRaw<u64>();
+
+ const auto size = ctx.GetWriteBufferSize();
+
+ const FileSys::PatchManager pm{title_id};
+ const auto control = pm.GetControlMetadata();
+
+ std::vector<u8> out;
+
+ if (control.first != nullptr) {
+ if (size < 0x4000) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
+ size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000);
+ const auto bytes = control.first->GetRawBytes();
+ std::memcpy(out.data(), bytes.data(), bytes.size());
+ } else {
+ LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ out.resize(std::min<u64>(0x4000, size));
+ }
+
+ if (control.second != nullptr) {
+ if (size < 0x4000 + control.second->GetSize()) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min={:016X})",
+ size, 0x4000 + control.second->GetSize());
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000 + control.second->GetSize());
+ control.second->Read(out.data() + 0x4000, control.second->GetSize());
+ } else {
+ LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ }
+
+ ctx.WriteBuffer(out);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(out.size()));
+ }
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a4cf45267..1ec340466 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -80,8 +80,8 @@ namespace Service {
* Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
-static std::string MakeFunctionString(const char* name, const char* port_name,
- const u32* cmd_buff) {
+[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name,
+ const u32* cmd_buff) {
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 44a6717d0..69c260408 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -3,18 +3,23 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <chrono>
#include <cstdlib>
+#include <ctime>
+#include <functional>
#include <vector>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h"
#include "core/hle/service/spl/spl.h"
+#include "core/settings.h"
namespace Service::SPL {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {}
+ : ServiceFramework(name), module(std::move(module)),
+ rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
@@ -24,7 +29,7 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
std::size_t size = ctx.GetWriteBufferSize();
std::vector<u8> data(size);
- std::generate(data.begin(), data.end(), std::rand);
+ std::generate(data.begin(), data.end(), rng);
ctx.WriteBuffer(data);
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 48fda6099..afa1f0295 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -4,6 +4,7 @@
#pragma once
+#include <random>
#include "core/hle/service/service.h"
namespace Service::SPL {
@@ -19,6 +20,9 @@ public:
protected:
std::shared_ptr<Module> module;
+
+ private:
+ std::mt19937 rng;
};
};
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 18a5d71d5..e3cbd7004 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,7 +21,7 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
- {400, nullptr, "GetClockSnapshot"},
+ {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
{501, nullptr, "CalculateSpanBetween"},
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 28fd8debc..85e7b1195 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -15,6 +15,44 @@
namespace Service::Time {
+static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
+ CalendarAdditionalInfo& additional_info,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ const std::time_t time(posix_time);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ calendar_time = {};
+ additional_info = {};
+ return;
+ }
+ calendar_time.year = tm->tm_year + 1900;
+ calendar_time.month = tm->tm_mon + 1;
+ calendar_time.day = tm->tm_mday;
+ calendar_time.hour = tm->tm_hour;
+ calendar_time.minute = tm->tm_min;
+ calendar_time.second = tm->tm_sec;
+
+ additional_info.day_of_week = tm->tm_wday;
+ additional_info.day_of_year = tm->tm_yday;
+ std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
+ additional_info.utc_offset = 0;
+}
+
+static u64 CalendarToPosix(const CalendarTime& calendar_time,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ std::tm time{};
+ time.tm_year = calendar_time.year - 1900;
+ time.tm_mon = calendar_time.month - 1;
+ time.tm_mday = calendar_time.day;
+
+ time.tm_hour = calendar_time.hour;
+ time.tm_min = calendar_time.minute;
+ time.tm_sec = calendar_time.second;
+
+ std::time_t epoch_time = std::mktime(&time);
+ return static_cast<u64>(epoch_time);
+}
+
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
@@ -80,8 +118,8 @@ public:
{5, nullptr, "GetTimeZoneRuleVersion"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
- {201, nullptr, "ToPosixTime"},
- {202, nullptr, "ToPosixTimeWithMyRule"},
+ {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
+ {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
RegisterHandlers(functions);
}
@@ -151,24 +189,29 @@ private:
rb.PushRaw(additional_info);
}
- void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
- CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) {
- std::time_t t(posix_time);
- std::tm* tm = std::localtime(&t);
- if (!tm) {
- return;
- }
- calendar_time.year = tm->tm_year + 1900;
- calendar_time.month = tm->tm_mon + 1;
- calendar_time.day = tm->tm_mday;
- calendar_time.hour = tm->tm_hour;
- calendar_time.minute = tm->tm_min;
- calendar_time.second = tm->tm_sec;
-
- additional_info.day_of_week = tm->tm_wday;
- additional_info.day_of_year = tm->tm_yday;
- std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
- additional_info.utc_offset = 0;
+ void ToPosixTime(Kernel::HLERequestContext& ctx) {
+ // TODO(ogniK): Figure out how to handle multiple times
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
+ }
+
+ void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
}
};
@@ -207,6 +250,55 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called");
}
+void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto unknown_u8 = rp.PopRaw<u8>();
+
+ ClockSnapshot clock_snapshot{};
+
+ const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count()};
+ CalendarTime calendar_time{};
+ const std::time_t time(time_since_epoch);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
+ return;
+ }
+ SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
+ 1000};
+
+ LocationName location_name{"UTC"};
+ calendar_time.year = tm->tm_year + 1900;
+ calendar_time.month = tm->tm_mon + 1;
+ calendar_time.day = tm->tm_mday;
+ calendar_time.hour = tm->tm_hour;
+ calendar_time.minute = tm->tm_min;
+ calendar_time.second = tm->tm_sec;
+ clock_snapshot.system_posix_time = time_since_epoch;
+ clock_snapshot.network_posix_time = time_since_epoch;
+ clock_snapshot.system_calendar_time = calendar_time;
+ clock_snapshot.network_calendar_time = calendar_time;
+
+ CalendarAdditionalInfo additional_info{};
+ PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
+
+ clock_snapshot.system_calendar_info = additional_info;
+ clock_snapshot.network_calendar_info = additional_info;
+
+ clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
+ clock_snapshot.location_name = location_name;
+ clock_snapshot.clock_auto_adjustment_enabled = 1;
+ clock_snapshot.ipc_u8 = unknown_u8;
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
+}
+
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
: ServiceFramework(name), time(std::move(time)) {}
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 5659ecad3..77871ae07 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include "common/common_funcs.h"
#include "core/hle/service/service.h"
namespace Service::Time {
@@ -53,6 +54,23 @@ struct SystemClockContext {
static_assert(sizeof(SystemClockContext) == 0x20,
"SystemClockContext structure has incorrect size");
+struct ClockSnapshot {
+ SystemClockContext user_clock_context;
+ SystemClockContext network_clock_context;
+ s64_le system_posix_time;
+ s64_le network_posix_time;
+ CalendarTime system_calendar_time;
+ CalendarTime network_calendar_time;
+ CalendarAdditionalInfo system_calendar_info;
+ CalendarAdditionalInfo network_calendar_info;
+ SteadyClockTimePoint steady_clock_timepoint;
+ LocationName location_name;
+ u8 clock_auto_adjustment_enabled;
+ u8 ipc_u8;
+ INSERT_PADDING_BYTES(2);
+};
+static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
@@ -65,6 +83,7 @@ public:
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
+ void GetClockSnapshot(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;