Compare commits

...

2 Commits

Author SHA1 Message Date
german77 47a469804b kj 2023-10-10 08:31:38 -06:00
german77 3c3ca709de I'm steady 2023-10-09 22:30:55 -06:00
60 changed files with 817 additions and 3471 deletions

View File

@ -781,40 +781,28 @@ add_library(core STATIC
hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h
hle/service/time/clock_types.h
hle/service/time/ephemeral_network_system_clock_context_writer.h
hle/service/time/ephemeral_network_system_clock_core.h
hle/service/time/errors.h
hle/service/time/local_system_clock_context_writer.h
hle/service/time/network_system_clock_context_writer.h
hle/service/time/standard_local_system_clock_core.h
hle/service/time/standard_network_system_clock_core.h
hle/service/time/standard_steady_clock_core.cpp
hle/service/time/standard_steady_clock_core.h
hle/service/time/standard_user_system_clock_core.cpp
hle/service/time/standard_user_system_clock_core.h
hle/service/time/steady_clock_core.h
hle/service/time/system_clock_context_update_callback.cpp
hle/service/time/system_clock_context_update_callback.h
hle/service/time/system_clock_core.cpp
hle/service/time/system_clock_core.h
hle/service/time/tick_based_steady_clock_core.cpp
hle/service/time/tick_based_steady_clock_core.h
hle/service/time/clock_interfaces/steady_clock.cpp
hle/service/time/clock_interfaces/steady_clock.h
hle/service/time/clock_interfaces/system_clock.cpp
hle/service/time/clock_interfaces/system_clock.h
hle/service/time/clock_types/local_system_clock.cpp
hle/service/time/clock_types/local_system_clock.h
hle/service/time/clock_types/network_system_clock.cpp
hle/service/time/clock_types/network_system_clock.h
hle/service/time/clock_types/steady_clock.cpp
hle/service/time/clock_types/steady_clock.h
hle/service/time/clock_types/user_system_clock.cpp
hle/service/time/clock_types/user_system_clock.h
hle/service/time/time_zone/time_zone_service.cpp
hle/service/time/time_zone/time_zone_service.h
hle/service/time/time_zone/time_zone_types.h
hle/service/time/time.cpp
hle/service/time/time.h
hle/service/time/time_interface.cpp
hle/service/time/time_interface.h
hle/service/time/time_manager.cpp
hle/service/time/time_manager.h
hle/service/time/time_sharedmemory.cpp
hle/service/time/time_sharedmemory.h
hle/service/time/time_zone_content_manager.cpp
hle/service/time/time_zone_content_manager.h
hle/service/time/time_zone_manager.cpp
hle/service/time/time_zone_manager.h
hle/service/time/time_zone_service.cpp
hle/service/time/time_zone_service.h
hle/service/time/time_zone_types.h
hle/service/time/time_result.h
hle/service/time/time_types.h
hle/service/time/time_util.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp

View File

@ -42,7 +42,6 @@
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
#include "core/internal_network/network.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@ -133,7 +132,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system},
cpu_manager{system}, reporter{system}, applet_manager{system},
gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
@ -148,8 +147,6 @@ struct System::Impl {
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
RefreshTime();
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr) {
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
@ -187,16 +184,6 @@ struct System::Impl {
Initialize(system);
}
void RefreshTime() {
const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
const auto current_time =
std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
Settings::values.custom_rtc_differential =
(Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
: current_time) -
current_time;
}
void Run() {
std::unique_lock<std::mutex> lk(suspend_guard);
@ -270,9 +257,6 @@ struct System::Impl {
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
services = std::make_unique<Service::Services>(service_manager, system);
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
is_powered_on = true;
exit_locked = false;
exit_requested = false;
@ -425,7 +409,6 @@ struct System::Impl {
service_manager.reset();
cheat_engine.reset();
telemetry_session.reset();
time_manager.Shutdown();
core_timing.ClearPendingEvents();
app_loader.reset();
audio_core.reset();
@ -543,7 +526,6 @@ struct System::Impl {
/// Service State
Service::Glue::ARPManager arp_manager;
Service::Time::TimeManager time_manager;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@ -956,14 +938,6 @@ const Service::APM::Controller& System::GetAPMController() const {
return impl->apm_controller;
}
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}
const Service::Time::TimeManager& System::GetTimeManager() const {
return impl->time_manager;
}
void System::SetExitLocked(bool locked) {
impl->exit_locked = locked;
}
@ -1075,13 +1049,7 @@ void System::Exit() {
}
void System::ApplySettings() {
impl->RefreshTime();
if (IsPoweredOn()) {
if (Settings::values.custom_rtc_enabled) {
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
Renderer().RefreshBaseSettings();
}
}

View File

@ -68,10 +68,6 @@ namespace SM {
class ServiceManager;
} // namespace SM
namespace Time {
class TimeManager;
} // namespace Time
} // namespace Service
namespace Tegra {
@ -405,9 +401,6 @@ public:
[[nodiscard]] Service::APM::Controller& GetAPMController();
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
[[nodiscard]] Core::Debugger& GetDebugger();
[[nodiscard]] const Core::Debugger& GetDebugger() const;

View File

@ -6,7 +6,7 @@
#include "common/swap.h"
#include "core/file_sys/system_archive/time_zone_binary.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/time/time_zone_types.h"
#include "core/hle/service/time/time_zone/time_zone_types.h"
#include "nx_tzdb.h"

View File

@ -32,7 +32,6 @@
#include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/mifare_result.h"
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/time_manager.h"
namespace Service::NFC {
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
@ -393,12 +392,12 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
return result;
}
Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data,
std::span<u8> out_data) {
// Not implemented
return ResultSuccess;
}
//Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
// std::span<const u8> command_data,
// std::span<u8> out_data) {
// // Not implemented
// return ResultSuccess;
//}
Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
if (device_state != DeviceState::TagFound) {
@ -1390,27 +1389,28 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
}
NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
const auto& time_zone_manager =
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
Time::TimeZone::CalendarInfo calendar_info{};
//const auto& time_zone_manager =
// system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
//Time::TimeZone::CalendarInfo calendar_info{};
NFP::AmiiboDate amiibo_date{};
amiibo_date.SetYear(2000);
amiibo_date.SetMonth(1);
amiibo_date.SetDay(1);
if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
amiibo_date.SetYear(calendar_info.time.year);
amiibo_date.SetMonth(calendar_info.time.month);
amiibo_date.SetDay(calendar_info.time.day);
}
//if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
// amiibo_date.SetYear(calendar_info.time.year);
// amiibo_date.SetMonth(calendar_info.time.month);
// amiibo_date.SetDay(calendar_info.time.day);
//}
return amiibo_date;
}
u64 NfcDevice::GetCurrentPosixTime() const {
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
return standard_steady_clock.GetCurrentTimePoint(system).time_point;
//auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
//return standard_steady_clock.GetCurrentTimePoint(system).time_point;
return 0;
}
u64 NfcDevice::RemoveVersionByte(u64 application_id) const {

View File

@ -11,7 +11,6 @@
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Kernel {
class KEvent;
@ -49,8 +48,8 @@ public:
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<u8> out_data);
//Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
// std::span<const u8> command_data, std::span<u8> out_data);
Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
Result Unmount();

View File

@ -11,8 +11,6 @@
#include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_manager.h"
namespace Service::NFC {
@ -81,14 +79,14 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max
continue;
}
if (skip_fatal_errors) {
constexpr u64 MinimumRecoveryTime = 60;
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
time_since_last_error;
//constexpr u64 MinimumRecoveryTime = 60;
//auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
//const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
// time_since_last_error;
if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
continue;
}
//if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
// continue;
//}
}
if (device->GetCurrentState() == DeviceState::Unavailable) {
continue;
@ -249,22 +247,22 @@ Result DeviceManager::WriteMifare(u64 device_handle,
return result;
}
Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data,
std::span<u8> out_data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->SendCommandByPassThrough(timeout, command_data, out_data);
result = VerifyDeviceResult(device, result);
}
return result;
}
//Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
// const Time::Clock::TimeSpanType& timeout,
// std::span<const u8> command_data,
// std::span<u8> out_data) {
// std::scoped_lock lock{mutex};
//
// std::shared_ptr<NfcDevice> device = nullptr;
// auto result = GetDeviceHandle(device_handle, device);
//
// if (result.IsSuccess()) {
// result = device->SendCommandByPassThrough(timeout, command_data, out_data);
// result = VerifyDeviceResult(device, result);
// }
//
// return result;
//}
Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
NFP::MountTarget mount_target) {
@ -738,11 +736,11 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
return device_state;
}
if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
operation_result == ResultUnknown115) {
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point;
}
//if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
// operation_result == ResultUnknown115) {
// auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
// time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point;
//}
return operation_result;
}

View File

@ -14,7 +14,6 @@
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::NFC {
class NfcDevice;
@ -42,8 +41,8 @@ public:
std::span<MifareReadBlockData> read_data);
Result WriteMifare(u64 device_handle,
std::span<const MifareWriteBlockParameter> write_parameters);
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<u8> out_data);
//Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
// std::span<const u8> command_data, std::span<u8> out_data);
// Nfp device manager
Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);

View File

@ -14,7 +14,6 @@
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::NFC {
@ -261,14 +260,15 @@ void NfcInterface::WriteMifare(HLERequestContext& ctx) {
void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
//const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
const auto command_data{ctx.ReadBuffer()};
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
device_handle, timeout.ToSeconds(), command_data.size());
device_handle, 0, command_data.size());
std::vector<u8> out_data(1);
auto result =
GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
//auto result =
// GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
Result result = ResultSuccess;
result = TranslateResultToServiceError(result);
if (result.IsError()) {

View File

@ -5,7 +5,7 @@
#include "common/uuid.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
@ -254,7 +254,7 @@ private:
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Time::Clock::SteadyClockTimePoint timestamp;
Time::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
@ -265,7 +265,7 @@ private:
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
Time::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");

View File

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
namespace Service::Time {
ISteadyClock::ISteadyClock(Core::System& system_) : ServiceFramework{system_, "ISteadyClock"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
{2, nullptr, "GetTestOffset"},
{3, nullptr, "SetTestOffset"},
{100, nullptr, "GetRtcValue"},
{101, nullptr, "IsRtcResetDetected"},
{102, nullptr, "GetSetupResultValue"},
{200, nullptr, "GetInternalOffset"},
{201, nullptr, "SetInternalOffset"},
};
// clang-format on
RegisterHandlers(functions);
}
ISteadyClock::~ISteadyClock() = default;
void ISteadyClock::GetCurrentTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(0);
}
bool ISteadyClock::IsInitialized() {
return is_initialized;
}
} // namespace Service::Time

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class ISteadyClock : public ServiceFramework<ISteadyClock> {
public:
explicit ISteadyClock(Core::System& system_);
~ISteadyClock();
bool IsInitialized();
void UpdateTime();
private:
void GetCurrentTimePoint(HLERequestContext& ctx);
bool is_initialized{};
};
} // namespace Service::Time

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/time/clock_interfaces/system_clock.h"
namespace Service::Time {
ISystemClock::ISystemClock(Core::System& system_) : ServiceFramework{system_, "ISystemClock"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"},
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
{3, nullptr, "SetSystemClockContext"},
{4, nullptr, "GetOperationEventReadableHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
ISystemClock::~ISystemClock() = default;
void ISystemClock::GetCurrentTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
s64 posix_time{};
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s64>(posix_time);
}
void ISystemClock::GetSystemClockContext(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(0);
}
Result ISystemClock::GetClockContext(SystemClockContext& out_context) {
out_context = context;
return ResultSuccess;
}
} // namespace Service::Time

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class ISystemClock : public ServiceFramework<ISystemClock> {
public:
explicit ISystemClock(Core::System& system_);
~ISystemClock();
Result GetClockContext(SystemClockContext& out_context);
bool IsStandardNetworkSystemClockAccuracySufficient();
void UpdateTime();
private:
void GetCurrentTime(HLERequestContext& ctx);
void GetSystemClockContext(HLERequestContext& ctx);
SystemClockContext context;
};
} // namespace Service::Time

View File

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
namespace Service::Time {} // namespace Service::Time

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_interfaces/system_clock.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class LocalSystemClock : public ISystemClock {
public:
explicit LocalSystemClock();
~LocalSystemClock();
};
} // namespace Service::Time

View File

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
namespace Service::Time {} // namespace Service::Time

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_interfaces/system_clock.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class NetworkSystemClock : public ISystemClock {
public:
explicit NetworkSystemClock();
~NetworkSystemClock();
};
} // namespace Service::Time

View File

@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
#include "core/hle/service/time/clock_types/system_clock.h"
namespace Service::Time {} // namespace Service::Time

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_interfaces/steady_clock.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class SteadyClock : public ISteadyClock {
public:
explicit SteadyClock();
~SteadyClock();
};
} // namespace Service::Time

View File

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
namespace Service::Time {} // namespace Service::Time

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_interfaces/system_clock.h"
#include "core/hle/service/time/time_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class UserSystemClock : public ISystemClock {
public:
explicit UserSystemClock();
~UserSystemClock();
};
} // namespace Service::Time

View File

@ -1,15 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/system_clock_context_update_callback.h"
namespace Service::Time::Clock {
class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
public:
EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {}
};
} // namespace Service::Time::Clock

View File

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/system_clock_core.h"
namespace Service::Time::Clock {
class EphemeralNetworkSystemClockCore final : public SystemClockCore {
public:
explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
: SystemClockCore{steady_clock_core_} {}
};
} // namespace Service::Time::Clock

View File

@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::Time {
constexpr Result ERROR_PERMISSION_DENIED{ErrorModule::Time, 1};
constexpr Result ERROR_TIME_MISMATCH{ErrorModule::Time, 102};
constexpr Result ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103};
constexpr Result ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200};
constexpr Result ERROR_OVERFLOW{ErrorModule::Time, 201};
constexpr Result ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801};
constexpr Result ERROR_OUT_OF_RANGE{ErrorModule::Time, 902};
constexpr Result ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903};
constexpr Result ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989};
constexpr Result ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990};
} // namespace Service::Time

View File

@ -1,26 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/system_clock_context_update_callback.h"
#include "core/hle/service/time/time_sharedmemory.h"
namespace Service::Time::Clock {
class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
public:
explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_)
: SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
protected:
Result Update() override {
shared_memory.UpdateLocalSystemClockContext(context);
return ResultSuccess;
}
private:
SharedMemory& shared_memory;
};
} // namespace Service::Time::Clock

View File

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/system_clock_context_update_callback.h"
#include "core/hle/service/time/time_sharedmemory.h"
namespace Service::Time::Clock {
class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
public:
explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_)
: SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
protected:
Result Update() override {
shared_memory.UpdateNetworkSystemClockContext(context);
return ResultSuccess;
}
private:
SharedMemory& shared_memory;
};
} // namespace Service::Time::Clock

View File

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/system_clock_core.h"
namespace Service::Time::Clock {
class StandardLocalSystemClockCore final : public SystemClockCore {
public:
explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_)
: SystemClockCore{steady_clock_core_} {}
};
} // namespace Service::Time::Clock

View File

@ -1,45 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/steady_clock_core.h"
#include "core/hle/service/time/system_clock_core.h"
namespace Core {
class System;
}
namespace Service::Time::Clock {
class StandardNetworkSystemClockCore final : public SystemClockCore {
public:
explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
: SystemClockCore{steady_clock_core_} {}
void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
standard_network_clock_sufficient_accuracy = value;
}
bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const {
SystemClockContext clock_ctx{};
if (GetClockContext(system, clock_ctx) != ResultSuccess) {
return {};
}
s64 span{};
if (clock_ctx.steady_time_point.GetSpanBetween(
GetSteadyClockCore().GetCurrentTimePoint(system), span) != ResultSuccess) {
return {};
}
return TimeSpanType{span}.nanoseconds <
standard_network_clock_sufficient_accuracy.nanoseconds;
}
private:
TimeSpanType standard_network_clock_sufficient_accuracy{};
};
} // namespace Service::Time::Clock

View File

@ -1,24 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
#include "core/hle/service/time/standard_steady_clock_core.h"
namespace Service::Time::Clock {
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{
TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds;
}
cached_raw_time_point = raw_time_point;
return raw_time_point;
}
} // namespace Service::Time::Clock

View File

@ -1,41 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/steady_clock_core.h"
namespace Core {
class System;
}
namespace Service::Time::Clock {
class StandardSteadyClockCore final : public SteadyClockCore {
public:
SteadyClockTimePoint GetTimePoint(Core::System& system) override {
return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()};
}
TimeSpanType GetInternalOffset() const override {
return internal_offset;
}
void SetInternalOffset(TimeSpanType value) override {
internal_offset = value;
}
TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
void SetSetupValue(TimeSpanType value) {
setup_value = value;
}
private:
TimeSpanType setup_value{};
TimeSpanType internal_offset{};
TimeSpanType cached_raw_time_point{};
};
} // namespace Service::Time::Clock

