Compare commits
2 Commits
master
...
im_steady_
Author | SHA1 | Date |
---|---|---|
german77 | 47a469804b | |
german77 | 3c3ca709de |
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue