// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/glue/time/file_timestamp_worker.h" #include "core/hle/service/glue/time/static.h" #include "core/hle/service/psc/time/errors.h" #include "core/hle/service/psc/time/service_manager.h" #include "core/hle/service/psc/time/static.h" #include "core/hle/service/psc/time/steady_clock.h" #include "core/hle/service/psc/time/system_clock.h" #include "core/hle/service/psc/time/time_zone_service.h" #include "core/hle/service/set/system_settings_server.h" #include "core/hle/service/sm/sm.h" namespace Service::Glue::Time { namespace { template T GetSettingsItemValue(std::shared_ptr& set_sys, const char* category, const char* name) { std::vector interval_buf; auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); ASSERT(res == ResultSuccess); T v{}; std::memcpy(&v, interval_buf.data(), sizeof(T)); return v; } } // namespace StaticService::StaticService(Core::System& system_, Service::PSC::Time::StaticServiceSetupInfo setup_info, std::shared_ptr time, const char* name) : ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m}, m_setup_info{setup_info}, m_time_sm{time->m_time_sm}, m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{ time->m_steady_clock_resource} { // clang-format off static const FunctionInfo functions[] = { {0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"}, {1, D<&StaticService::GetStandardNetworkSystemClock>, "GetStandardNetworkSystemClock"}, {2, D<&StaticService::GetStandardSteadyClock>, "GetStandardSteadyClock"}, {3, D<&StaticService::GetTimeZoneService>, "GetTimeZoneService"}, {4, D<&StaticService::GetStandardLocalSystemClock>, "GetStandardLocalSystemClock"}, {5, D<&StaticService::GetEphemeralNetworkSystemClock>, "GetEphemeralNetworkSystemClock"}, {20, D<&StaticService::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"}, {50, D<&StaticService::SetStandardSteadyClockInternalOffset>, "SetStandardSteadyClockInternalOffset"}, {51, D<&StaticService::GetStandardSteadyClockRtcValue>, "GetStandardSteadyClockRtcValue"}, {100, D<&StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled>, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, {101, D<&StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled>, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, {102, D<&StaticService::GetStandardUserSystemClockInitialYear>, "GetStandardUserSystemClockInitialYear"}, {200, D<&StaticService::IsStandardNetworkSystemClockAccuracySufficient>, "IsStandardNetworkSystemClockAccuracySufficient"}, {201, D<&StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime>, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, {300, D<&StaticService::CalculateMonotonicSystemClockBaseTimePoint>, "CalculateMonotonicSystemClockBaseTimePoint"}, {400, D<&StaticService::GetClockSnapshot>, "GetClockSnapshot"}, {401, D<&StaticService::GetClockSnapshotFromSystemClockContext>, "GetClockSnapshotFromSystemClockContext"}, {500, D<&StaticService::CalculateStandardUserSystemClockDifferenceByUser>, "CalculateStandardUserSystemClockDifferenceByUser"}, {501, D<&StaticService::CalculateSpanBetween>, "CalculateSpanBetween"}, }; // clang-format on RegisterHandlers(functions); m_set_sys = m_system.ServiceManager().GetService("set:sys", true); if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock && !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location && !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { m_time_m->GetStaticServiceAsAdmin(&m_wrapped_service); } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && !m_setup_info.can_write_network_clock && !m_setup_info.can_write_timezone_device_location && !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { m_time_m->GetStaticServiceAsUser(&m_wrapped_service); } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && !m_setup_info.can_write_network_clock && !m_setup_info.can_write_timezone_device_location && m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { m_time_m->GetStaticServiceAsRepair(&m_wrapped_service); } else { UNREACHABLE(); } auto res = m_wrapped_service->GetTimeZoneService(&m_time_zone); ASSERT(res == ResultSuccess); } Result StaticService::GetStandardUserSystemClock( OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service)); } Result StaticService::GetStandardNetworkSystemClock( OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service)); } Result StaticService::GetStandardSteadyClock( OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service)); } Result StaticService::GetTimeZoneService(OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); *out_service = std::make_shared( m_system, m_file_timestamp_worker, m_setup_info.can_write_timezone_device_location, m_time_zone); R_SUCCEED(); } Result StaticService::GetStandardLocalSystemClock( OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service)); } Result StaticService::GetEphemeralNetworkSystemClock( OutInterface out_service) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service)); } Result StaticService::GetSharedMemoryNativeHandle( OutCopyHandle out_shared_memory) { LOG_DEBUG(Service_Time, "called."); R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory)); } Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { LOG_DEBUG(Service_Time, "called. offset_ns={}", offset_ns); R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied); R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset( offset_ns / std::chrono::duration_cast(std::chrono::seconds(1)).count())); } Result StaticService::GetStandardSteadyClockRtcValue(Out out_rtc_value) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); } Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( Out out_automatic_correction) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); }); R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( out_automatic_correction)); } Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( bool automatic_correction) { LOG_DEBUG(Service_Time, "called. automatic_correction={}", automatic_correction); R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled( automatic_correction)); } Result StaticService::GetStandardUserSystemClockInitialYear(Out out_year) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); }); *out_year = GetSettingsItemValue(m_set_sys, "time", "standard_user_clock_initial_year"); R_SUCCEED(); } Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out out_is_sufficient) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); } Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( Out out_time_point) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( out_time_point)); } Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( Out out_time, const Service::PSC::Time::SystemClockContext& context) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); } Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, Service::PSC::Time::TimeType type) { SCOPE_EXIT( { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); } Result StaticService::GetClockSnapshotFromSystemClockContext( Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, const Service::PSC::Time::SystemClockContext& user_context, const Service::PSC::Time::SystemClockContext& network_context) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. type={} out_snapshot={} user_context={} network_context={}", type, *out_snapshot, user_context, network_context); }); R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( type, out_snapshot, user_context, network_context)); } Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out out_time, InClockSnapshot a, InClockSnapshot b) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); } Result StaticService::CalculateSpanBetween(Out out_time, InClockSnapshot a, InClockSnapshot b) { SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); } } // namespace Service::Glue::Time