View File

@ -1,81 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/time/standard_local_system_clock_core.h"
#include "core/hle/service/time/standard_network_system_clock_core.h"
#include "core/hle/service/time/standard_user_system_clock_core.h"
namespace Service::Time::Clock {
StandardUserSystemClockCore::StandardUserSystemClockCore(
StandardLocalSystemClockCore& local_system_clock_core_,
StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_)
: SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
local_system_clock_core{local_system_clock_core_},
network_system_clock_core{network_system_clock_core_},
auto_correction_time{SteadyClockTimePoint::GetRandom()}, service_context{
system_,
"StandardUserSystemClockCore"} {
auto_correction_event =
service_context.CreateEvent("StandardUserSystemClockCore:AutoCorrectionEvent");
}
StandardUserSystemClockCore::~StandardUserSystemClockCore() {
service_context.CloseEvent(auto_correction_event);
}
Result StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
bool value) {
if (const Result result{ApplyAutomaticCorrection(system, value)}; result != ResultSuccess) {
return result;
}
auto_correction_enabled = value;
return ResultSuccess;
}
Result StandardUserSystemClockCore::GetClockContext(Core::System& system,
SystemClockContext& ctx) const {
if (const Result result{ApplyAutomaticCorrection(system, false)}; result != ResultSuccess) {
return result;
}
return local_system_clock_core.GetClockContext(system, ctx);
}
Result StandardUserSystemClockCore::Flush(const SystemClockContext&) {
UNIMPLEMENTED();
return ERROR_NOT_IMPLEMENTED;
}
Result StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) {
UNIMPLEMENTED();
return ERROR_NOT_IMPLEMENTED;
}
Result StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system,
bool value) const {
if (auto_correction_enabled == value) {
return ResultSuccess;
}
if (!network_system_clock_core.IsClockSetup(system)) {
return ERROR_UNINITIALIZED_CLOCK;
}
SystemClockContext ctx{};
if (const Result result{network_system_clock_core.GetClockContext(system, ctx)};
result != ResultSuccess) {
return result;
}
local_system_clock_core.SetClockContext(ctx);
return ResultSuccess;
}
} // namespace Service::Time::Clock

View File

@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/system_clock_core.h"
namespace Core {
class System;
}
namespace Kernel {
class KEvent;
}
namespace Service::Time::Clock {
class StandardLocalSystemClockCore;
class StandardNetworkSystemClockCore;
class StandardUserSystemClockCore final : public SystemClockCore {
public:
StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_,
StandardNetworkSystemClockCore& network_system_clock_core_,
Core::System& system_);
~StandardUserSystemClockCore() override;
Result SetAutomaticCorrectionEnabled(Core::System& system, bool value);
Result GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
bool IsAutomaticCorrectionEnabled() const {
return auto_correction_enabled;
}
void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) {
auto_correction_time = steady_clock_time_point;
}
protected:
Result Flush(const SystemClockContext&) override;
Result SetClockContext(const SystemClockContext&) override;
Result ApplyAutomaticCorrection(Core::System& system, bool value) const;
const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const {
return auto_correction_time;
}
private:
StandardLocalSystemClockCore& local_system_clock_core;
StandardNetworkSystemClockCore& network_system_clock_core;
bool auto_correction_enabled{};
SteadyClockTimePoint auto_correction_time;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* auto_correction_event;
};
} // namespace Service::Time::Clock

View File

@ -1,55 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/uuid.h"
#include "core/hle/service/time/clock_types.h"
namespace Core {
class System;
}
namespace Service::Time::Clock {
class SteadyClockCore {
public:
SteadyClockCore() = default;
virtual ~SteadyClockCore() = default;
const Common::UUID& GetClockSourceId() const {
return clock_source_id;
}
void SetClockSourceId(const Common::UUID& value) {
clock_source_id = value;
}
virtual TimeSpanType GetInternalOffset() const = 0;
virtual void SetInternalOffset(TimeSpanType internal_offset) = 0;
virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0;
virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0;
SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) {
SteadyClockTimePoint result{GetTimePoint(system)};
result.time_point += GetInternalOffset().ToSeconds();
return result;
}
bool IsInitialized() const {
return is_initialized;
}
void MarkAsInitialized() {
is_initialized = true;
}
private:
Common::UUID clock_source_id{Common::UUID::MakeRandom()};
bool is_initialized{};
};
} // namespace Service::Time::Clock

View File

@ -1,54 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/system_clock_context_update_callback.h"
namespace Service::Time::Clock {
SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default;
SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default;
bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const {
if (has_context) {
return context.offset != value.offset ||
context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id;
}
return true;
}
void SystemClockContextUpdateCallback::RegisterOperationEvent(
std::shared_ptr<Kernel::KEvent>&& event) {
operation_event_list.emplace_back(std::move(event));
}
void SystemClockContextUpdateCallback::BroadcastOperationEvent() {
for (const auto& event : operation_event_list) {
event->Signal();
}
}
Result SystemClockContextUpdateCallback::Update(const SystemClockContext& value) {
Result result{ResultSuccess};
if (NeedUpdate(value)) {
context = value;
has_context = true;
result = Update();
if (result == ResultSuccess) {
BroadcastOperationEvent();
}
}
return result;
}
Result SystemClockContextUpdateCallback::Update() {
return ResultSuccess;
}
} // namespace Service::Time::Clock

View File

@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <vector>
#include "core/hle/service/time/clock_types.h"
namespace Kernel {
class KEvent;
}
namespace Service::Time::Clock {
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
// This code was released under public domain.
class SystemClockContextUpdateCallback {
public:
SystemClockContextUpdateCallback();
virtual ~SystemClockContextUpdateCallback();
bool NeedUpdate(const SystemClockContext& value) const;
void RegisterOperationEvent(std::shared_ptr<Kernel::KEvent>&& event);
void BroadcastOperationEvent();
Result Update(const SystemClockContext& value);
protected:
virtual Result Update();
SystemClockContext context{};
private:
bool has_context{};
std::vector<std::shared_ptr<Kernel::KEvent>> operation_event_list;
};
} // namespace Service::Time::Clock

View File

@ -1,71 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/time/steady_clock_core.h"
#include "core/hle/service/time/system_clock_context_update_callback.h"
#include "core/hle/service/time/system_clock_core.h"
namespace Service::Time::Clock {
SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
: steady_clock_core{steady_clock_core_} {
context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
}
SystemClockCore::~SystemClockCore() = default;
Result SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const {
posix_time = 0;
const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
SystemClockContext clock_context{};
if (const Result result{GetClockContext(system, clock_context)}; result != ResultSuccess) {
return result;
}
if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) {
return ERROR_TIME_MISMATCH;
}
posix_time = clock_context.offset + current_time_point.time_point;
return ResultSuccess;
}
Result SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) {
const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
const SystemClockContext clock_context{posix_time - current_time_point.time_point,
current_time_point};
if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) {
return result;
}
return Flush(clock_context);
}
Result SystemClockCore::Flush(const SystemClockContext& clock_context) {
if (!system_clock_context_update_callback) {
return ResultSuccess;
}
return system_clock_context_update_callback->Update(clock_context);
}
Result SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) {
if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) {
return result;
}
return Flush(clock_context);
}
bool SystemClockCore::IsClockSetup(Core::System& system) const {
SystemClockContext value{};
if (GetClockContext(system, value) == ResultSuccess) {
const SteadyClockTimePoint steady_clock_time_point{
steady_clock_core.GetCurrentTimePoint(system)};
return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id;
}
return {};
}
} // namespace Service::Time::Clock

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
#include "core/hle/service/time/clock_types.h"
namespace Core {
class System;
}
namespace Service::Time::Clock {
class SteadyClockCore;
class SystemClockContextUpdateCallback;
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
// This code was released under public domain.
class SystemClockCore {
public:
explicit SystemClockCore(SteadyClockCore& steady_clock_core_);
virtual ~SystemClockCore();
SteadyClockCore& GetSteadyClockCore() const {
return steady_clock_core;
}
Result GetCurrentTime(Core::System& system, s64& posix_time) const;
Result SetCurrentTime(Core::System& system, s64 posix_time);
virtual Result GetClockContext([[maybe_unused]] Core::System& system,
SystemClockContext& value) const {
value = context;
return ResultSuccess;
}
virtual Result SetClockContext(const SystemClockContext& value) {
context = value;
return ResultSuccess;
}
virtual Result Flush(const SystemClockContext& clock_context);
void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
system_clock_context_update_callback = std::move(callback);
}
Result SetSystemClockContext(const SystemClockContext& context);
bool IsInitialized() const {
return is_initialized;
}
void MarkAsInitialized() {
is_initialized = true;
}
bool IsClockSetup(Core::System& system) const;
private:
SteadyClockCore& steady_clock_core;
SystemClockContext context{};
bool is_initialized{};
std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback;
};
} // namespace Service::Time::Clock

View File

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
#include "core/hle/service/time/tick_based_steady_clock_core.h"
namespace Service::Time::Clock {
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{
TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
}
TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
return TimeSpanType::FromSeconds(GetTimePoint(system).time_point);
}
} // namespace Service::Time::Clock

View File

@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/steady_clock_core.h"
namespace Core {
class System;
}
namespace Service::Time::Clock {
class TickBasedSteadyClockCore final : public SteadyClockCore {
public:
TimeSpanType GetInternalOffset() const override {
return {};
}
void SetInternalOffset(TimeSpanType internal_offset) override {}
SteadyClockTimePoint GetTimePoint(Core::System& system) override;
TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
};
} // namespace Service::Time::Clock

View File

@ -4,29 +4,45 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_interfaces/steady_clock.h"
#include "core/hle/service/time/clock_interfaces/system_clock.h"
#include "core/hle/service/time/time.h"
#include "core/hle/service/time/time_interface.h"
#include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_sharedmemory.h"
#include "core/hle/service/time/time_zone_service.h"
#include "core/hle/service/time/time_types.h"
#include "core/hle/service/time/time_util.h"
#include "core/hle/service/time/time_zone/time_zone_service.h"
namespace Service::Time {
class ISystemClock final : public ServiceFramework<ISystemClock> {
class IStaticService final : public ServiceFramework<IStaticService> {
public:
explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_)
: ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} {
explicit IStaticService(const char* name, Core::System& system_)
: ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"},
{2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
{3, nullptr, "SetSystemClockContext"},
{4, nullptr, "GetOperationEventReadableHandle"},
{0, &IStaticService::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
{1, &IStaticService::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
{2, &IStaticService::GetStandardSteadyClock, "GetStandardSteadyClock"},
{3, &IStaticService::GetTimeZoneService, "GetTimeZoneService"},
{4, &IStaticService::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
{5, nullptr, "GetEphemeralNetworkSystemClock"},
{20, &IStaticService::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
{51, nullptr, "GetStandardSteadyClockRtcValue"},
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, &IStaticService::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
{300, &IStaticService::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
{400, &IStaticService::GetClockSnapshot, "GetClockSnapshot"},
{401, &IStaticService::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
{500, &IStaticService::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
{501, &IStaticService::CalculateSpanBetween, "CalculateSpanBetween"},
};
// clang-format on
@ -34,378 +50,273 @@ public:
}
private:
void GetCurrentTime(HLERequestContext& ctx) {
void GetStandardUserSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
return;
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(manager->GetStandardUserSystemClock());
}
void GetStandardNetworkSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(manager->GetStandardNetworkSystemClock());
}
void GetStandardSteadyClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISteadyClock>(manager->GetStandardSteadyClock());
}
void GetTimeZoneService(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ITimeZoneService>(manager->GetTimeZoneService());
}
void GetStandardLocalSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(manager->GetStandardLocalSystemClock());
}
void GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem());
}
void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& clock_core{manager->GetStandardNetworkSystemClock()};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient());
}
void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto context{rp.PopRaw<SystemClockContext>()};
LOG_DEBUG(Service_Time, "called");
Result result = ResultSuccess;
u64 base_time_point{};
SteadyClockTimePoint current_time_point{};
auto& steady_clock_core{manager->GetStandardSteadyClock()};
if (!steady_clock_core.IsInitialized()) {
result = ResultUnitializedClock;
}
s64 posix_time{};
if (const Result result{clock_core.GetCurrentTime(system, posix_time)}; result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
if (result.IsSuccess()) {
result = manager->GetCurrentTimePoint(current_time_point);
}
if (result.IsSuccess()) {
if (current_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
result = ResultTimeMismatch;
}
}
if (result.IsSuccess()) {
const auto ticks{TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
system.CoreTiming().GetClockTicks())};
base_time_point = context.offset + current_time_point.time_point - ticks.ToSeconds();
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.PushRaw(base_time_point);
}
Result GetClockSnapshotFromSystemClockContextImpl(ClockSnapshot& out_clock_snapshot,
const SystemClockContext& user_context,
const SystemClockContext& network_context,
TimeType type) {
Result result = ResultSuccess;
out_clock_snapshot.user_context = user_context;
out_clock_snapshot.network_context = network_context;
result = manager->GetCurrentTimePoint(out_clock_snapshot.steady_clock_time_point);
if (result.IsSuccess()) {
out_clock_snapshot.is_automatic_correction_enabled =
manager->IsAutomaticCorrectionEnabled();
result = manager->GetLocationName(out_clock_snapshot.location_name);
}
if (result.IsSuccess()) {
result = TimeUtil::GetCurrentTime(out_clock_snapshot.user_time,
out_clock_snapshot.steady_clock_time_point,
out_clock_snapshot.user_context);
}
if (result.IsSuccess()) {
result = manager->GetCalendarTime(out_clock_snapshot.user_calendar_time,
out_clock_snapshot.user_calendar_additional_time,
out_clock_snapshot.user_time);
}
if (result.IsSuccess()) {
const Result time_result = TimeUtil::GetCurrentTime(
out_clock_snapshot.network_time, out_clock_snapshot.steady_clock_time_point,
out_clock_snapshot.network_context);
if (time_result.IsError()) {
out_clock_snapshot.network_time = 0;
}
result = manager->GetCalendarTime(out_clock_snapshot.network_calendar_time,
out_clock_snapshot.network_calendar_additional_time,
out_clock_snapshot.network_time);
}
if (result.IsSuccess()) {
out_clock_snapshot.type = type;
}
return result;
}
void GetClockSnapshot(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<TimeType>()};
LOG_DEBUG(Service_Time, "called, type={}", type);
Result result = ResultSuccess;
SystemClockContext user_context{};
SystemClockContext network_context{};
ClockSnapshot clock_snapshot{};
result = manager->GetStandardUserSystemClock().GetClockContext(user_context);
if (result.IsSuccess()) {
result = manager->GetStandardNetworkSystemClock().GetClockContext(user_context);
}
if (result.IsSuccess()) {
result = GetClockSnapshotFromSystemClockContextImpl(clock_snapshot, user_context,
network_context, type);
}
if (result.IsSuccess()) {
ctx.WriteBuffer(clock_snapshot);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
struct params {
TimeType type;
};
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<TimeType>()};
rp.Skip(1, false);
const SystemClockContext user_context{rp.PopRaw<SystemClockContext>()};
const SystemClockContext network_context{rp.PopRaw<SystemClockContext>()};
LOG_DEBUG(Service_Time, "called, type={}", type);
ClockSnapshot clock_snapshot{};
const auto result = GetClockSnapshotFromSystemClockContextImpl(clock_snapshot, user_context,
network_context, type);
if (result.IsSuccess()) {
ctx.WriteBuffer(clock_snapshot);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) {
const auto snapshot_a_data = ctx.ReadBuffer(0);
const auto snapshot_b_data = ctx.ReadBuffer(1);
ClockSnapshot snapshot_a;
ClockSnapshot snapshot_b;
std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(ClockSnapshot));
std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(ClockSnapshot));
LOG_DEBUG(Service_Time, "called");
auto time_span = TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
snapshot_a.user_context.offset);
if (snapshot_a.user_context.steady_time_point.clock_source_id !=
snapshot_b.user_context.steady_time_point.clock_source_id) {
time_span = {};
}
if (snapshot_a.is_automatic_correction_enabled &&
snapshot_b.is_automatic_correction_enabled) {
if (snapshot_a.network_context.steady_time_point.clock_source_id ==
snapshot_a.steady_clock_time_point.clock_source_id) {
time_span = {};
}
if (snapshot_b.network_context.steady_time_point.clock_source_id ==
snapshot_b.steady_clock_time_point.clock_source_id) {
time_span = {};
}
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s64>(posix_time);
rb.PushRaw(time_span.nanoseconds);
}
void GetSystemClockContext(HLERequestContext& ctx) {
void CalculateSpanBetween(HLERequestContext& ctx) {
const auto snapshot_a_data = ctx.ReadBuffer(0);
const auto snapshot_b_data = ctx.ReadBuffer(1);
ClockSnapshot snapshot_a;
ClockSnapshot snapshot_b;
std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(ClockSnapshot));
std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(ClockSnapshot));
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
return;
TimeSpanType time_span{};
Result result = TimeUtil::GetSpanBetween(time_span, snapshot_a.steady_clock_time_point,
snapshot_b.steady_clock_time_point);
if (result.IsError()) {
result = ResultTimeNotFound;
if (snapshot_a.network_time != 0 && snapshot_b.network_time != 0) {
time_span = {snapshot_b.network_time - snapshot_a.network_time};
result = ResultSuccess;
}
}
Clock::SystemClockContext system_clock_context{};
if (const Result result{clock_core.GetClockContext(system, system_clock_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2};
rb.Push(ResultSuccess);
rb.PushRaw(system_clock_context);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.PushRaw(time_span.nanoseconds);
}
Clock::SystemClockCore& clock_core;
std::shared_ptr<TimeManager> manager;
};
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public:
explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_)
: ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} {
static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
{2, nullptr, "GetTestOffset"},
{3, nullptr, "SetTestOffset"},
{100, nullptr, "GetRtcValue"},
{101, nullptr, "IsRtcResetDetected"},
{102, nullptr, "GetSetupResultValue"},
{200, nullptr, "GetInternalOffset"},
{201, nullptr, "SetInternalOffset"},
};
RegisterHandlers(functions);
}
private:
void GetCurrentTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
return;
}
const Clock::SteadyClockTimePoint time_point{clock_core.GetCurrentTimePoint(system)};
IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2};
rb.Push(ResultSuccess);
rb.PushRaw(time_point);
}
Clock::SteadyClockCore& clock_core;
};
Result Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
Kernel::KThread* thread, Clock::SystemClockContext user_context,
Clock::SystemClockContext network_context, Clock::TimeType type,
Clock::ClockSnapshot& clock_snapshot) {
auto& time_manager{system.GetTimeManager()};
clock_snapshot.steady_clock_time_point =
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system);
clock_snapshot.is_automatic_correction_enabled =
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
clock_snapshot.type = type;
if (const Result result{
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
clock_snapshot.location_name)};
result != ResultSuccess) {
return result;
}
clock_snapshot.user_context = user_context;
if (const Result result{Clock::ClockSnapshot::GetCurrentTime(
clock_snapshot.user_time, clock_snapshot.steady_clock_time_point,
clock_snapshot.user_context)};
result != ResultSuccess) {
return result;
}
TimeZone::CalendarInfo userCalendarInfo{};
if (const Result result{
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
clock_snapshot.user_time, userCalendarInfo)};
result != ResultSuccess) {
return result;
}
clock_snapshot.user_calendar_time = userCalendarInfo.time;
clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info;
clock_snapshot.network_context = network_context;
if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time,
clock_snapshot.steady_clock_time_point,
clock_snapshot.network_context) != ResultSuccess) {
clock_snapshot.network_time = 0;
}
TimeZone::CalendarInfo networkCalendarInfo{};
if (const Result result{
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
clock_snapshot.network_time, networkCalendarInfo)};
result != ResultSuccess) {
return result;
}
clock_snapshot.network_calendar_time = networkCalendarInfo.time;
clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info;
return ResultSuccess;
}
void Module::Interface::GetStandardUserSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
system);
}
void Module::Interface::GetStandardNetworkSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
system);
}
void Module::Interface::GetStandardSteadyClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
}
void Module::Interface::GetTimeZoneService(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ITimeZoneService>(system,
system.GetTimeManager().GetTimeZoneContentManager());
}
void Module::Interface::GetStandardLocalSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
system);
}
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
}
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
if (!steady_clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
return;
}
IPC::RequestParser rp{ctx};
const auto context{rp.PopRaw<Clock::SystemClockContext>()};
const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
system.CoreTiming().GetClockTicks())};
const s64 base_time_point{context.offset + current_time_point.time_point -
ticks.ToSeconds()};
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
rb.Push(ResultSuccess);
rb.PushRaw(base_time_point);
return;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_TIME_MISMATCH);
}
void Module::Interface::GetClockSnapshot(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<Clock::TimeType>()};
LOG_DEBUG(Service_Time, "called, type={}", type);
Clock::SystemClockContext user_context{};
if (const Result result{
system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
user_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
Clock::SystemClockContext network_context{};
if (const Result result{
system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
system, network_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
Clock::ClockSnapshot clock_snapshot{};
if (const Result result{GetClockSnapshotFromSystemClockContextInternal(
&ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(clock_snapshot);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Module::Interface::GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<Clock::TimeType>()};
rp.Skip(1, false);
const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
LOG_DEBUG(Service_Time, "called, type={}", type);
Clock::ClockSnapshot clock_snapshot{};
if (const Result result{GetClockSnapshotFromSystemClockContextInternal(
&ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(clock_snapshot);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
Clock::ClockSnapshot snapshot_a;
Clock::ClockSnapshot snapshot_b;
const auto snapshot_a_data = ctx.ReadBuffer(0);
const auto snapshot_b_data = ctx.ReadBuffer(1);
std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
snapshot_a.user_context.offset)};
if ((snapshot_b.user_context.steady_time_point.clock_source_id !=
snapshot_a.user_context.steady_time_point.clock_source_id) ||
(snapshot_b.is_automatic_correction_enabled &&
snapshot_a.is_automatic_correction_enabled)) {
time_span_type.nanoseconds = 0;
}
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
rb.Push(ResultSuccess);
rb.PushRaw(time_span_type.nanoseconds);
}
void Module::Interface::CalculateSpanBetween(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
Clock::ClockSnapshot snapshot_a;
Clock::ClockSnapshot snapshot_b;
const auto snapshot_a_data = ctx.ReadBuffer(0);
const auto snapshot_b_data = ctx.ReadBuffer(1);
std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
Clock::TimeSpanType time_span_type{};
s64 span{};
if (const Result result{snapshot_a.steady_clock_time_point.GetSpanBetween(
snapshot_b.steady_clock_time_point, span)};
result != ResultSuccess) {
if (snapshot_a.network_time && snapshot_b.network_time) {
time_span_type =
Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_TIME_NOT_FOUND);
return;
}
} else {
time_span_type = Clock::TimeSpanType::FromSeconds(span);
}
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
rb.Push(ResultSuccess);
rb.PushRaw(time_span_type.nanoseconds);
}
void Module::Interface::GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem());
}
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
const char* name)
: ServiceFramework{system_, name}, module{std::move(module_)} {}
Module::Interface::~Interface() = default;
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
auto module{std::make_shared<Module>()};
server_manager->RegisterNamedService("time:a",
std::make_shared<Time>(module, system, "time:a"));
std::make_shared<IStaticService>("time:a", system));
server_manager->RegisterNamedService("time:s",
std::make_shared<Time>(module, system, "time:s"));
std::make_shared<IStaticService>("time:s", system));
server_manager->RegisterNamedService("time:u",
std::make_shared<Time>(module, system, "time:u"));
std::make_shared<IStaticService>("time:u", system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -3,49 +3,12 @@
#pragma once
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Core {
class System;
}
namespace Service::Time {
class Module final {
public:
Module() = default;
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
const char* name);
~Interface() override;
void GetStandardUserSystemClock(HLERequestContext& ctx);
void GetStandardNetworkSystemClock(HLERequestContext& ctx);
void GetStandardSteadyClock(HLERequestContext& ctx);
void GetTimeZoneService(HLERequestContext& ctx);
void GetStandardLocalSystemClock(HLERequestContext& ctx);
void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
void GetClockSnapshot(HLERequestContext& ctx);
void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
void CalculateSpanBetween(HLERequestContext& ctx);
void GetSharedMemoryNativeHandle(HLERequestContext& ctx);
private:
Result GetClockSnapshotFromSystemClockContextInternal(
Kernel::KThread* thread, Clock::SystemClockContext user_context,
Clock::SystemClockContext network_context, Clock::TimeType type,
Clock::ClockSnapshot& cloc_snapshot);
protected:
std::shared_ptr<Module> module;
};
};
void LoopProcess(Core::System& system);
} // namespace Service::Time

View File

@ -1,41 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/time/time_interface.h"
namespace Service::Time {
Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_)
: Interface{std::move(module_), system_, name_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
{1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
{2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"},
{3, &Time::GetTimeZoneService, "GetTimeZoneService"},
{4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
{5, nullptr, "GetEphemeralNetworkSystemClock"},
{20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
{30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
{51, nullptr, "GetStandardSteadyClockRtcValue"},
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
{300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
{400, &Time::GetClockSnapshot, "GetClockSnapshot"},
{401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
{500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
{501, &Time::CalculateSpanBetween, "CalculateSpanBetween"},
};
// clang-format on
RegisterHandlers(functions);
}
Time::~Time() = default;
} // namespace Service::Time

View File

@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/time.h"
namespace Core {
class System;
}
namespace Service::Time {
class Time final : public Module::Interface {
public:
explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_);
~Time() override;
};
} // namespace Service::Time

View File

@ -1,293 +1,99 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <ctime>
#include "common/settings.h"
#include "common/time_zone.h"
#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
#include "core/hle/service/time/local_system_clock_context_writer.h"
#include "core/hle/service/time/network_system_clock_context_writer.h"
#include "core/hle/service/time/tick_based_steady_clock_core.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/time/time_manager.h"
#include "core/core_timing.h"
namespace Service::Time {
namespace {
constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL};
constexpr auto time_update_ns =
std::chrono::nanoseconds{5ull * 60 * 1000 * 1000 * 1000}; // (5 minutes)
s64 GetSecondsSinceEpoch() {
const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() +
Settings::values.custom_rtc_differential;
TimeManager::TimeManager(Core::System& system_) : time_zone_service{system_}, system{system_} {
// Register update callbacks
time_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
UpdateTime();
return std::nullopt;
});
system.CoreTiming().ScheduleLoopingEvent(time_update_ns, time_update_ns, time_update_event);
}
} // Anonymous namespace
struct TimeManager::Impl final {
explicit Impl(Core::System& system)
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
standard_network_system_clock_core{standard_steady_clock_core},
standard_user_system_clock_core{standard_local_system_clock_core,
standard_network_system_clock_core, system},
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
local_system_clock_context_writer{
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
network_system_clock_context_writer{
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
ephemeral_network_system_clock_context_writer{
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())};
SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
Clock::SystemClockContext clock_context{};
standard_local_system_clock_core.GetClockContext(system, clock_context);
SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
~Impl() = default;
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
return standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
return standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
return standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
return standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
return standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
return standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
return standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
return standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
return time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
return time_zone_content_manager;
}
SharedMemory& GetSharedMemory() {
return shared_memory;
}
const SharedMemory& GetSharedMemory() const {
return shared_memory;
}
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::vector<std::string> location_names, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != ResultSuccess) {
ASSERT(false);
return;
}
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
location_names.size());
time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
standard_steady_clock_core.SetSetupValue(setup_value);
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)};
shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point);
}
void SetupStandardLocalSystemClock(Core::System& system_,
Clock::SystemClockContext clock_context, s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(
local_system_clock_context_writer);
const auto current_time_point{
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) !=
ResultSuccess) {
ASSERT(false);
return;
}
}
standard_local_system_clock_core.MarkAsInitialized();
}
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy) {
standard_network_system_clock_core.SetUpdateCallbackInstance(
network_system_clock_context_writer);
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
ResultSuccess) {
ASSERT(false);
return;
}
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
sufficient_accuracy);
standard_network_system_clock_core.MarkAsInitialized();
}
void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
system_, is_automatic_correction_enabled) != ResultSuccess) {
ASSERT(false);
return;
}
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
standard_user_system_clock_core.MarkAsInitialized();
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
}
void SetupEphemeralNetworkSystemClock() {
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
ephemeral_network_system_clock_context_writer);
ephemeral_network_system_clock_core.MarkAsInitialized();
}
void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) {
const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)};
if (GetStandardLocalSystemClockCore()
.SetCurrentTime(system_, timespan.ToSeconds())
.IsError()) {
ASSERT(false);
return;
}
}
SharedMemory shared_memory;
Clock::StandardSteadyClockCore standard_steady_clock_core;
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
ephemeral_network_system_clock_context_writer;
TimeZone::TimeZoneContentManager time_zone_content_manager;
TimeManager::~TimeManager() {
system.CoreTiming().UnscheduleEvent(time_update_event, 0);
};
TimeManager::TimeManager(Core::System& system_) : system{system_} {}
TimeManager::~TimeManager() = default;
void TimeManager::Initialize() {
impl = std::make_unique<Impl>(system);
// Time zones can only be initialized after impl is valid
impl->time_zone_content_manager.Initialize(*this);
void TimeManager::UpdateTime() {
steady_clock.UpdateTime();
local_system_clock.UpdateTime();
network_system_clock.UpdateTime();
user_system_clock.UpdateTime();
time_zone_service.UpdateTime();
}
Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
return impl->standard_steady_clock_core;
bool TimeManager::IsAutomaticCorrectionEnabled() const {
return false;
}
const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
return impl->standard_steady_clock_core;
Result TimeManager::GetCurrentTimePoint(SteadyClockTimePoint& out_steady_time_point) const {
return ResultSuccess;
}
Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
return impl->standard_local_system_clock_core;
Result TimeManager::GetLocationName(TimeZone::LocationName& out_name) const {
return ResultSuccess;
}
const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
return impl->standard_local_system_clock_core;
Result TimeManager::GetCalendarTime(TimeZone::CalendarTime& out_calendar_time,
TimeZone::CalendarAdditionalInfo& out_calendar_aditional_info,
s64 time) const {
return ResultSuccess;
}
Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
return impl->standard_network_system_clock_core;
SteadyClock& TimeManager::GetStandardSteadyClock() {
return steady_clock;
}
const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
const {
return impl->standard_network_system_clock_core;
const SteadyClock& TimeManager::GetStandardSteadyClock() const {
return steady_clock;
}
Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
return impl->standard_user_system_clock_core;
LocalSystemClock& TimeManager::GetStandardLocalSystemClock() {
return local_system_clock;
}
const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
return impl->standard_user_system_clock_core;
const LocalSystemClock& TimeManager::GetStandardLocalSystemClock() const {
return local_system_clock;
}
TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
return impl->time_zone_content_manager;
NetworkSystemClock& TimeManager::GetStandardNetworkSystemClock() {
return network_system_clock;
}
const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
return impl->time_zone_content_manager;
const NetworkSystemClock& TimeManager::GetStandardNetworkSystemClock() const {
return network_system_clock;
}
SharedMemory& TimeManager::GetSharedMemory() {
return impl->shared_memory;
UserSystemClock& TimeManager::GetStandardUserSystemClock() {
return user_system_clock;
}
const SharedMemory& TimeManager::GetSharedMemory() const {
return impl->shared_memory;
const UserSystemClock& TimeManager::GetStandardUserSystemClock() const {
return user_system_clock;
}
void TimeManager::Shutdown() {
impl.reset();
ITimeZoneService& TimeManager::GetTimeZoneService() {
return time_zone_service;
}
void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
impl->UpdateLocalSystemClockTime(system, posix_time);
const ITimeZoneService& TimeManager::GetTimeZoneService() const {
return time_zone_service;
}
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::vector<std::string> location_names,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names,
time_zone_rule_version, vfs_file);
}
} // namespace Service::Time

View File

@ -1,74 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/standard_local_system_clock_core.h"
#include "core/hle/service/time/standard_network_system_clock_core.h"
#include "core/hle/service/time/standard_steady_clock_core.h"
#include "core/hle/service/time/standard_user_system_clock_core.h"
#include "core/hle/service/time/time_sharedmemory.h"
#include "core/hle/service/time/time_zone_content_manager.h"
#include "core/hle/service/time/clock_types/local_system_clock.h"
#include "core/hle/service/time/clock_types/network_system_clock.h"
#include "core/hle/service/time/clock_types/steady_clock.h"
#include "core/hle/service/time/clock_types/user_system_clock.h"
#include "core/hle/service/time/time_types.h"
#include "core/hle/service/time/time_zone/time_zone_service.h"
namespace Core {
class System;
}
namespace Service::Time {
namespace Clock {
class EphemeralNetworkSystemClockContextWriter;
class LocalSystemClockContextWriter;
class NetworkSystemClockContextWriter;
} // namespace Clock
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
// This code was released under public domain.
class TimeManager final {
class TimeManager {
public:
explicit TimeManager(Core::System& system_);
~TimeManager();
void Initialize();
bool IsAutomaticCorrectionEnabled() const;
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
Result GetCurrentTimePoint(SteadyClockTimePoint& out_steady_time_point) const;
Result GetLocationName(TimeZone::LocationName& out_name) const;
Result GetCalendarTime(TimeZone::CalendarTime& out_calendar_time,
TimeZone::CalendarAdditionalInfo& out_calendar_aditional_info,
s64 time) const;
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
SteadyClock& GetStandardSteadyClock();
const SteadyClock& GetStandardSteadyClock() const;
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
LocalSystemClock& GetStandardLocalSystemClock();
const LocalSystemClock& GetStandardLocalSystemClock() const;
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
NetworkSystemClock& GetStandardNetworkSystemClock();
const NetworkSystemClock& GetStandardNetworkSystemClock() const;
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
UserSystemClock& GetStandardUserSystemClock();
const UserSystemClock& GetStandardUserSystemClock() const;
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
void UpdateLocalSystemClockTime(s64 posix_time);
SharedMemory& GetSharedMemory();
const SharedMemory& GetSharedMemory() const;
void Shutdown();
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::vector<std::string> location_names, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file);
ITimeZoneService& GetTimeZoneService();
const ITimeZoneService& GetTimeZoneService() const;
private:
Core::System& system;
void UpdateTime();
struct Impl;
std::unique_ptr<Impl> impl;
std::shared_ptr<Core::Timing::EventType> time_update_event;
SteadyClock steady_clock;
LocalSystemClock local_system_clock;
NetworkSystemClock network_system_clock;
UserSystemClock user_system_clock;
ITimeZoneService time_zone_service;
Core::System& system;
};
} // namespace Service::Time

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::Time {
constexpr Result ResultPermissionDenied{ErrorModule::Time, 1};
constexpr Result ResultTimeMismatch{ErrorModule::Time, 102};
constexpr Result ResultUnitializedClock{ErrorModule::Time, 103};
constexpr Result ResultTimeNotFound{ErrorModule::Time, 200};
constexpr Result ResultOverflow{ErrorModule::Time, 201};
constexpr Result ResultLocationNameTooLong{ErrorModule::Time, 801};
constexpr Result ResultOutOfRange{ErrorModule::Time, 902};
constexpr Result ResutTimeConversionFailed{ErrorModule::Time, 903};
constexpr Result ResultTimezoneNotFound{ErrorModule::Time, 989};
constexpr Result ResultNotImplemented{ErrorModule::Time, 990};
} // namespace Service::Time

View File

@ -1,69 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/steady_clock_core.h"
#include "core/hle/service/time/time_sharedmemory.h"
namespace Service::Time {
static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
SharedMemory::SharedMemory(Core::System& system_) : system(system_) {
std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE);
}
SharedMemory::~SharedMemory() = default;
void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
Clock::TimeSpanType current_time_point) {
const Clock::TimeSpanType ticks_time_span{
Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
system.CoreTiming().GetClockTicks())};
const Clock::SteadyClockContext context{
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
clock_source_id};
StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context);
}
void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
// lower and upper are related to the measurement point for the steady time point,
// and compare equal on boot
const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL;
// This adjusts for some sort of time skew
// Both 0 on boot
const s64 diff_scale = 0;
const u32 shift_amount = 0;
const Clock::ContinuousAdjustmentTimePoint adjustment{
.measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(),
.diff_scale = diff_scale,
.shift_amount = shift_amount,
.lower = time_point_ns,
.upper = time_point_ns,
.clock_source_id = context.steady_time_point.clock_source_id,
};
StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment);
StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
}
void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context);
}
void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
StoreToLockFreeAtomicType(
&GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled);
}
SharedMemory::Format* SharedMemory::GetFormat() {
return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer());
}
} // namespace Service::Time

View File

@ -1,89 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Time {
// Note: this type is not safe for concurrent writes.
template <typename T>
struct LockFreeAtomicType {
u32 counter_;
std::array<T, 2> value_;
};
template <typename T>
static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
// Get the current counter.
auto counter = p->counter_;
// Increment the counter.
++counter;
// Store the updated value.
p->value_[counter % 2] = value;
// Fence memory.
std::atomic_thread_fence(std::memory_order_release);
// Set the updated counter.
p->counter_ = counter;
}
template <typename T>
static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
while (true) {
// Get the counter.
auto counter = p->counter_;
// Get the value.
auto value = p->value_[counter % 2];
// Fence memory.
std::atomic_thread_fence(std::memory_order_acquire);
// Check that the counter matches.
if (counter == p->counter_) {
return value;
}
}
}
class SharedMemory final {
public:
explicit SharedMemory(Core::System& system_);
~SharedMemory();
// Shared memory format
struct Format {
LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint;
LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint;
};
static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
0xc8);
static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0);
static_assert(sizeof(Format) == 0x148, "Format is an invalid size");
void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
Clock::TimeSpanType current_time_point);
void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
void SetAutomaticCorrectionEnabled(bool is_enabled);
Format* GetFormat();
private:
Core::System& system;
};
} // namespace Service::Time

View File

@ -8,10 +8,10 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/time_zone_types.h"
#include "core/hle/service/time/time_result.h"
#include "core/hle/service/time/time_zone/time_zone_types.h"
namespace Service::Time::Clock {
namespace Service::Time {
enum class TimeType : u8 {
UserSystemClock,
@ -24,18 +24,6 @@ struct SteadyClockTimePoint {
s64 time_point;
Common::UUID clock_source_id;
Result GetSpanBetween(SteadyClockTimePoint other, s64& span) const {
span = 0;
if (clock_source_id != other.clock_source_id) {
return ERROR_TIME_MISMATCH;
}
span = other.time_point - time_point;
return ResultSuccess;
}
static SteadyClockTimePoint GetRandom() {
return {0, Common::UUID::MakeRandom()};
}
@ -107,18 +95,7 @@ struct ClockSnapshot {
u8 is_automatic_correction_enabled;
TimeType type;
INSERT_PADDING_BYTES_NOINIT(0x2);
static Result GetCurrentTime(s64& current_time,
const SteadyClockTimePoint& steady_clock_time_point,
const SystemClockContext& context) {
if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
current_time = 0;
return ERROR_TIME_MISMATCH;
}
current_time = steady_clock_time_point.time_point + context.offset;
return ResultSuccess;
}
};
static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size");
} // namespace Service::Time::Clock
} // namespace Service::Time

View File

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/time/time_result.h"
#include "core/hle/service/time/time_types.h"
namespace Service::Time::TimeUtil {
bool IsSubstractionOverflow(const SteadyClockTimePoint& a, const SteadyClockTimePoint& b) {
return (b.time_point < 0) && (a.time_point > std::numeric_limits<s64>::max() + b.time_point);
}
Result GetSpanBetween(TimeSpanType& out_time_span, const SteadyClockTimePoint& time_point_a,
const SteadyClockTimePoint& time_point_b) {
if (time_point_a.clock_source_id != time_point_b.clock_source_id) {
return ResultTimeNotFound;
}
if (IsSubstractionOverflow(time_point_a, time_point_b)) {
return ResultOverflow;
}
out_time_span = {time_point_b.time_point - time_point_a.time_point};
return ResultSuccess;
}
Result GetCurrentTime(s64& out_current_time, const SteadyClockTimePoint& steady_clock_time_point,
const SystemClockContext& context) {
if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
out_current_time = 0;
return ResultTimeMismatch;
}
out_current_time = steady_clock_time_point.time_point + context.offset;
return ResultSuccess;
}
} // namespace Service::Time::TimeUtil

View File

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/time/time_zone/time_zone_service.h"
namespace Service::Time {
ITimeZoneService::ITimeZoneService(Core::System& system_)
: ServiceFramework{system_, "ITimeZoneService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
{1, nullptr, "SetDeviceLocationName"},
{2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
{3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
{6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
{202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
// clang-format on
RegisterHandlers(functions);
}
ITimeZoneService::~ITimeZoneService() = default;
} // namespace Service::Time

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@ -11,14 +11,12 @@ class System;
namespace Service::Time {
namespace TimeZone {
class TimeZoneContentManager;
}
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
class ITimeZoneService : public ServiceFramework<ITimeZoneService> {
public:
explicit ITimeZoneService(Core::System& system_,
TimeZone::TimeZoneContentManager& time_zone_manager_);
explicit ITimeZoneService(Core::System& system_);
~ITimeZoneService();
void UpdateTime();
private:
void GetDeviceLocationName(HLERequestContext& ctx);
@ -30,9 +28,6 @@ private:
void ToCalendarTimeWithMyRule(HLERequestContext& ctx);
void ToPosixTime(HLERequestContext& ctx);
void ToPosixTimeWithMyRule(HLERequestContext& ctx);
private:
TimeZone::TimeZoneContentManager& time_zone_content_manager;
};
} // namespace Service::Time

View File

@ -1,151 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <sstream>
#include <utility>
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/time_zone.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#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.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_zone_content_manager.h"
namespace Service::Time::TimeZone {
constexpr u64 time_zone_binary_titleid{0x010000000000080E};
static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) {
const auto* nand{system.GetFileSystemController().GetSystemNANDContents()};
const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)};
FileSys::VirtualFile romfs;
if (nca) {
romfs = nca->GetRomFS();
}
if (!romfs) {
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid);
}
if (!romfs) {
LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid);
return {};
}
return FileSys::ExtractRomFS(romfs);
}
static std::vector<std::string> BuildLocationNameCache(
const FileSys::VirtualDir& time_zone_binary) {
if (!time_zone_binary) {
LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
return {};
}
const FileSys::VirtualFile binary_list{time_zone_binary->GetFile("binaryList.txt")};
if (!binary_list) {
LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid);
return {};
}
std::vector<char> raw_data(binary_list->GetSize() + 1);
binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
std::stringstream data_stream{raw_data.data()};
std::string name;
std::vector<std::string> location_name_cache;
while (std::getline(data_stream, name)) {
name.pop_back(); // Remove carriage return
location_name_cache.emplace_back(std::move(name));
}
return location_name_cache;
}
TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
: system{system_}, time_zone_binary{GetTimeZoneBinary(system)},
location_name_cache{BuildLocationNameCache(time_zone_binary)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
const auto timezone_setting =
Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
if (FileSys::VirtualFile vfs_file;
GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {
const auto time_point{
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {},
vfs_file);
} else {
time_zone_manager.MarkAsInitialized();
}
}
Result TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules,
const std::string& location_name) const {
FileSys::VirtualFile vfs_file;
if (const Result result{GetTimeZoneInfoFile(location_name, vfs_file)};
result != ResultSuccess) {
return result;
}
return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file);
}
bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const {
return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) !=
location_name_cache.end();
}
Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name,
FileSys::VirtualFile& vfs_file) const {
if (!IsLocationNameValid(location_name)) {
return ERROR_TIME_NOT_FOUND;
}
if (!time_zone_binary) {
LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
return ERROR_TIME_NOT_FOUND;
}
const FileSys::VirtualDir zoneinfo_dir{time_zone_binary->GetSubdirectory("zoneinfo")};
if (!zoneinfo_dir) {
LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid);
return ERROR_TIME_NOT_FOUND;
}
vfs_file = zoneinfo_dir->GetFileRelative(location_name);
if (!vfs_file) {
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.",
time_zone_binary_titleid, location_name);
const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()};
vfs_file = zoneinfo_dir->GetFile(system_time_zone);
}
if (!vfs_file) {
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
time_zone_binary_titleid, location_name);
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
}
if (!vfs_file) {
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
location_name);
return ERROR_TIME_NOT_FOUND;
}
return ResultSuccess;
}
} // namespace Service::Time::TimeZone

View File

@ -1,49 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <vector>
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/time/time_zone_manager.h"
namespace Core {
class System;
}
namespace Service::Time {
class TimeManager;
}
namespace Service::Time::TimeZone {
class TimeZoneContentManager final {
public:
explicit TimeZoneContentManager(Core::System& system_);
void Initialize(TimeManager& time_manager);
TimeZoneManager& GetTimeZoneManager() {
return time_zone_manager;
}
const TimeZoneManager& GetTimeZoneManager() const {
return time_zone_manager;
}
Result LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const;
private:
bool IsLocationNameValid(const std::string& location_name) const;
Result GetTimeZoneInfoFile(const std::string& location_name,
FileSys::VirtualFile& vfs_file) const;
Core::System& system;
TimeZoneManager time_zone_manager;
const FileSys::VirtualDir time_zone_binary;
const std::vector<std::string> location_name_cache;
};
} // namespace Service::Time::TimeZone

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_zone_types.h"
namespace Service::Time::TimeZone {
class TimeZoneManager final {
public:
TimeZoneManager();
~TimeZoneManager();
void SetTotalLocationNameCount(std::size_t value) {
total_location_name_count = value;
}
void SetLocationNames(std::vector<std::string> location_names) {
total_location_names = location_names;
}
void SetTimeZoneRuleVersion(const u128& value) {
time_zone_rule_version = value;
}
void MarkAsInitialized() {
is_initialized = true;
}
Result SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
FileSys::VirtualFile& vfs_file);
Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value);
Result GetDeviceLocationName(TimeZone::LocationName& value) const;
Result GetTotalLocationNameCount(s32& count) const;
Result GetTimeZoneRuleVersion(u128& version) const;
Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const;
Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const;
Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const;
Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const;
Result ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time,
s64& posix_time) const;
Result ToPosixTimeWithMyRule(const CalendarTime& calendar_time, s64& posix_time) const;
private:
bool is_initialized{};
TimeZoneRule time_zone_rule{};
std::string device_location_name{"GMT"};
u128 time_zone_rule_version{};
std::size_t total_location_name_count{};
std::vector<std::string> total_location_names{};
Clock::SteadyClockTimePoint time_zone_update_time_point{
Clock::SteadyClockTimePoint::GetRandom()};
};
} // namespace Service::Time::TimeZone

View File

@ -1,217 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/time/time_zone_content_manager.h"
#include "core/hle/service/time/time_zone_service.h"
#include "core/hle/service/time/time_zone_types.h"
namespace Service::Time {
ITimeZoneService::ITimeZoneService(Core::System& system_,
TimeZone::TimeZoneContentManager& time_zone_manager_)
: ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} {
static const FunctionInfo functions[] = {
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
{1, nullptr, "SetDeviceLocationName"},
{2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
{3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
{6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
{202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
RegisterHandlers(functions);
}
void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
TimeZone::LocationName location_name{};
if (const Result result{
time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2};
rb.Push(ResultSuccess);
rb.PushRaw(location_name);
}
void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
s32 count{};
if (const Result result{
time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(count);
}
void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
std::vector<TimeZone::LocationName> location_names{};
if (const Result result{
time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(location_names);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<s32>(location_names.size()));
}
void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
u128 rule_version{};
if (const Result result{
time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(rule_version);
}
void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()};
std::string location_name;
for (const auto& byte : raw_location_name) {
// Strip extra bytes
if (byte == '\0') {
break;
}
location_name.push_back(byte);
}
LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
TimeZone::TimeZoneRule time_zone_rule{};
const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
ctx.WriteBuffer(time_zone_rule_outbuffer);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto posix_time{rp.Pop<s64>()};
LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
TimeZone::TimeZoneRule time_zone_rule{};
const auto buffer{ctx.ReadBuffer()};
std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
TimeZone::CalendarInfo calendar_info{};
if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime(
time_zone_rule, posix_time, calendar_info)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
rb.Push(ResultSuccess);
rb.PushRaw(calendar_info);
}
void ITimeZoneService::ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto posix_time{rp.Pop<s64>()};
LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
TimeZone::CalendarInfo calendar_info{};
if (const Result result{
time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules(
posix_time, calendar_info)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
rb.Push(ResultSuccess);
rb.PushRaw(calendar_info);
}
void ITimeZoneService::ToPosixTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
TimeZone::TimeZoneRule time_zone_rule{};
std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule));
s64 posix_time{};
if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime(
time_zone_rule, calendar_time, posix_time)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(posix_time);
// TODO(bunnei): Handle multiple times
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw<u32>(1); // Number of times we're returning
}
void ITimeZoneService::ToPosixTimeWithMyRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
s64 posix_time{};
if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTimeWithMyRule(
calendar_time, posix_time)};
result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(posix_time);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw<u32>(1); // Number of times we're returning
}
} // namespace Service::Time

View File

@ -14,7 +14,6 @@
#include <QMessageBox>
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/time/time_manager.h"
#include "ui_configure_system.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configuration_shared.h"